You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by li...@apache.org on 2021/12/15 19:38:12 UTC
[arrow] 02/02: ARROW-14421: [C++] Implement Flight SQL
This is an automated email from the ASF dual-hosted git repository.
lidavidm pushed a commit to branch flight-sql
in repository https://gitbox.apache.org/repos/asf/arrow.git
commit 9c2d8ed5e82a5dd33ca0e17c71c7ca4a3f72b855
Author: Rafael Telles <ra...@telles.dev>
AuthorDate: Wed Dec 15 14:33:04 2021 -0500
ARROW-14421: [C++] Implement Flight SQL
Squashed commit of the following:
commit 72ce72ba855909052f7dfb898105b419697157c8
Author: Rafael Telles <ra...@telles.dev>
Date: Mon Dec 6 16:55:20 2021 -0300
Fix documentation for GetSqlInfo on FlightSql.proto
commit 076187ec3aa18295c92de1f38b9036e66fa8ca7e
Author: Rafael Telles <ra...@telles.dev>
Date: Mon Dec 6 15:02:45 2021 -0300
Add better description to table types on FlightSql.proto
commit 9a9b536acf207456c8050d165c4f1a12c7d71010
Author: Rafael Telles <ra...@telles.dev>
Date: Mon Dec 6 15:01:21 2021 -0300
Change SQL_NUMERIC_FUNCTIONS result on sqlite_sql_info to uppercase
commit dd9d507997e1bcf88aeb3511889dcb3f6b777283
Author: Rafael Telles <ra...@telles.dev>
Date: Mon Dec 6 15:00:19 2021 -0300
Remove dependency on boost/lexical_cast.hpp
commit 023f71a12fbd233dbba2571c7935db454516293e
Author: Rafael Telles <ra...@telles.dev>
Date: Fri Dec 3 16:47:34 2021 -0300
Use std::generate_n to generate random string on sqlite_server.cc
commit 6a928ca82ae69e579d4785c092d069f6b2439ceb
Author: Rafael Telles <ra...@telles.dev>
Date: Fri Dec 3 17:09:25 2021 -0300
Move implementation of methods and data from SQLiteFlightSqlServer to SQLiteFlightSqlServer::Impl and remove dependency of boost-uuid (#221)
* Use pimpl idiom on sqlite_server and add comments on protobuf file
* Correctly implement impl pattern
commit cfe9e2ac79412d375e1415f40445589fd33500d6
Author: Rafael Telles <ra...@telles.dev>
Date: Fri Dec 3 16:27:46 2021 -0300
Use EXPECT_RAISES_WITH_MESSAGE_THAT on TestFlightSqlServer#TestCommandGetSqlInfoNoInfo
commit de8600ca83046bdb51b1a6e1c6420e36896d7e3d
Author: Rafael Telles <ra...@telles.dev>
Date: Fri Dec 3 13:49:55 2021 -0300
nit: Fix indentation on cpp_build.sh
commit ea94097953448a48ebd31215113859f00d06dc4a
Author: Rafael Telles <ra...@telles.dev>
Date: Fri Dec 3 12:15:44 2021 -0300
Use TCP instead on unix sockets on server_test.cc
commit 99ae0216466aee26944b31e10d46d2c3f372842d
Author: Rafael Telles <ra...@telles.dev>
Date: Fri Dec 3 12:03:45 2021 -0300
Remove need of RunServerInternal
commit 2b3839aff39b474d77d515e0ce6290e8e1a9f81a
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Dec 2 13:48:49 2021 -0300
Remove generated protobuf enum from example application
commit 8431e41bddda5abc8aeec8a363b40deab352e5a4
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Dec 2 13:35:56 2021 -0300
[C++] Address ratification comments (round 4 - part 4) (#215)
* Make other methods from SQLite server example to return arrow::Result instead of Status
* Fix bug for null values in numeric columns on SQLite server example
* Structure catalog-schema-table tuple on a TableRef struct on client
* Rename 'schema' to 'db_schema'
* Use TableRef struct on server.cc
* Undo renaming db_schema_filter_pattern
commit fe9d7dc5a1b26a00c789cee969e750479353f581
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Dec 2 13:28:23 2021 -0300
Make sure to wait for server to be ready before running tests (#220)
* Make sure to wait for server to be ready before running tests
* Start server independently for each test
* Use unique_ptr for server thread on server_test.cc
commit e8d8a13aa82c0ec929a103dcc81f250ab0dda02b
Author: Rafael Telles <ra...@telles.dev>
Date: Fri Nov 26 13:59:04 2021 -0300
[C++] Address ratification comments (round 4 - part 3) (#214)
* Make other methods from SQLite server example to return arrow::Result instead of Status
* Fix bug for null values in numeric columns on SQLite server example
* Add comment regarding to performance on sqlite_statement_batch_reader
* Separate GetSqlInfoResultMap from sqlite_server.h
* Remove unused parameter on DoPutCommandStatementUpdate
commit c36b81706a9d6260a733b5ad48baa26694759ddc
Author: Rafael Telles <ra...@telles.dev>
Date: Fri Nov 26 13:25:38 2021 -0300
Remove PRECOMPILED_HEADERS option on arrow_flight_sql's CMakeList.txt
commit 9e3c928cd870c81f1e2f4e2210c1fb3b05a4182e
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Nov 25 16:24:16 2021 -0300
[C++] Address ratification comments (round 4 - part 2) (#213)
* Make FlightSqlClient::GetFlightInfo return a Result instead of Status
* Make most methods on FlightSqlServerBase to return a Result instead of Status
* Move private functions on server.cc to anonymous namespace
* Fixes on doxygen and better readability on server_test.cc
* Rename fields on client_test.cc to follow the convention
commit 7d74b7efce86f77fd1b42716cec4d6b7c3a3bd13
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Nov 25 11:15:37 2021 -0300
[C++] Address ratification comments (round 4) (#212)
* Fix minor issues on sql_info_internal
* Change table_types parameter to be a pointer
* Improve GetSqlInfo error in case of no info
* Replace ArrayFromVector to ArrayFromJSON in most cases
* Improve server_test assertions and code quality
commit 56d84e9fd210a74c0aea7fb4675b76e35e12de76
Author: Rafael Telles <ra...@telles.dev>
Date: Fri Nov 19 14:27:50 2021 -0300
Rename directory flight_sql to sql (#210)
commit 9fcacf22c236ce45fd31ce13b0c4cf1370dee877
Author: Rafael Telles <ra...@telles.dev>
Date: Mon Nov 15 18:13:57 2021 -0300
Fix CMake minor issue, add sql_info_types.h
commit 76d04ea0dff846a1a3f5bf0176af1e287f4c05d3
Author: Rafael Telles <ra...@telles.dev>
Date: Mon Nov 15 17:36:24 2021 -0300
[C++] Fix comments on ratification PR (round 3) (#205)
* Fix comments pointed on review
* Replace boost::variant to arrow::util::variant
* Remove unused macros and redundant definitions
* Refactor sql_info_internal to prepopulate builder pointers on constructor
* Replace ArrayFromJSON usage to ArrayFromVector for consistency on tests
* Remove mention to GetFlightInfoForCommand from doxygen
* Remove copy constructors on SQLInfo related visitors
* Remove move constructors on SQLInfo related visitors
commit fd9bd948002ec393b05a1dfe50f4c8dceb5e4635
Author: Rafael Telles <ra...@telles.dev>
Date: Mon Nov 15 11:25:53 2021 -0300
Fix build when BUILD_EXAMPLES or BUILD_TESTS is OFF
commit f0555708f3b386382b1f32e28c825dce9802171b
Author: Rafael Telles <ra...@telles.dev>
Date: Fri Nov 12 13:03:49 2021 -0300
Enable Flight SQL C++ on CI
commit 6c98d52656971a00cd863c40ca87708a6c1e4488
Author: Juscelino Junior <ju...@id.uff.br>
Date: Thu Nov 11 16:38:45 2021 -0300
Fix FindSQLite3Alt.cmake
commit 3cee40c5ddf7fc066e2d473202576284a946e66b
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Nov 11 14:56:58 2021 -0300
Fix code style issues
commit ec1c4d0e2b36ef51a18cd28fdad6783bd3d69430
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Nov 11 13:21:25 2021 -0300
Fix ODR violation when linking protobuf
commit 2e48187c2c683ea82f79d1abef520b385ed66b69
Author: Juscelino Junior <ju...@id.uff.br>
Date: Thu Nov 11 13:53:06 2021 -0300
Fix method docs on server.h
commit c778682eee06d1dd6bb744ce979b165b8c1b8bc4
Author: Jose Almeida <al...@gmail.com>
Date: Thu Nov 11 08:50:21 2021 -0300
Change Status to arrow::Result on CreateStatementQueryTicket method
commit 45b58cb00a48a751b231ecd054fe48e6e8741767
Author: Jose Almeida <al...@gmail.com>
Date: Wed Nov 10 17:31:05 2021 -0300
Add documentation on public method GetFlightInfo
commit 6908d3851b1c85a9db15bb58c20ab818d7a98ef2
Author: Jose Almeida <al...@gmail.com>
Date: Wed Nov 10 17:21:02 2021 -0300
Change status type on sqlite classes
commit 26f0c194fce55951d1c4af96e69b3cd0862e046d
Author: Jose Almeida <al...@gmail.com>
Date: Wed Nov 10 17:20:35 2021 -0300
Make parameter ordering consistent
commit 8ececc8b17431fc50b40d2a045f86adc1d41974b
Author: Jose Almeida <al...@gmail.com>
Date: Wed Nov 10 17:19:21 2021 -0300
Remove old use of CreateStatementQueryTicket
commit 9e352e3a77231942562964c968926d32e3d4cea2
Author: Jose Almeida <al...@gmail.com>
Date: Wed Nov 10 17:18:48 2021 -0300
Change CreateStatementQueryTicket to a free function
commit 776d739476793cd47f70f156e144f966ec338126
Author: Juscelino Junior <ju...@id.uff.br>
Date: Thu Nov 11 11:25:45 2021 -0300
Fix method docs errors on server.h and sqlite example
commit 404b27deb0df2833175a58efe63eaf718e50ffd1
Author: Rafael Telles <ra...@telles.dev>
Date: Wed Nov 10 17:29:01 2021 -0300
[C++] Implement GetSqlInfo on server example (#193)
* WIP: Implement GetSqlInfo on server-side
* Fix build and missing code parts
* Add test for map<int, list<int>> @ GetSqlInfo
* Fix integration tests
* Fix comments pointed on review
* Fix comments pointed on review
* Add more comments about the logic around DenseUnionArrays
* Remove unnecessary includes on sqlite_server.cc
* Fix comments pointed on review
* Use std::vector reserve and assign to avoid allocating temporary object
* Remove unused dependencies on server.cc
Co-authored-by: Abner Eduardo Ferreira <ab...@pm.me>
commit 817baf9a5d347fc5d8cbf9c598458fbb85acfc3a
Author: Rafael Telles <ra...@telles.dev>
Date: Wed Nov 10 15:05:20 2021 -0300
Fix code style issues
commit 93f93c4c1148b394b660461f20a8a7511ff23546
Author: Jose Almeida <53...@users.noreply.github.com>
Date: Wed Nov 10 14:27:18 2021 -0300
[CPP] Fix issues from client files in flight-sql (#201)
* Order include and rename protocol namespace
* Change a reference to pointer in the client client and refactor the name of namespace on functions
* Nit: remove empty line
* Improve naming from protocol::sql namespace
* Fix include and its orderding
commit 0519976bc9299607444c0f21141b939da6142da0
Author: Rafael Telles <ra...@telles.dev>
Date: Wed Nov 10 14:23:05 2021 -0300
Update vcpkg.json and remove unused variable on CMakeLists.txt (#200)
commit df1ce715fe6382979ceaa11cfc6e66d5219a5562
Author: Jose Almeida <53...@users.noreply.github.com>
Date: Wed Nov 10 13:32:53 2021 -0300
[CPP] Modify the way arrays are created in tests (#199)
* Create array using method ArrayFromJson
* Create array using method ArrayFromJson in server tests
* improve conditional from if statement
commit 35a530ae5a8e0ca2dd5374bbddc94ebe10aef745
Author: Juscelino Junior <ju...@id.uff.br>
Date: Wed Nov 10 12:13:15 2021 -0300
Fix FindSQLite3Alt.cmake
commit 5e1c200bffcec0e7f3a4038177233f5df9e46957
Author: Juscelino Junior <ju...@id.uff.br>
Date: Wed Nov 10 08:38:32 2021 -0300
Fix linter erros on FindSQLite3Alt.cmake
commit 5f5ea06da8b7c62ea9419add7750f37fdedbf87f
Author: Juscelino Junior <ju...@id.uff.br>
Date: Wed Nov 10 08:37:05 2021 -0300
Fix wrong parameter name on SetParameters docs on client.h
commit d40ef9994e532538615d4ca16a908db1dd8df631
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Nov 9 17:57:42 2021 -0300
Reestructure FlightSqlClient to use virtual methods (#195)
commit 093b539df8f16e6e319869b7acbdae7789e91e47
Author: Juscelino Junior <ju...@id.uff.br>
Date: Tue Nov 9 16:03:32 2021 -0300
Fix protobuf version on flight-core
commit 71f877df2e34b10e5c83e3540aca164ec0d46873
Author: Juscelino Junior <ju...@id.uff.br>
Date: Mon Nov 8 16:13:34 2021 -0300
Remove wrong line on CmakeLists
commit 0b32b272ac1bd9b16d1bd4a7d2521db9780ffc30
Author: Juscelino Junior <ju...@id.uff.br>
Date: Mon Nov 8 15:03:58 2021 -0300
implement FindSQLite3Alt on cmake modules
commit e2e57ae39876e1978138ca2b3d66ea9ecacaf7fc
Author: Juscelino Junior <ju...@id.uff.br>
Date: Thu Nov 4 13:04:00 2021 -0300
Fix sql_client close before server stop server test
commit f604d468f9ba885a51f738c93c055d8f8d064f19
Author: Juscelino Junior <ju...@id.uff.br>
Date: Thu Nov 4 13:00:14 2021 -0300
Fix sql_cliente close before server on server test
commit 9135703c25e4f54bd3d487676ce62739fbb3e52e
Author: Juscelino Junior <ju...@id.uff.br>
Date: Thu Nov 4 12:41:09 2021 -0300
server.reset() and sql_client.reset() on server test TearDown
commit 2483ff4cfd7674a2ad5f6a432569419bcbf179d9
Author: Juscelino Junior <ju...@id.uff.br>
Date: Thu Nov 4 11:49:11 2021 -0300
Change sql_client to unique_pointer on server test
commit 46569759a234cf62a1897bdd2ae12687faba852c
Author: Juscelino Junior <ju...@id.uff.br>
Date: Wed Nov 3 18:23:23 2021 -0300
Change server to unique pointer on server tests
commit 698645d127de4647e72cc93236f4700fc0a7a6ea
Author: Juscelino Junior <ju...@id.uff.br>
Date: Wed Nov 3 17:26:24 2021 -0300
fix server stop on serve rt
commit 70bda0c5c117121787922987b6687749c73a2ea0
Author: Juscelino Junior <ju...@id.uff.br>
Date: Wed Nov 3 16:01:06 2021 -0300
Fix test_server
commit 24343e24df274eb1566971ab139f7ac33dc5fb6a
Author: Juscelino Junior <ju...@id.uff.br>
Date: Wed Nov 3 15:42:56 2021 -0300
Fix memory leak with mock
commit 89b4f17cf9aac989f9aa09fa6a0d2113532d9a9d
Author: Juscelino Junior <ju...@id.uff.br>
Date: Wed Nov 3 14:04:58 2021 -0300
fix: correct issues on tests
commit 996c708e6835adad8468d5ece6ba5e5ca2693d4b
Author: Juscelino Junior <ju...@id.uff.br>
Date: Tue Nov 2 16:28:08 2021 -0300
Format test files
commit d480e77dd7c54a18823f2af3f676755d8f4e8785
Author: Juscelino Junior <ju...@id.uff.br>
Date: Thu Oct 28 14:55:12 2021 -0300
Made fixture to client_test.cc to avoid duplication
commit 75f67ad5e2cefde1cd0d6145a928066b6a9b5215
Author: Juscelino Junior <ju...@id.uff.br>
Date: Wed Oct 27 11:02:19 2021 -0300
Fix some issues on CMake and Server Test
commit 4abcd45a0e0706c9d8da1cbb79807971acbb0bf1
Author: Juscelino Junior <ju...@id.uff.br>
Date: Tue Nov 2 15:18:00 2021 -0300
fix: merge test client
commit 39f63c24e41a8f9d83793696e38435dc83890e87
Author: Juscelino Junior <ju...@id.uff.br>
Date: Thu Oct 28 14:55:12 2021 -0300
Made fixture to client_test.cc to avoid duplication
commit 9ef1cae7645fc4456d55d6bd8e365368b69b8533
Author: Juscelino Junior <ju...@id.uff.br>
Date: Wed Oct 27 11:02:19 2021 -0300
Fix some issues on CMake and Server Test
commit 697cde3dab946f727d56d7a0cbdec68ce7b9a301
Author: Rafael Telles <ra...@telles.dev>
Date: Wed Nov 3 17:54:35 2021 -0300
[C++] Ensure client_test.cc does not violate ODR (#192)
* Ensure client_test.cc does not violate ODR
* Format CMakeLists.txt
commit 9716a20c949717eeb3db064df9ee15184d0bea2d
Author: Rafael Telles <ra...@telles.dev>
Date: Wed Nov 3 16:12:07 2021 -0300
Fix issues reported by cppcheck
commit 92c546444714402dbf7e25f6643c08951e98c800
Author: Rafael Telles <ra...@telles.dev>
Date: Wed Nov 3 13:17:52 2021 -0300
Remove unused variable on CMakeLists.txt
commit f080caa3739a71992bf11ec37c03485eb604f763
Author: Jose Almeida <53...@users.noreply.github.com>
Date: Tue Nov 2 17:42:37 2021 -0300
[CPP] Fix on sqlite classes from FlightSqlServer (#181)
* Change FlightMetadataWriter and FlightMessageReader from unique_ptr to raw ptr
* Change reinterpret_cast to dynamic_cast
* Add const to sqlite3Stmt getter
* Add const to string parameter
* Using ARROW_ASSIGN_OR_RAISE to buffer and batch creation
* Change from unique_ptr to raw ptr
* Change sqlite_tables_schema_batch_reader extension from cpp to cc
* Avoid instantiate a string object
* Make ExecuteSql return Status
* Change Create methods from sqlStatement to return Result<T>
* Fix from rebase
* Fix from rebase
* Fix server initialization
* Fix checkstyle
* Add missing ;
* Fix docs on methods
* add explicit to sqlite_server.h constructor
* Fix double free
* Add comment of ownership to SQLiteFlightSqlServer constructor
* Fixed possible close with null_ptr on sqlite classes
* Fix style issues
* Use static_cast instead of dynamic_cast
* Fix other review comments
* Use 'static_cast' when casting scalars on sqlite_server.cc
* Fix comments pointed on review
Co-authored-by: Rafael Telles <ra...@telles.dev>
commit c079a477bb849594ff1e899dab4983519bed8d90
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Nov 2 17:30:40 2021 -0300
[C++] Use util::optional on Flight SQL structs (#191)
* Use optionals on Flight SQL command structs
* Use delete instead of free() on server_test.cc
* Un-nest PreparedStatement class from FlightSqlClient
* Make PreparedStatement::IsClosed const
commit b26bfc40d4a85d0a685d7a985e1541828f613027
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Nov 2 14:54:53 2021 -0300
[C++] Other fixes for ratification (#190)
* Rename sqlClient to sql_client on test_app_cli.cc
* Add missing parameters on PreparedStatement constructor
* Add NOTE to PreparedStatement destructor
* Parse PreparedStatement's dataset and parameters schema when constructing
* Rename Flight SQL Actions constants
* Remove unnecessary 'using' keyword on server.h
* Clean up header files and includes
* Rename getters for schemas on PreparedStatement and make them const
* Handle possible protobuf parsing errors on server.cc
* Move CreateStatementQueryTicket implementation to sql namespace
commit 8095b6e9b8593fb15d528c863f9d9a8963b02013
Author: Rafael Telles <ra...@telles.dev>
Date: Mon Nov 1 14:04:48 2021 -0300
Remove unused includes on server.h
commit 166bb6b40544ea0a58354b1e553711338ceddcea
Author: Rafael Telles <ra...@telles.dev>
Date: Mon Nov 1 14:02:01 2021 -0300
Rename directory flight-sql to flight_sql
commit d89a82ee66a67e22e88dca5a766a3c0e57d9c1f1
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Oct 28 17:57:08 2021 -0300
Remove unnecessary const modifiers on client interface
commit 838469fae0a8cab867d3574a74d0ffccd6a5faa4
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Oct 28 17:23:04 2021 -0300
Remove explicit using of GFlags namespaces
commit 3d0dcfecb203fe89354a0422592873a17bc8ca92
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Oct 28 17:07:26 2021 -0300
[C++] Remove templating from client interface (#184)
* Fix variable initialization
* Remove templating from FlightSqlClient and PreparedStatement classes
* Fix inconsistent member names
* Make PreparedStatement an inner class of FlightSqlClient
* WIP: Use references on FlightCLientImpl methods
* Use shared_ptr<FlightClientImpl> to avoid dangling pointers
* Log error when deleting PreparedStatement
Co-authored-by: Jose Almeida <al...@gmail.com>
commit f1199debe277b0629692d27d0a409b016b6107df
Author: Jose Almeida <53...@users.noreply.github.com>
Date: Thu Oct 28 16:56:28 2021 -0300
Add ARROW_EXPORT and change designated initializer from struct (#189)
commit 4dfa02606adbea3947696024d9fc50a6336bbce9
Author: Rafael Telles <ra...@telles.dev>
Date: Wed Oct 27 13:17:40 2021 -0300
Handle errors on all Parse and Unpack calls to Protobuf (#185)
commit 92b7b48a346f46d4f0049ea6479a29609ade7399
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Oct 26 17:52:14 2021 -0300
Improve DoPutUpdateResult parsing
commit 6ab6e27e2262a5bc535e075747693e97740ee190
Author: Jose Almeida <al...@gmail.com>
Date: Tue Oct 26 13:49:46 2021 -0300
Change ASSERT_TRUE to AsserTableEqual()
commit 30929b7920d477c2a9f2d7d69dc5d9253c4349f2
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Oct 26 11:55:35 2021 -0300
Fix linting issues
commit 5acfa2325674dd61a31e6146e5e29289d1ffbd72
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Oct 26 11:29:48 2021 -0300
Fix compiler warnings on client_impl.h
commit fdbe5f1a6368d3232bc62fea0cd4663e61e67cf8
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Oct 26 11:19:41 2021 -0300
[C++] Wrap Protobufs on server (#182)
* WIP: Wrap CommandStatementQuery protobuf into a struct
* Wrap all Protobuf for commands on server
* Change Parse methods as anonymous functions
commit 5010c1baac182dc7b318e67a6c91da3d4cf66f79
Author: Rafael Telles <ra...@telles.dev>
Date: Mon Oct 25 15:42:35 2021 -0300
Fix flaky tests
commit ba7332757b197a34c2b3619690419816f0c62820
Author: Rafael Telles <ra...@telles.dev>
Date: Mon Oct 25 15:00:08 2021 -0300
[C++] Improvements on CMakeLists.txt (#178)
* Remove extra options on CMakeLists.txt
* Remove GRPC-related instructions from CMakeLists.txt and guard SQLite requirement on ARROW_BUILD_TESTS
* Remove redudant dependencies on CMakeLists.txt
commit 9a96bbdcd1befd5c93aa9bbd47dcd4a78c070666
Author: Jose Almeida <53...@users.noreply.github.com>
Date: Mon Oct 25 14:23:50 2021 -0300
[CPP] Change the way arrays are created in flight-sql tests (#179)
* Create arrays using methods MakeArrayOfNull and ArrayFromJSON
* Fix checkstyle
* Remove macro declare binary array
commit 3895b53c5a49b37ebc403c7aa4f897eb06a85209
Author: Rafael Telles <ra...@telles.dev>
Date: Mon Oct 25 11:26:31 2021 -0300
[C++] Improve Client interface (#180)
* Use '#pragma once' on header files
* Remove ghost parameter on Doxygen for PreparedStatement.Execute
* Change client interface to use Result instead of Status
* Rename sqlClient to sql_client on tests
commit 655d8dd0b88ccfc0905226dc6fa1058c9917f22c
Author: Rafael Telles <ra...@telles.dev>
Date: Fri Oct 22 16:26:19 2021 -0300
Use ASSERT_OK on client_test.cc
commit 87e02ac0921ff4277adf8dae10347f222c9b0c37
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Oct 21 14:06:38 2021 -0300
Fix linter issues
commit 8b5324f730ca55cc556b3e9517ca40af7826dac6
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Oct 19 11:18:17 2021 -0300
Rename flight-sql/server.cpp to server.cc
commit e9aafe7c3e9dafa348bf9efea9bc8e2dfd3d091f
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Oct 19 11:09:31 2021 -0300
[C++] CommandGetCrossReference (#172)
* Add CommandGetCrossReference on FlightSql.proto
* Implement CommandGetCrossReference on C++ client
* Implement CommandGetCrossReference on C++ server example
* Update FlightSql.proto
* Update FlightSql.proto
commit 84ae269e1f131e175bc254cb7bef408b957870a7
Author: Rafael Telles <ra...@telles.dev>
Date: Mon Oct 18 16:10:10 2021 -0300
Implement CommandPreparedStatementUpdate on SQL server example (#169)
* Implement CommandPreparedStatementUpdate on SQL server example
* Refactor sqlite_server to avoid duplication
commit d0e94764bbfc0dc0f6485b122b875f6de1d6e58c
Author: Rafael Telles <ra...@telles.dev>
Date: Mon Oct 18 14:21:42 2021 -0300
Fix wrong error messages on server.cpp
commit 6248009942d05bd955c1f6e4ef4a67c8ac3311bb
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Oct 14 17:59:19 2021 -0300
Rename server files
commit a89a8ffec3a0080cc0ab28fe78599c50afc6c782
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Oct 14 17:28:38 2021 -0300
Fix CheckStyle issues
commit b30041539f491f31df46abd94e121cd870931905
Author: Abner Eduardo Ferreira <ab...@protonmail.ch>
Date: Thu Oct 14 14:15:38 2021 -0300
Fix resource leak where record batch is being created for client_impl.h
commit 5d03029a092075b7ff816cf32f995f864aaf4bb0
Author: Abner Eduardo Ferreira <ab...@protonmail.ch>
Date: Wed Oct 13 17:57:26 2021 -0300
Minor refactor: move variables closer to used
commit ade534d655d4ad99da920db891015774a034f2df
Author: Abner Eduardo Ferreira <ab...@protonmail.ch>
Date: Wed Oct 13 16:04:20 2021 -0300
Fix SIGSEV in test case for PreparedStatement.ExecuteUpdate with parameter binding
commit b9205c1de5b11e89c3c3bee5d24305f2ba8bd4ad
Author: Jose Almeida <al...@gmail.com>
Date: Wed Oct 13 15:32:41 2021 -0300
Refactor ExecuteUpdate with parameter binding test
commit 14d2725e337e1d297eeb6638742f94c5bf560728
Author: Abner Eduardo Ferreira <ab...@protonmail.ch>
Date: Wed Oct 13 14:46:46 2021 -0300
WIP: Refactor test cases for PreparedStatement.ExecuteUpdate to use lambda functions
commit 464248d4ef4fa8b9f17be8b96f5671f0f9eec2a6
Author: Abner Eduardo Ferreira <ab...@protonmail.ch>
Date: Wed Oct 13 12:05:25 2021 -0300
WIP: Refactor test cases for PreparedStatement.ExecuteUpdate
commit 86fe0463d75db9059b4a73a3d71a4a17ccf05905
Author: Abner Eduardo Ferreira <ab...@protonmail.ch>
Date: Tue Oct 12 17:33:48 2021 -0300
Fix rebase issues
commit d9ab9348e49ed2aef29183df0f0315693cc6b676
Author: Abner Eduardo Ferreira <ab...@protonmail.ch>
Date: Tue Oct 12 17:19:46 2021 -0300
Add test case for PreparedStatement.ExecuteUpdate with parameter binding
commit 2d23d07476b9be306507a00b76ffd8eae5053b7b
Author: Abner Eduardo Ferreira <ab...@protonmail.ch>
Date: Tue Oct 12 16:36:22 2021 -0300
Fix broken test for PreparedStatement.ExecuteUpdate without parameter binding
commit 22320fd20ecf83e92406df0dd3c3d97d7f465895
Author: Rafael Telles <ra...@telles.dev>
Date: Fri Oct 8 18:04:35 2021 -0300
Make changes regarding to reviews
commit 247be5bc7b0fdef71d4ce16747fc1185b59bb245
Author: Rafael Telles <ra...@telles.dev>
Date: Fri Oct 8 18:04:35 2021 -0300
Make changes regarding to reviews
commit a9c11db01101843e96e8c88468959bd9b8e21e4f
Author: Rafael Telles <ra...@telles.dev>
Date: Fri Oct 8 15:07:01 2021 -0300
Add integration tests for PreparedStatement query
commit 54ecc387d745b38b66f1bd6a1d0d96cc05cd9ffa
Author: Rafael Telles <ra...@telles.dev>
Date: Fri Oct 8 14:04:05 2021 -0300
Add missing docs for GetArrowType
commit b8417b1a2295730772de68975b7a82c0e1bb655d
Author: Rafael Telles <ra...@telles.dev>
Date: Fri Oct 8 13:55:19 2021 -0300
Remove GetArrowType method duplicate
commit 66a0e41244bc3aa2df7a935dfcd2cc735d3bb138
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Oct 7 13:35:55 2021 -0300
Implement parameter binding on Flight SQL server and example
commit 1bf1ea0dd737c89be10646be2a99b6bd08c3106f
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Oct 5 15:15:03 2021 -0300
WIP: Implement prepared statement on server example
commit 1e437aa119dd8d807918ba46b7b8ec8076142a35
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Oct 5 14:00:35 2021 -0300
Add Create/Close prepared statement actions to sql_server
commit 6e2c9e9bf84ccad95cf700a3ac4b94d7636039b7
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Oct 12 15:27:09 2021 -0300
[C++] Implement CommandGetImportedKeys and CommandGetExportedKeys (#163)
* Implement CommandGetImportedKeys and CommandGetExportedKeys on Flight SQL Server example
* Refactor DoGet methods to reduce code duplication
commit 171d540ac82c3b4bfbb0a5ab53f9d9362dc7c67e
Author: Jose Almeida <53...@users.noreply.github.com>
Date: Tue Oct 12 14:31:14 2021 -0300
[CPP] Implements GetPrimaryKeys on flight sql server (#162)
* Add Schema template for the primary keys
* Implement GetPrimaryKeys on server
* Add an integrated test for GetPrimaryKeys
* Fix checkstyle
* Add a comment to the query on primary keys query
* Use GetFlightInfoForCommand helper method on GetFlightInfoPrimaryKeys
Co-authored-by: Rafael Telles <ra...@telles.dev>
commit e8efe631e106c2dc9788af6db99899353a7b10d4
Author: Rafael Telles <ra...@telles.dev>
Date: Fri Oct 8 15:57:04 2021 -0300
Implement CommandGetTableTypes on server example
commit 042fcc250c597bb03e95901b739251b68ff04557
Author: Jose Almeida <al...@gmail.com>
Date: Fri Oct 8 15:17:46 2021 -0300
use variable close to its use
commit afd0e3e8c6af317d23dbfb0ad64b9ee8c1aeaf21
Author: Jose Almeida <al...@gmail.com>
Date: Fri Oct 8 15:17:00 2021 -0300
Add comment when calling ReadMetadata on DoPut
commit 51462791dcb003b4b2e56795403577e646ef78b7
Author: Jose Almeida <al...@gmail.com>
Date: Fri Oct 8 15:16:28 2021 -0300
Sort includes alphabetically
commit 2f1c93585632e62e6baf73c6f0d5f977015eca31
Author: Jose Almeida <al...@gmail.com>
Date: Fri Oct 8 15:15:54 2021 -0300
change const references from setParameters method
commit 8327b47cb50c3808e0ed06fc63ac99419efc3a35
Author: Jose Almeida <al...@gmail.com>
Date: Fri Oct 8 14:21:43 2021 -0300
change (void) to ASSERT_OK on test
commit 432b0267573138134219e78d22fc9aea4e4c92f6
Author: Jose Almeida <al...@gmail.com>
Date: Fri Oct 8 14:21:26 2021 -0300
Implement method GetResultSetSchema
commit eb2f76ce63cbbe514288886f9c8ab5c0157971c9
Author: Jose Almeida <al...@gmail.com>
Date: Fri Oct 8 13:39:56 2021 -0300
Add missing docs to prepared statement methods
commit e3facf744f7ad0d4466a28121a522a8542020387
Author: Jose Almeida <al...@gmail.com>
Date: Fri Oct 8 13:27:35 2021 -0300
Add prepared statement parameter binding to test app
commit b59afc612594fdcfa64f1d633c263856f044d25b
Author: Jose Almeida <al...@gmail.com>
Date: Fri Oct 8 13:27:11 2021 -0300
Create a mocked client test for parameter binding
commit 15a6b3d17ce168a30c83049185bd9a97c7ad5311
Author: Jose Almeida <al...@gmail.com>
Date: Fri Oct 8 13:26:00 2021 -0300
Pass option to DoPut CALL
commit b19552ee18036912f21994f20349fb831206b345
Author: Jose Almeida <al...@gmail.com>
Date: Fri Oct 8 13:25:35 2021 -0300
Fix add a break line
commit b2b1b8c3c854048ef793160e69a8f098ab4133a0
Author: Jose Almeida <al...@gmail.com>
Date: Thu Oct 7 14:50:34 2021 -0300
Add macro ARRROW_RETURN_NOT_OK
commit 9ccb72e90d2bee8d77b704156f99f2785665191e
Author: Jose Almeida <al...@gmail.com>
Date: Thu Oct 7 14:49:28 2021 -0300
remove TODO
commit 7f9daa9f467461c3b4010417588131c05b8d8fa8
Author: Jose Almeida <al...@gmail.com>
Date: Thu Oct 7 14:49:00 2021 -0300
remove unused code from test_app
commit 832aec33f9b3667e7d60681a1acd70f3bcdb26d6
Author: Jose Almeida <al...@gmail.com>
Date: Thu Oct 7 13:29:57 2021 -0300
add paremter binding to query execution with prepared statement
commit e98fd67350e7c8839a1bdc361cb55c07a026e501
Author: Jose Almeida <al...@gmail.com>
Date: Thu Oct 7 13:29:25 2021 -0300
Add methods to set and get parameters
commit e85e8f84e04a1e6fb60672ae352481fd45a8a3fc
Author: Jose Almeida <al...@gmail.com>
Date: Thu Sep 30 15:39:18 2021 -0300
Fix checkstyle
commit 46c568171b8d0f45a19b6929e5fac7f6d605e64b
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Oct 5 13:14:55 2021 -0300
Implement CommandGetSchemas
commit ca738150306bab8866f4398749d697fdfddf7000
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Oct 7 17:49:05 2021 -0300
Add missing docs for DoPutCommandStatementUpdate
commit 08b029434dcae677e27f53fe4cc1d7fec02f0b7e
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Oct 7 14:20:27 2021 -0300
Implement CommandStatementUpdate on server example
commit ac77dbc9b310271b8ec578d96299e8b05dc4cb0b
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Oct 7 17:52:07 2021 -0300
Change SqliteStatement.Reset argumento to pointer
commit dcc8f7fb5f80d69abe78334dd0eb0ad770411772
Author: Abner Eduardo Ferreira <ab...@protonmail.ch>
Date: Thu Oct 7 15:37:01 2021 -0300
Add GetSqlInfo on client side for FlightSQL
commit f8f404ada1c5fd778a60912597c61f5f1a0d8bd4
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Oct 7 15:06:11 2021 -0300
Remove duplicate import
commit 3c3b928fd22ad1b35421eb7108dfa336f5bc3073
Author: Jose Almeida <al...@gmail.com>
Date: Thu Oct 7 14:44:12 2021 -0300
Make the mock object be called twice
commit a9361aa41958be9494da639a6bc495b31bf4120f
Author: Jose Almeida <al...@gmail.com>
Date: Thu Oct 7 14:16:18 2021 -0300
Remove options as parameter from PreparedStatement methods
commit 6759818b9567692dad9e6166a897b06041f98b66
Author: Jose Almeida <al...@gmail.com>
Date: Thu Oct 7 14:04:10 2021 -0300
Make the destructor call the Close method
commit 8f23bd5953697a7559d9e8818f91ff65c9cd4969
Author: Jose Almeida <al...@gmail.com>
Date: Thu Oct 7 13:50:24 2021 -0300
rename the variable of the CommandPreparedStatementQuery
commit d30cef29e2a51c2bc4d476471b0e7740dd029098
Author: Jose Almeida <al...@gmail.com>
Date: Thu Oct 7 13:49:51 2021 -0300
Move constructor to the top of the file
commit de161ec9d10eb1a8cf563e4b33cce247f24fd764
Author: Jose Almeida <al...@gmail.com>
Date: Thu Oct 7 13:49:17 2021 -0300
Remove extra lines and duplicated import
commit 8d60000190848035b3d138a3f92ea6ad331d2b3d
Author: Jose Almeida <al...@gmail.com>
Date: Wed Oct 6 16:42:19 2021 -0300
Remove duplicate function due to rebase
commit 78b454094835bff1a829f3dec1e3cbb4a5d0fcf3
Author: Jose Almeida <al...@gmail.com>
Date: Wed Oct 6 16:28:22 2021 -0300
Modify the constructor of the PreparedStatement
commit f80bfafaa4b93513010b0fe4651720a87f6f8a25
Author: Jose Almeida <al...@gmail.com>
Date: Wed Oct 6 16:28:10 2021 -0300
Pass options to the client calls
commit 4b0adb6cabf9f357ca7afe53ea64d5b8a0aa262d
Author: Jose Almeida <al...@gmail.com>
Date: Wed Oct 6 15:13:30 2021 -0300
Fix test_app for prepared statement execution
commit 297b7f06968e859149b6adca4aa4d4f7d5e2f637
Author: Jose Almeida <al...@gmail.com>
Date: Wed Oct 6 15:09:04 2021 -0300
Treat if the statement is already closed
commit a46dd6db945744c0b7f7ae81cf4abc6a07475f2d
Author: Jose Almeida <al...@gmail.com>
Date: Wed Oct 6 14:59:15 2021 -0300
Adding missing files from rebase
commit 9414a2ef4a054ced35ed7c49dd9963db879dfa01
Author: Jose Almeida <al...@gmail.com>
Date: Wed Oct 6 14:59:05 2021 -0300
Fix checkstyle
commit a5c362c2f59929f3fe4077c87f882a3f1b09ebca
Author: Jose Almeida <al...@gmail.com>
Date: Tue Oct 5 22:31:36 2021 -0300
Add a branch on test_app to execute a query with PreparedStatement mode
commit fe96fe096dbba6088808dee434f262aeda5d304b
Author: Jose Almeida <al...@gmail.com>
Date: Tue Oct 5 22:31:09 2021 -0300
Refactor the creation of the PreparedStatement on sql_client
commit ea75e69ba05b25b5aaa9752a91cd046edd1135f7
Author: Jose Almeida <al...@gmail.com>
Date: Tue Oct 5 22:18:31 2021 -0300
Create a mocked sql_client test for the preparedStatement
commit ee1ed1930d8f3374760388f7ac394f6197174629
Author: Jose Almeida <al...@gmail.com>
Date: Tue Oct 5 22:18:12 2021 -0300
implemenet methods PreparedStatemenetClass in sql_client
commit 83b1c169d6604b346d373509e301cb10f56aec49
Author: Jose Almeida <al...@gmail.com>
Date: Tue Oct 5 22:16:37 2021 -0300
Add PreparedStatementClass to sql client
commit 3b08157e1ab88515e4f67c966868ccd31a4ac033
Author: Rafael Telles <ra...@telles.dev>
Date: Wed Sep 29 17:16:52 2021 -0300
Implement CommandGetSchemas
commit 3066113d217e508d409c27c8eb626682057cd629
Author: Jose Almeida <al...@gmail.com>
Date: Thu Sep 30 15:39:18 2021 -0300
Fix checkstyle
commit 70800d0a19d046aefd6b4ced477a9a339846e81d
Author: Jose Almeida <al...@gmail.com>
Date: Tue Sep 28 16:09:27 2021 -0300
Add the schemas to be used by the GetTabkes
commit 2a221a6a957c479253fa820c792fec6e573df2c6
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Oct 5 13:14:55 2021 -0300
Implement CommandGetSchemas
commit 1036ec8c11f1a7992f7a435762702dbc199152c7
Author: Jose Almeida <al...@gmail.com>
Date: Thu Oct 7 13:39:21 2021 -0300
Remove extra line
commit a7ff4573a72ffed2eb401ae291b29dc0b3477b12
Author: Jose Almeida <al...@gmail.com>
Date: Thu Oct 7 13:39:09 2021 -0300
Add missing return at docs from SqlSchema methods
commit 6c52c281353322d9416e10d2d393bbfe46ffbcfd
Author: Jose Almeida <al...@gmail.com>
Date: Thu Oct 7 13:35:22 2021 -0300
Passes the rc variable as reference to Reset method
commit b7089548f4219cbb8e994d24da427a0bd060aa00
Author: Jose Almeida <al...@gmail.com>
Date: Thu Oct 7 13:32:12 2021 -0300
Remove unused RecordBatchReader
commit 250a3c4b4a3db0967c17bb8384c8e3ad7976d598
Author: Jose Almeida <al...@gmail.com>
Date: Wed Oct 6 16:11:18 2021 -0300
Add missing include
commit 95e7507622be9037b819a17ed7f1163dad1893a1
Author: Jose Almeida <al...@gmail.com>
Date: Wed Oct 6 16:00:20 2021 -0300
Fix missing files from rebase
commit acfaec0df1c08c32907cb05093fd2b23ddf2dbcb
Author: Jose Almeida <al...@gmail.com>
Date: Wed Oct 6 14:15:41 2021 -0300
Add a variable to control the execution flow
commit d10d1916c3cf7777029b4803f2d86045799a6da6
Author: Jose Almeida <al...@gmail.com>
Date: Wed Oct 6 14:15:19 2021 -0300
Add a method to reset the statement to its original condition
commit ec0319c26d2c44e7f30855066e3212064e7f4d03
Author: Jose Almeida <al...@gmail.com>
Date: Wed Oct 6 13:25:19 2021 -0300
Fix checkstyle
commit 6bf3fdecf5f55e0715a354c09b89ec5407e14624
Author: Jose Almeida <al...@gmail.com>
Date: Wed Oct 6 12:00:26 2021 -0300
change parameter from string to char* on GetArrowType method
commit 4f0807a7eb8d99e363ce07e33364acc164621a89
Author: Jose Almeida <al...@gmail.com>
Date: Wed Oct 6 12:00:03 2021 -0300
Remove status from sqlite use
commit 05d6280326872b3f7f75bc51b8e8f91ef49979c1
Author: Jose Almeida <al...@gmail.com>
Date: Wed Oct 6 11:59:30 2021 -0300
Move anonymous function to the top of file
commit d962a33462b2061e9926a540f016d761247fbec5
Author: Jose Almeida <al...@gmail.com>
Date: Tue Oct 5 16:04:37 2021 -0300
Fix checkstyle
commit 9f90bdec11c5827d6ac790f5345a2707b5d1b9a5
Author: Jose Almeida <al...@gmail.com>
Date: Tue Oct 5 16:01:52 2021 -0300
Refactor constructor from the class sqlite_tables_schema_batch_reader
commit 61af7d444e635855fe0854dfba49d26cf75f38ac
Author: Jose Almeida <al...@gmail.com>
Date: Tue Oct 5 16:01:22 2021 -0300
Fix import order
commit 5e2071c84e3775f09814548655986456bd257f1a
Author: Jose Almeida <al...@gmail.com>
Date: Tue Oct 5 16:01:11 2021 -0300
Decouple method PrepareQueryForGetTables from the class
commit 449938b94b5b1d4ba241ec31ad57ee3ab91aee15
Author: Jose Almeida <al...@gmail.com>
Date: Tue Oct 5 16:00:16 2021 -0300
Remove extra space
commit e5ea5eba96bb9fbce298454441cd2d62cd7a1b7c
Author: Jose Almeida <al...@gmail.com>
Date: Fri Oct 1 18:15:41 2021 -0300
Pass the query to the batch reader vector for the table with schemas
commit abe5af8dd3412531a46aa35fa03d02b78200481f
Author: Jose Almeida <al...@gmail.com>
Date: Fri Oct 1 18:15:14 2021 -0300
Invert order of vector on tests
commit 4a99053103e53a08c6f8398d3473351ea8f450b2
Author: Jose Almeida <al...@gmail.com>
Date: Fri Oct 1 18:14:15 2021 -0300
Add method prepareQuery
commit bd19a660f588e6a4e17907a6ff972e05407aa0cf
Author: Jose Almeida <al...@gmail.com>
Date: Thu Sep 30 16:45:24 2021 -0300
Fix checkstyle
commit 9a838a9dd04279526b5b3d25b683556f0526b6c6
Author: Jose Almeida <al...@gmail.com>
Date: Thu Sep 30 16:44:07 2021 -0300
Update CMakeLists.txt
commit 574878f2e7cec50658b19fd3668a0755795d8769
Author: Jose Almeida <al...@gmail.com>
Date: Thu Sep 30 16:43:57 2021 -0300
Set values from catalogs and schema as null
commit 0aa1cab6dd1743d59ed5f9252b7fc3cd54649e4e
Author: Jose Almeida <al...@gmail.com>
Date: Thu Sep 30 16:43:41 2021 -0300
Modify Macro from builder to deal with null values
commit b8d8396a1b2585d4f02895c91a850fe90d559550
Author: Jose Almeida <al...@gmail.com>
Date: Thu Sep 30 15:39:52 2021 -0300
change constructor initialization
commit 8e846c84631e6dcf2dce99d129e8b788c12aae57
Author: Jose Almeida <al...@gmail.com>
Date: Thu Sep 30 15:39:18 2021 -0300
Fix checkstyle
commit 60b8326c29411d709dcf43b4b2aca9277d8baa99
Author: Jose Almeida <al...@gmail.com>
Date: Thu Sep 30 15:09:11 2021 -0300
Add more test for the GetTables
commit 5bc0e9f2449cad3f128a936194682c7e52f9b8cf
Author: Jose Almeida <al...@gmail.com>
Date: Thu Sep 30 15:08:57 2021 -0300
Add a DECLARE_BINARY_ARRAY for testing
commit 01266d72b56edc38071b83bfcabc8257be277cfc
Author: Jose Almeida <al...@gmail.com>
Date: Thu Sep 30 15:08:23 2021 -0300
Add table type filter to the query
commit 8a02752d9f1ef897937e0c48f98c42213f2f8672
Author: Jose Almeida <al...@gmail.com>
Date: Thu Sep 30 15:07:45 2021 -0300
Refactor methods that parse the table type to field type
commit a0f32ba9ab4bf390110d772c353592f018d5f692
Author: Jose Almeida <al...@gmail.com>
Date: Thu Sep 30 09:59:53 2021 -0300
Refactor test from GetTables
commit 8a3dc6d8e20cf8826849453607dae92b83d6050d
Author: Jose Almeida <al...@gmail.com>
Date: Wed Sep 29 11:28:54 2021 -0300
Add new tests to GetTables
commit aef712a73a4640c76088e08cd8ca339b934e16e0
Author: Jose Almeida <al...@gmail.com>
Date: Wed Sep 29 11:28:41 2021 -0300
Add new filter to the query on GetTables
commit 814dc10579876ef44017a9bb74eec0efef224fd7
Author: Jose Almeida <al...@gmail.com>
Date: Wed Sep 29 11:28:23 2021 -0300
Refactor the name of class sqlite table schema batch reader
commit 7d53dd6a3343569fca9279e9968c5f7678895fcc
Author: Jose Almeida <al...@gmail.com>
Date: Tue Sep 28 16:09:39 2021 -0300
Add class to tge CMakeLists.txt
commit 86a0ba0b3d1a186dab33c48ffedaa1ebbbcfbf63
Author: Jose Almeida <al...@gmail.com>
Date: Tue Sep 28 16:09:27 2021 -0300
Add the schemas to be used by the GetTabkes
commit 6b6d9c2b9bc13d2a46b13dce81f9f16f723fbaf8
Author: Jose Almeida <al...@gmail.com>
Date: Tue Sep 28 16:09:09 2021 -0300
Include methods GetTablesFlightInfo and DoGetTables
commit 203e64f1116072e06874430be839832824965f04
Author: Jose Almeida <al...@gmail.com>
Date: Tue Sep 28 16:08:46 2021 -0300
Create a class to deal the DoGetTables when schema is included
commit cac2d9fb56408e223be9ea0ca76582e57a0f2223
Author: Rafael Telles <ra...@telles.dev>
Date: Wed Oct 6 15:11:16 2021 -0300
Fix style issues
commit c750b15a1c1d7543517f82bb3fe2594ad06d9e5b
Author: Rafael Telles <ra...@telles.dev>
Date: Wed Oct 6 15:11:16 2021 -0300
Fix style issues
commit b22fe92358cc1a8c5d7342ae0fda7101fbd00d19
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Sep 30 11:14:06 2021 -0300
Undo unscoped changes to other files
commit e68f6e689d366a3b2299f7c3d7e948de724735d7
Author: Rafael Telles <ra...@telles.dev>
Date: Wed Sep 29 17:16:52 2021 -0300
Implement CommandGetSchemas
commit f1d9f9da9d297c8e17979623d32f6aeec95de654
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Sep 30 15:39:43 2021 -0300
Fix checkstyle errors
commit 2fdc7c84cdfc1236baaf1f2fb478e6c8048d260f
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Sep 30 13:17:10 2021 -0300
Fix problem when linking protobuf to flight-sql targets
commit 5e57cd15cb480bbd6f743009a6a763c8a8e26f0b
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Oct 5 13:14:55 2021 -0300
Implement CommandGetSchemas
commit b8f5dda429b7aebbcc936270d3123ff0cc27f27d
Author: Rafael Telles <ra...@telles.dev>
Date: Wed Sep 29 17:42:15 2021 -0300
Make GetCatalogs return empty results
commit a631b4f97f43f9f7074888c6b0e158df13bc93e5
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Sep 28 22:30:11 2021 -0300
Add comment about hardcoded GetCatalogs implementation
commit d754fdec6fbd724c50c81024d3e00a8bd7bfcd9a
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Sep 28 19:06:10 2021 -0300
Fix minor comments on PR
commit 060e9b45998512f53d30f072693194a00c53e104
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Sep 28 16:04:32 2021 -0300
Refactor tests to reduce duplication
commit 7add18f4f40f7865298c31f7a3a523be2e191f9e
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Sep 28 15:07:40 2021 -0300
Implement CommandGetCatalogs
commit 5d3bc66c200abc30fd421ac7eb0c1c6bb87985cb
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Sep 28 16:30:11 2021 -0300
Improve readability for SqliteFlightSqlServer setup
commit 68bec018bd9784327d27dc80b80c84e18077606c
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Sep 28 16:07:07 2021 -0300
Fix minor comments on PR
commit 93c5a4ba70e2dd6b2083c8235255af095a3a703b
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Sep 28 14:27:29 2021 -0300
Fix checkstyle errors
commit 2232dd67f3829aa61feea031809dad4543e75c21
Author: Rafael Telles <ra...@telles.dev>
Date: Mon Sep 27 16:36:06 2021 -0300
Add integration tests for Flight SQL server example
commit f7b6461ee156d05e602f4af287d1ae7be54794f2
Author: Rafael Telles <ra...@telles.dev>
Date: Fri Sep 24 16:04:58 2021 -0300
Add documentation to example classes
commit 3584fc07f7fd76ab46ab76215d609cb35d344c91
Author: Rafael Telles <ra...@telles.dev>
Date: Fri Sep 24 15:42:35 2021 -0300
Add missing sqlite3 dependency on vcpkg.json
commit 87fc8aae9cb0e5819dadc2f3a1ba394904f2acc2
Author: Rafael Telles <ra...@telles.dev>
Date: Fri Sep 24 15:38:02 2021 -0300
Implement Flight SQL example server using SQLite3
commit 9dd9a3216c735183039cd87fb9d077433fec17f1
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Sep 28 14:00:22 2021 -0300
Change default Status return on GetFlightInfo and DoGet
commit 5bd548fb8f720397c1e7756151ac8c68190741c2
Author: Rafael Telles <ra...@telles.dev>
Date: Fri Sep 24 15:35:25 2021 -0300
Remove empty constructor and destructor from FlightSqlServerBase header
commit cffd1f4cbb5d9199bb47807e7fef131ac4359a7a
Author: Jose Almeida <al...@gmail.com>
Date: Fri Sep 24 15:20:36 2021 -0300
Separate implementation from header file
commit 685ccd00406593a35ee4156004db5a4b9a499c03
Author: Jose Almeida <al...@gmail.com>
Date: Thu Sep 23 11:38:27 2021 -0300
Add missing else if on DoGet method
commit 4099ad21518a087ed818587be3e73ef84368398e
Author: Rafael Telles <ra...@telles.dev>
Date: Wed Sep 22 15:16:52 2021 -0300
Improve documentation on sql_server.h
commit 8aaee1edcf1e248bb62ec4c81e0ef52097879ec0
Author: Rafael Telles <ra...@telles.dev>
Date: Wed Sep 22 14:29:16 2021 -0300
Fix wrong arguments on server header file
commit 5f7a4c81195c7bf688e1f82cef8781f7299d89d0
Author: Rafael Telles <ra...@telles.dev>
Date: Wed Sep 22 14:13:36 2021 -0300
Implement missing branches on DoGet
commit c5d63016cf700fdd3bcd3526011608ac0482c652
Author: Jose Almeida <al...@gmail.com>
Date: Wed Sep 22 14:11:58 2021 -0300
Add more statement to the getFlightInfo methods
commit a25bb904c90726473816ba9d6fc11be1441e111c
Author: Rafael Telles <ra...@telles.dev>
Date: Wed Sep 22 14:00:27 2021 -0300
Remove doPut* methods (not used yet)
commit eeb4a3531d607d9a57513a04ec98c5282e7cc681
Author: Jose Almeida <al...@gmail.com>
Date: Wed Sep 22 13:56:52 2021 -0300
Remove flight-sql from CMakeLists.txt
commit 03425db52435102f9fa40e20da3d497c4d0410f8
Author: Jose Almeida <al...@gmail.com>
Date: Wed Sep 22 13:52:52 2021 -0300
Add flight-sql server header file
commit bf5cfeff437e045cbf38945c82f64bcb8fbc5f2f
Author: Rafael Telles <ra...@telles.dev>
Date: Mon Sep 20 15:25:42 2021 -0300
Change ExecuteUpdate output argument to raw pointer instead of unique_ptr<int64_t>
commit bd2890ee117d64bca9856b3705eadd4eecd95274
Author: Jose Almeida <al...@gmail.com>
Date: Fri Sep 17 16:24:24 2021 -0300
Change order of call from ExecuteUpdate on test_app.cc
commit 5e11c8243312d6c1dc7cb4723ada6f2cff739940
Author: Jose Almeida <al...@gmail.com>
Date: Fri Sep 17 16:11:47 2021 -0300
Checkstyle fix on flight-sql
commit 59e1c2897fc2adb0891072faad09c92745bb18c5
Author: Jose Almeida <al...@gmail.com>
Date: Fri Sep 17 16:11:36 2021 -0300
Change order of output parameters on methods from flight-sql
commit 7aa4c14425b5b2628e16488166dcd9fe762454be
Author: Jose Almeida <al...@gmail.com>
Date: Fri Sep 17 16:09:25 2021 -0300
Change rows on executeUpdate to a unique_ptr
commit 015d015ea7da2f8347c63b76c55768656b8d8f27
Author: Rafael Telles <ra...@telles.dev>
Date: Thu Sep 16 10:30:27 2021 -0300
Refactor client_impl to reduce duplication on FlightDescriptor build
commit 83db0122781b94c23557837661a27659ae8e4af7
Author: Jose Almeida <al...@gmail.com>
Date: Tue Sep 14 16:56:07 2021 -0300
Create a mock test for execute_update method on sql_client
commit e078c057148c9ed91176036485e7c4a8363fb779
Author: Jose Almeida <al...@gmail.com>
Date: Tue Sep 14 16:55:50 2021 -0300
Implement executeUpdate logic on sql client
commit 69dbdecccf977d6b3a6fb33a76047ab368af546e
Author: Rafael Telles <ra...@telles.dev>
Date: Wed Sep 15 19:33:25 2021 -0300
[C++] Implement Flight SQL client test application (#121)
* Implement Flight SQL client test application
* Adjust PrintResults to consider multiple endpoints
* Remove mentions to Dremio
* Minor fix
* Sort 'using' statements on test_app.cc
* Transfer ownership of FLightClient to FlightSqlClient on constructor
* Use reference instead of pointers on PrintResults
* Make client methods to be const
commit fde5c0022594146b971a635c337616ffe86e5bd1
Author: Jose Almeida <53...@users.noreply.github.com>
Date: Tue Sep 14 11:42:48 2021 -0300
[C++] Implements methods from flight-sql-client (#120)
* add a header file to the sql-client
* Implements methods from sql-client
* Add configuration files to the flight-sql
* Change getFlightInfo to virtual and its constructor to protected
* Create a mock test for getCatalogs
* Remove unused test from CMakeLists.txt
* Fix checkstyle on flight-sql files
* Fix duplicate tests execution
* Add test for getSchema from flightsql
* Update flight headers and implements getTable and getTableTypes
* Add other unit tests for metadata methods
* Fix checkstyle errors
* Implement missing methods GetPrimaryKeys, GetImportedKeys and GetExportedKeys
* Refactor flight-sql/client.cc implementation
* Remove unimplemented ExecuteUpdate test
* Add google/protobuf/message include to flight-sql-client
* Undo changes on flight/client.h and use templates for mocking FlightClient on FlightSqlClient
* Use string references where parameters can not be null
* Reorder FlightSqlClient method arguments
* Avoid needing to use diamond syntax on FlightSqlClient
Co-authored-by: Rafael Telles <ra...@telles.dev>
commit f3fe962c5838c345589320d7c559526650e87cde
Author: Rafael Telles <ra...@telles.dev>
Date: Mon Sep 6 11:37:08 2021 -0300
Fix checkstyle issues
commit 2ed7b0efae2a6128f13920ed4e18d6d7d7f0d803
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Aug 24 14:12:37 2021 -0300
WIP: Clean up changes
commit 7dc836e789b390297e191471e4aa142386bf793b
Author: Rafael Telles <ra...@telles.dev>
Date: Tue Aug 24 13:49:32 2021 -0300
Update FindArrowFlightSql.cmake
commit 370c92ef1d9748feef8c61e2b19515a558124939
Author: Rafael Telles <ra...@telles.dev>
Date: Mon Aug 23 15:28:53 2021 -0300
WIP: Set up flight-sql project on cpp directory
---
ci/docker/conda-cpp.dockerfile | 1 +
ci/scripts/cpp_build.sh | 1 +
cpp/CMakeLists.txt | 4 +
cpp/cmake_modules/DefineOptions.cmake | 2 +
cpp/cmake_modules/FindArrowFlightSql.cmake | 93 +++
cpp/cmake_modules/FindSQLite3Alt.cmake | 43 +
cpp/src/arrow/CMakeLists.txt | 4 +
cpp/src/arrow/flight/CMakeLists.txt | 18 +-
.../arrow/flight/sql/ArrowFlightSqlConfig.cmake.in | 36 +
cpp/src/arrow/flight/sql/CMakeLists.txt | 100 +++
cpp/src/arrow/flight/sql/api.h | 20 +
cpp/src/arrow/flight/sql/arrow-flight-sql.pc.in | 25 +
cpp/src/arrow/flight/sql/client.cc | 425 ++++++++++
cpp/src/arrow/flight/sql/client.h | 247 ++++++
cpp/src/arrow/flight/sql/client_test.cc | 515 ++++++++++++
cpp/src/arrow/flight/sql/example/sqlite_server.cc | 813 +++++++++++++++++++
cpp/src/arrow/flight/sql/example/sqlite_server.h | 142 ++++
.../arrow/flight/sql/example/sqlite_sql_info.cc | 223 ++++++
cpp/src/arrow/flight/sql/example/sqlite_sql_info.h | 34 +
.../arrow/flight/sql/example/sqlite_statement.cc | 137 ++++
.../arrow/flight/sql/example/sqlite_statement.h | 73 ++
.../sql/example/sqlite_statement_batch_reader.cc | 189 +++++
.../sql/example/sqlite_statement_batch_reader.h | 65 ++
.../example/sqlite_tables_schema_batch_reader.cc | 106 +++
.../example/sqlite_tables_schema_batch_reader.h | 58 ++
cpp/src/arrow/flight/sql/server.cc | 761 ++++++++++++++++++
cpp/src/arrow/flight/sql/server.h | 443 ++++++++++
cpp/src/arrow/flight/sql/server_test.cc | 767 ++++++++++++++++++
cpp/src/arrow/flight/sql/sql_info_internal.cc | 101 +++
cpp/src/arrow/flight/sql/sql_info_internal.h | 87 ++
cpp/src/arrow/flight/sql/test_app_cli.cc | 197 +++++
cpp/src/arrow/flight/sql/test_server_cli.cc | 63 ++
cpp/src/arrow/flight/sql/types.h | 890 +++++++++++++++++++++
cpp/vcpkg.json | 1 +
docker-compose.yml | 3 +
35 files changed, 6686 insertions(+), 1 deletion(-)
diff --git a/ci/docker/conda-cpp.dockerfile b/ci/docker/conda-cpp.dockerfile
index 8fd5e46..9363e67 100644
--- a/ci/docker/conda-cpp.dockerfile
+++ b/ci/docker/conda-cpp.dockerfile
@@ -41,6 +41,7 @@ ENV ARROW_BUILD_TESTS=ON \
ARROW_DATASET=ON \
ARROW_DEPENDENCY_SOURCE=CONDA \
ARROW_FLIGHT=ON \
+ ARROW_FLIGHT_SQL=ON \
ARROW_GANDIVA=ON \
ARROW_HOME=$CONDA_PREFIX \
ARROW_ORC=ON \
diff --git a/ci/scripts/cpp_build.sh b/ci/scripts/cpp_build.sh
index f791ddd..02718e5 100755
--- a/ci/scripts/cpp_build.sh
+++ b/ci/scripts/cpp_build.sh
@@ -70,6 +70,7 @@ cmake \
-DARROW_EXTRA_ERROR_CONTEXT=${ARROW_EXTRA_ERROR_CONTEXT:-OFF} \
-DARROW_FILESYSTEM=${ARROW_FILESYSTEM:-ON} \
-DARROW_FLIGHT=${ARROW_FLIGHT:-OFF} \
+ -DARROW_FLIGHT_SQL=${ARROW_FLIGHT_SQL:-OFF} \
-DARROW_FUZZING=${ARROW_FUZZING:-OFF} \
-DARROW_GANDIVA_JAVA=${ARROW_GANDIVA_JAVA:-OFF} \
-DARROW_GANDIVA_PC_CXX_FLAGS=${ARROW_GANDIVA_PC_CXX_FLAGS:-} \
diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt
index 0262357..e2b9f4e 100644
--- a/cpp/CMakeLists.txt
+++ b/cpp/CMakeLists.txt
@@ -334,6 +334,10 @@ if(ARROW_GANDIVA)
set(ARROW_WITH_RE2 ON)
endif()
+if(ARROW_FLIGHT_SQL)
+ set(ARROW_FLIGHT ON)
+endif()
+
if(ARROW_CUDA
OR ARROW_FLIGHT
OR ARROW_PARQUET
diff --git a/cpp/cmake_modules/DefineOptions.cmake b/cpp/cmake_modules/DefineOptions.cmake
index f2ddff3..2afbdab 100644
--- a/cpp/cmake_modules/DefineOptions.cmake
+++ b/cpp/cmake_modules/DefineOptions.cmake
@@ -226,6 +226,8 @@ if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
define_option(ARROW_FLIGHT
"Build the Arrow Flight RPC System (requires GRPC, Protocol Buffers)" OFF)
+ define_option(ARROW_FLIGHT_SQL "Build the Arrow Flight SQL extension" OFF)
+
define_option(ARROW_GANDIVA "Build the Gandiva libraries" OFF)
define_option(ARROW_GCS
diff --git a/cpp/cmake_modules/FindArrowFlightSql.cmake b/cpp/cmake_modules/FindArrowFlightSql.cmake
new file mode 100644
index 0000000..cbca81c
--- /dev/null
+++ b/cpp/cmake_modules/FindArrowFlightSql.cmake
@@ -0,0 +1,93 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# - Find Arrow Flight SQL
+#
+# This module requires Arrow from which it uses
+# arrow_find_package()
+#
+# This module defines
+# ARROW_FLIGHT_SQL_FOUND, whether Flight has been found
+# ARROW_FLIGHT_SQL_IMPORT_LIB,
+# path to libarrow_flight's import library (Windows only)
+# ARROW_FLIGHT_SQL_INCLUDE_DIR, directory containing headers
+# ARROW_FLIGHT_SQL_LIBS, deprecated. Use ARROW_FLIGHT_SQL_LIB_DIR instead
+# ARROW_FLIGHT_SQL_LIB_DIR, directory containing Flight libraries
+# ARROW_FLIGHT_SQL_SHARED_IMP_LIB, deprecated. Use ARROW_FLIGHT_SQL_IMPORT_LIB instead
+# ARROW_FLIGHT_SQL_SHARED_LIB, path to libarrow_flight's shared library
+# ARROW_FLIGHT_SQL_STATIC_LIB, path to libarrow_flight.a
+
+if(DEFINED ARROW_FLIGHT_SQL_FOUND)
+ return()
+endif()
+
+set(find_package_arguments)
+if(${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION)
+ list(APPEND find_package_arguments "${${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION}")
+endif()
+if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED)
+ list(APPEND find_package_arguments REQUIRED)
+endif()
+if(${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY)
+ list(APPEND find_package_arguments QUIET)
+endif()
+find_package(Arrow ${find_package_arguments})
+
+if(ARROW_FOUND)
+ arrow_find_package(ARROW_FLIGHT_SQL
+ "${ARROW_HOME}"
+ arrow_flight_sql
+ arrow/flight/sql/api.h
+ ArrowFlightSql
+ arrow-flight-sql)
+ if(NOT ARROW_FLIGHT_SQL_VERSION)
+ set(ARROW_FLIGHT_SQL_VERSION "${ARROW_VERSION}")
+ endif()
+endif()
+
+if("${ARROW_FLIGHT_SQL_VERSION}" VERSION_EQUAL "${ARROW_VERSION}")
+ set(ARROW_FLIGHT_SQL_VERSION_MATCH TRUE)
+else()
+ set(ARROW_FLIGHT_SQL_VERSION_MATCH FALSE)
+endif()
+
+mark_as_advanced(ARROW_FLIGHT_SQL_IMPORT_LIB
+ ARROW_FLIGHT_SQL_INCLUDE_DIR
+ ARROW_FLIGHT_SQL_LIBS
+ ARROW_FLIGHT_SQL_LIB_DIR
+ ARROW_FLIGHT_SQL_SHARED_IMP_LIB
+ ARROW_FLIGHT_SQL_SHARED_LIB
+ ARROW_FLIGHT_SQL_STATIC_LIB
+ ARROW_FLIGHT_SQL_VERSION
+ ARROW_FLIGHT_SQL_VERSION_MATCH)
+
+find_package_handle_standard_args(
+ ArrowFlightSql
+ REQUIRED_VARS ARROW_FLIGHT_SQL_INCLUDE_DIR ARROW_FLIGHT_SQL_LIB_DIR
+ ARROW_FLIGHT_SQL_VERSION_MATCH
+ VERSION_VAR ARROW_FLIGHT_SQL_VERSION)
+set(ARROW_FLIGHT_SQL_FOUND ${ArrowFlightSql_FOUND})
+
+if(ArrowFlightSql_FOUND AND NOT ArrowFlightSql_FIND_QUIETLY)
+ message(STATUS "Found the Arrow Flight SQL by ${ARROW_FLIGHT_SQL_FIND_APPROACH}")
+ message(STATUS "Found the Arrow Flight SQL shared library: ${ARROW_FLIGHT_SQL_SHARED_LIB}"
+ )
+ message(STATUS "Found the Arrow Flight SQL import library: ${ARROW_FLIGHT_SQL_IMPORT_LIB}"
+ )
+ message(STATUS "Found the Arrow Flight SQL static library: ${ARROW_FLIGHT_SQL_STATIC_LIB}"
+ )
+endif()
diff --git a/cpp/cmake_modules/FindSQLite3Alt.cmake b/cpp/cmake_modules/FindSQLite3Alt.cmake
new file mode 100644
index 0000000..73a45f0
--- /dev/null
+++ b/cpp/cmake_modules/FindSQLite3Alt.cmake
@@ -0,0 +1,43 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Once done this will define
+# - FindSQLite3Alt
+#
+# This module will set the following variables if found:
+# SQLite3_INCLUDE_DIRS - SQLite3 include dir.
+# SQLite3_LIBRARIES - List of libraries when using SQLite3.
+# SQLite3_FOUND - True if SQLite3 found.
+#
+# Usage of this module as follows:
+# find_package(SQLite3Alt)
+
+find_path(SQLite3_INCLUDE_DIR sqlite3.h)
+find_library(SQLite3_LIBRARY NAMES sqlite3)
+
+# handle the QUIETLY and REQUIRED arguments and set SQLite3_FOUND to TRUE if
+# all listed variables are TRUE
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(SQLite3Alt REQUIRED_VARS SQLite3_LIBRARY
+ SQLite3_INCLUDE_DIR)
+
+mark_as_advanced(SQLite3_LIBRARY SQLite3_INCLUDE_DIR)
+
+if(SQLite3Alt_FOUND)
+ set(SQLite3_INCLUDE_DIRS ${SQLite3_INCLUDE_DIR})
+ set(SQLite3_LIBRARIES ${SQLite3_LIBRARY})
+endif()
diff --git a/cpp/src/arrow/CMakeLists.txt b/cpp/src/arrow/CMakeLists.txt
index 5736c55..502629a 100644
--- a/cpp/src/arrow/CMakeLists.txt
+++ b/cpp/src/arrow/CMakeLists.txt
@@ -732,6 +732,10 @@ if(ARROW_FLIGHT)
add_subdirectory(flight)
endif()
+if(ARROW_FLIGHT_SQL)
+ add_subdirectory(flight/sql)
+endif()
+
if(ARROW_HIVESERVER2)
add_subdirectory(dbi/hiveserver2)
endif()
diff --git a/cpp/src/arrow/flight/CMakeLists.txt b/cpp/src/arrow/flight/CMakeLists.txt
index 8a3228e..55e89b2 100644
--- a/cpp/src/arrow/flight/CMakeLists.txt
+++ b/cpp/src/arrow/flight/CMakeLists.txt
@@ -25,7 +25,23 @@ if(WIN32)
list(APPEND ARROW_FLIGHT_LINK_LIBS ws2_32.lib)
endif()
-if(ARROW_TEST_LINKAGE STREQUAL "static")
+set(ARROW_FLIGHT_TEST_LINKAGE
+ "${ARROW_TEST_LINKAGE}"
+ PARENT_SCOPE)
+if(Protobuf_USE_STATIC_LIBS)
+ message(STATUS "Linking Arrow Flight tests statically due to static Protobuf")
+ set(ARROW_FLIGHT_TEST_LINKAGE
+ "static"
+ PARENT_SCOPE)
+endif()
+if(NOT ARROW_GRPC_USE_SHARED)
+ message(STATUS "Linking Arrow Flight tests statically due to static gRPC")
+ set(ARROW_FLIGHT_TEST_LINKAGE
+ "static"
+ PARENT_SCOPE)
+endif()
+
+if(ARROW_FLIGHT_TEST_LINKAGE STREQUAL "static")
set(ARROW_FLIGHT_TEST_LINK_LIBS
arrow_flight_static arrow_flight_testing_static ${ARROW_FLIGHT_STATIC_LINK_LIBS}
${ARROW_TEST_LINK_LIBS})
diff --git a/cpp/src/arrow/flight/sql/ArrowFlightSqlConfig.cmake.in b/cpp/src/arrow/flight/sql/ArrowFlightSqlConfig.cmake.in
new file mode 100644
index 0000000..1658f44
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/ArrowFlightSqlConfig.cmake.in
@@ -0,0 +1,36 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# This config sets the following variables in your project::
+#
+# ArrowFlightSql_FOUND - true if Arrow Flight SQL found on the system
+#
+# This config sets the following targets in your project::
+#
+# arrow_flight_sql_shared - for linked as shared library if shared library is built
+# arrow_flight_sql_static - for linked as static library if static library is built
+
+@PACKAGE_INIT@
+
+include(CMakeFindDependencyMacro)
+find_dependency(ArrowFlight)
+
+# Load targets only once. If we load targets multiple times, CMake reports
+# already existent target error.
+if(NOT (TARGET arrow_flight_sql_shared OR TARGET arrow_flight_sql_static))
+ include("${CMAKE_CURRENT_LIST_DIR}/ArrowFlightSqlTargets.cmake")
+endif()
diff --git a/cpp/src/arrow/flight/sql/CMakeLists.txt b/cpp/src/arrow/flight/sql/CMakeLists.txt
new file mode 100644
index 0000000..4a31f5b
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/CMakeLists.txt
@@ -0,0 +1,100 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+add_custom_target(arrow_flight_sql)
+
+arrow_install_all_headers("arrow/flight/sql")
+
+set(FLIGHT_SQL_PROTO_PATH "${ARROW_SOURCE_DIR}/../format")
+set(FLIGHT_SQL_PROTO ${ARROW_SOURCE_DIR}/../format/FlightSql.proto)
+
+set(FLIGHT_SQL_GENERATED_PROTO_FILES "${CMAKE_CURRENT_BINARY_DIR}/FlightSql.pb.cc"
+ "${CMAKE_CURRENT_BINARY_DIR}/FlightSql.pb.h")
+
+set(PROTO_DEPENDS ${FLIGHT_SQL_PROTO} ${ARROW_PROTOBUF_LIBPROTOBUF})
+
+add_custom_command(OUTPUT ${FLIGHT_SQL_GENERATED_PROTO_FILES}
+ COMMAND ${ARROW_PROTOBUF_PROTOC} "-I${FLIGHT_SQL_PROTO_PATH}"
+ "--cpp_out=${CMAKE_CURRENT_BINARY_DIR}" "${FLIGHT_SQL_PROTO}"
+ DEPENDS ${PROTO_DEPENDS})
+
+set_source_files_properties(${FLIGHT_SQL_GENERATED_PROTO_FILES} PROPERTIES GENERATED TRUE)
+
+add_custom_target(flight_sql_protobuf_gen ALL DEPENDS ${FLIGHT_SQL_GENERATED_PROTO_FILES})
+
+set(ARROW_FLIGHT_SQL_SRCS server.cc sql_info_internal.cc client.cc
+ "${CMAKE_CURRENT_BINARY_DIR}/FlightSql.pb.cc")
+
+add_arrow_lib(arrow_flight_sql
+ CMAKE_PACKAGE_NAME
+ ArrowFlightSql
+ PKG_CONFIG_NAME
+ arrow-flight-sql
+ OUTPUTS
+ ARROW_FLIGHT_SQL_LIBRARIES
+ SOURCES
+ ${ARROW_FLIGHT_SQL_SRCS}
+ DEPENDENCIES
+ flight_sql_protobuf_gen
+ SHARED_LINK_FLAGS
+ ${ARROW_VERSION_SCRIPT_FLAGS} # Defined in cpp/arrow/CMakeLists.txt
+ SHARED_LINK_LIBS
+ arrow_flight_shared
+ STATIC_LINK_LIBS
+ arrow_flight_static)
+
+if(ARROW_FLIGHT_TEST_LINKAGE STREQUAL "static")
+ set(ARROW_FLIGHT_SQL_TEST_LINK_LIBS
+ arrow_flight_sql_static arrow_flight_testing_static
+ ${ARROW_FLIGHT_STATIC_LINK_LIBS} ${ARROW_TEST_LINK_LIBS})
+else()
+ set(ARROW_FLIGHT_SQL_TEST_LINK_LIBS arrow_flight_sql_shared arrow_flight_testing_shared
+ ${ARROW_TEST_LINK_LIBS})
+endif()
+
+# Build test server for unit tests
+if(ARROW_BUILD_TESTS OR ARROW_BUILD_EXAMPLES)
+ find_package(SQLite3Alt REQUIRED)
+
+ set(ARROW_FLIGHT_SQL_TEST_SERVER_SRCS
+ example/sqlite_sql_info.cc
+ example/sqlite_statement.cc
+ example/sqlite_statement_batch_reader.cc
+ example/sqlite_server.cc
+ example/sqlite_tables_schema_batch_reader.cc)
+
+ add_arrow_test(flight_sql_test
+ SOURCES
+ client_test.cc
+ server_test.cc
+ ${ARROW_FLIGHT_SQL_TEST_SERVER_SRCS}
+ STATIC_LINK_LIBS
+ ${ARROW_FLIGHT_SQL_TEST_LINK_LIBS}
+ ${SQLite3_LIBRARIES}
+ LABELS
+ "arrow_flight_sql")
+
+ add_executable(flight_sql_test_server test_server_cli.cc
+ ${ARROW_FLIGHT_SQL_TEST_SERVER_SRCS})
+ target_link_libraries(flight_sql_test_server
+ PRIVATE ${ARROW_FLIGHT_SQL_TEST_LINK_LIBS} ${GFLAGS_LIBRARIES}
+ ${SQLite3_LIBRARIES})
+
+ add_executable(flight_sql_test_app test_app_cli.cc)
+ target_link_libraries(flight_sql_test_app PRIVATE ${ARROW_FLIGHT_SQL_TEST_LINK_LIBS}
+ ${GFLAGS_LIBRARIES})
+endif()
diff --git a/cpp/src/arrow/flight/sql/api.h b/cpp/src/arrow/flight/sql/api.h
new file mode 100644
index 0000000..3b909ee
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/api.h
@@ -0,0 +1,20 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include "arrow/flight/sql/client.h"
diff --git a/cpp/src/arrow/flight/sql/arrow-flight-sql.pc.in b/cpp/src/arrow/flight/sql/arrow-flight-sql.pc.in
new file mode 100644
index 0000000..6d4eab0
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/arrow-flight-sql.pc.in
@@ -0,0 +1,25 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+libdir=@CMAKE_INSTALL_FULL_LIBDIR@
+includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
+
+Name: Apache Arrow Flight SQL
+Description: Apache Arrow Flight SQL extension
+Version: @ARROW_VERSION@
+Requires: arrow-flight
+Libs: -L${libdir} -larrow_flight_sql
diff --git a/cpp/src/arrow/flight/sql/client.cc b/cpp/src/arrow/flight/sql/client.cc
new file mode 100644
index 0000000..50a5777
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/client.cc
@@ -0,0 +1,425 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "arrow/flight/sql/client.h"
+
+#include <google/protobuf/any.pb.h>
+
+#include "arrow/buffer.h"
+#include "arrow/flight/sql/FlightSql.pb.h"
+#include "arrow/flight/types.h"
+#include "arrow/io/memory.h"
+#include "arrow/ipc/reader.h"
+#include "arrow/result.h"
+#include "arrow/testing/gtest_util.h"
+#include "arrow/util/logging.h"
+
+namespace flight_sql_pb = arrow::flight::protocol::sql;
+
+namespace arrow {
+namespace flight {
+namespace sql {
+
+FlightSqlClient::FlightSqlClient(std::shared_ptr<FlightClient> client)
+ : impl_(std::move(client)) {}
+
+PreparedStatement::PreparedStatement(FlightSqlClient* client, std::string handle,
+ std::shared_ptr<Schema> dataset_schema,
+ std::shared_ptr<Schema> parameter_schema,
+ FlightCallOptions options)
+ : client_(client),
+ options_(std::move(options)),
+ handle_(std::move(handle)),
+ dataset_schema_(std::move(dataset_schema)),
+ parameter_schema_(std::move(parameter_schema)),
+ is_closed_(false) {}
+
+PreparedStatement::~PreparedStatement() {
+ if (IsClosed()) return;
+
+ const Status status = Close();
+ if (!status.ok()) {
+ ARROW_LOG(ERROR) << "Failed to delete PreparedStatement: " << status.ToString();
+ }
+}
+
+inline FlightDescriptor GetFlightDescriptorForCommand(
+ const google::protobuf::Message& command) {
+ google::protobuf::Any any;
+ any.PackFrom(command);
+
+ const std::string& string = any.SerializeAsString();
+ return FlightDescriptor::Command(string);
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoForCommand(
+ FlightSqlClient& client, const FlightCallOptions& options,
+ const google::protobuf::Message& command) {
+ const FlightDescriptor& descriptor = GetFlightDescriptorForCommand(command);
+
+ ARROW_ASSIGN_OR_RAISE(auto flight_info, client.GetFlightInfo(options, descriptor));
+ return std::move(flight_info);
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> FlightSqlClient::Execute(
+ const FlightCallOptions& options, const std::string& query) {
+ flight_sql_pb::CommandStatementQuery command;
+ command.set_query(query);
+
+ return GetFlightInfoForCommand(*this, options, command);
+}
+
+arrow::Result<int64_t> FlightSqlClient::ExecuteUpdate(const FlightCallOptions& options,
+ const std::string& query) {
+ flight_sql_pb::CommandStatementUpdate command;
+ command.set_query(query);
+
+ const FlightDescriptor& descriptor = GetFlightDescriptorForCommand(command);
+
+ std::unique_ptr<FlightStreamWriter> writer;
+ std::unique_ptr<FlightMetadataReader> reader;
+
+ ARROW_RETURN_NOT_OK(DoPut(options, descriptor, NULLPTR, &writer, &reader));
+
+ std::shared_ptr<Buffer> metadata;
+
+ ARROW_RETURN_NOT_OK(reader->ReadMetadata(&metadata));
+
+ flight_sql_pb::DoPutUpdateResult doPutUpdateResult;
+
+ flight_sql_pb::DoPutUpdateResult result;
+ if (!result.ParseFromArray(metadata->data(), static_cast<int>(metadata->size()))) {
+ return Status::Invalid("Unable to parse DoPutUpdateResult object.");
+ }
+
+ return result.record_count();
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> FlightSqlClient::GetCatalogs(
+ const FlightCallOptions& options) {
+ flight_sql_pb::CommandGetCatalogs command;
+
+ return GetFlightInfoForCommand(*this, options, command);
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> FlightSqlClient::GetDbSchemas(
+ const FlightCallOptions& options, const std::string* catalog,
+ const std::string* db_schema_filter_pattern) {
+ flight_sql_pb::CommandGetDbSchemas command;
+ if (catalog != NULLPTR) {
+ command.set_catalog(*catalog);
+ }
+ if (db_schema_filter_pattern != NULLPTR) {
+ command.set_db_schema_filter_pattern(*db_schema_filter_pattern);
+ }
+
+ return GetFlightInfoForCommand(*this, options, command);
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> FlightSqlClient::GetTables(
+ const FlightCallOptions& options, const std::string* catalog,
+ const std::string* db_schema_filter_pattern, const std::string* table_filter_pattern,
+ bool include_schema, const std::vector<std::string>* table_types) {
+ flight_sql_pb::CommandGetTables command;
+
+ if (catalog != NULLPTR) {
+ command.set_catalog(*catalog);
+ }
+
+ if (db_schema_filter_pattern != NULLPTR) {
+ command.set_db_schema_filter_pattern(*db_schema_filter_pattern);
+ }
+
+ if (table_filter_pattern != NULLPTR) {
+ command.set_table_name_filter_pattern(*table_filter_pattern);
+ }
+
+ command.set_include_schema(include_schema);
+
+ if (table_types != NULLPTR) {
+ for (const std::string& table_type : *table_types) {
+ command.add_table_types(table_type);
+ }
+ }
+
+ return GetFlightInfoForCommand(*this, options, command);
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> FlightSqlClient::GetPrimaryKeys(
+ const FlightCallOptions& options, const TableRef& table_ref) {
+ flight_sql_pb::CommandGetPrimaryKeys command;
+
+ if (table_ref.catalog.has_value()) {
+ command.set_catalog(table_ref.catalog.value());
+ }
+
+ if (table_ref.db_schema.has_value()) {
+ command.set_db_schema(table_ref.db_schema.value());
+ }
+
+ command.set_table(table_ref.table);
+
+ return GetFlightInfoForCommand(*this, options, command);
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> FlightSqlClient::GetExportedKeys(
+ const FlightCallOptions& options, const TableRef& table_ref) {
+ flight_sql_pb::CommandGetExportedKeys command;
+
+ if (table_ref.catalog.has_value()) {
+ command.set_catalog(table_ref.catalog.value());
+ }
+
+ if (table_ref.db_schema.has_value()) {
+ command.set_db_schema(table_ref.db_schema.value());
+ }
+
+ command.set_table(table_ref.table);
+
+ return GetFlightInfoForCommand(*this, options, command);
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> FlightSqlClient::GetImportedKeys(
+ const FlightCallOptions& options, const TableRef& table_ref) {
+ flight_sql_pb::CommandGetImportedKeys command;
+
+ if (table_ref.catalog.has_value()) {
+ command.set_catalog(table_ref.catalog.value());
+ }
+
+ if (table_ref.db_schema.has_value()) {
+ command.set_db_schema(table_ref.db_schema.value());
+ }
+
+ command.set_table(table_ref.table);
+
+ return GetFlightInfoForCommand(*this, options, command);
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> FlightSqlClient::GetCrossReference(
+ const FlightCallOptions& options, const TableRef& pk_table_ref,
+ const TableRef& fk_table_ref) {
+ flight_sql_pb::CommandGetCrossReference command;
+
+ if (pk_table_ref.catalog.has_value()) {
+ command.set_pk_catalog(pk_table_ref.catalog.value());
+ }
+ if (pk_table_ref.db_schema.has_value()) {
+ command.set_pk_db_schema(pk_table_ref.db_schema.value());
+ }
+ command.set_pk_table(pk_table_ref.table);
+
+ if (fk_table_ref.catalog.has_value()) {
+ command.set_fk_catalog(fk_table_ref.catalog.value());
+ }
+ if (fk_table_ref.db_schema.has_value()) {
+ command.set_fk_db_schema(fk_table_ref.db_schema.value());
+ }
+ command.set_fk_table(fk_table_ref.table);
+
+ return GetFlightInfoForCommand(*this, options, command);
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> FlightSqlClient::GetTableTypes(
+ const FlightCallOptions& options) {
+ flight_sql_pb::CommandGetTableTypes command;
+
+ return GetFlightInfoForCommand(*this, options, command);
+}
+
+arrow::Result<std::unique_ptr<FlightStreamReader>> FlightSqlClient::DoGet(
+ const FlightCallOptions& options, const Ticket& ticket) {
+ std::unique_ptr<FlightStreamReader> stream;
+ ARROW_RETURN_NOT_OK(DoGet(options, ticket, &stream));
+
+ return std::move(stream);
+}
+
+arrow::Result<std::shared_ptr<PreparedStatement>> FlightSqlClient::Prepare(
+ const FlightCallOptions& options, const std::string& query) {
+ google::protobuf::Any command;
+ flight_sql_pb::ActionCreatePreparedStatementRequest request;
+ request.set_query(query);
+ command.PackFrom(request);
+
+ Action action;
+ action.type = "CreatePreparedStatement";
+ action.body = Buffer::FromString(command.SerializeAsString());
+
+ std::unique_ptr<ResultStream> results;
+
+ ARROW_RETURN_NOT_OK(DoAction(options, action, &results));
+
+ std::unique_ptr<Result> result;
+ ARROW_RETURN_NOT_OK(results->Next(&result));
+
+ google::protobuf::Any prepared_result;
+
+ std::shared_ptr<Buffer> message = std::move(result->body);
+ if (!prepared_result.ParseFromArray(message->data(),
+ static_cast<int>(message->size()))) {
+ return Status::Invalid("Unable to parse packed ActionCreatePreparedStatementResult");
+ }
+
+ flight_sql_pb::ActionCreatePreparedStatementResult prepared_statement_result;
+
+ if (!prepared_result.UnpackTo(&prepared_statement_result)) {
+ return Status::Invalid("Unable to unpack ActionCreatePreparedStatementResult");
+ }
+
+ const std::string& serialized_dataset_schema =
+ prepared_statement_result.dataset_schema();
+ const std::string& serialized_parameter_schema =
+ prepared_statement_result.parameter_schema();
+
+ std::shared_ptr<Schema> dataset_schema;
+ if (!serialized_dataset_schema.empty()) {
+ io::BufferReader dataset_schema_reader(serialized_dataset_schema);
+ ipc::DictionaryMemo in_memo;
+ ARROW_ASSIGN_OR_RAISE(dataset_schema, ReadSchema(&dataset_schema_reader, &in_memo));
+ }
+ std::shared_ptr<Schema> parameter_schema;
+ if (!serialized_parameter_schema.empty()) {
+ io::BufferReader parameter_schema_reader(serialized_parameter_schema);
+ ipc::DictionaryMemo in_memo;
+ ARROW_ASSIGN_OR_RAISE(parameter_schema,
+ ReadSchema(¶meter_schema_reader, &in_memo));
+ }
+ auto handle = prepared_statement_result.prepared_statement_handle();
+
+ return std::make_shared<PreparedStatement>(this, handle, dataset_schema,
+ parameter_schema, options);
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> PreparedStatement::Execute() {
+ if (is_closed_) {
+ return Status::Invalid("Statement already closed.");
+ }
+
+ flight_sql_pb::CommandPreparedStatementQuery execute_query_command;
+
+ execute_query_command.set_prepared_statement_handle(handle_);
+
+ google::protobuf::Any any;
+ any.PackFrom(execute_query_command);
+
+ const std::string& string = any.SerializeAsString();
+ const FlightDescriptor descriptor = FlightDescriptor::Command(string);
+
+ if (parameter_binding_ && parameter_binding_->num_rows() > 0) {
+ std::unique_ptr<FlightStreamWriter> writer;
+ std::unique_ptr<FlightMetadataReader> reader;
+ ARROW_RETURN_NOT_OK(client_->DoPut(options_, descriptor, parameter_binding_->schema(),
+ &writer, &reader));
+
+ ARROW_RETURN_NOT_OK(writer->WriteRecordBatch(*parameter_binding_));
+ ARROW_RETURN_NOT_OK(writer->DoneWriting());
+ // Wait for the server to ack the result
+ std::shared_ptr<Buffer> buffer;
+ ARROW_RETURN_NOT_OK(reader->ReadMetadata(&buffer));
+ }
+
+ ARROW_ASSIGN_OR_RAISE(auto flight_info, client_->GetFlightInfo(options_, descriptor));
+ return std::move(flight_info);
+}
+
+arrow::Result<int64_t> PreparedStatement::ExecuteUpdate() {
+ if (is_closed_) {
+ return Status::Invalid("Statement already closed.");
+ }
+
+ flight_sql_pb::CommandPreparedStatementUpdate command;
+ command.set_prepared_statement_handle(handle_);
+ const FlightDescriptor& descriptor = GetFlightDescriptorForCommand(command);
+ std::unique_ptr<FlightStreamWriter> writer;
+ std::unique_ptr<FlightMetadataReader> reader;
+
+ if (parameter_binding_ && parameter_binding_->num_rows() > 0) {
+ ARROW_RETURN_NOT_OK(client_->DoPut(options_, descriptor, parameter_binding_->schema(),
+ &writer, &reader));
+ ARROW_RETURN_NOT_OK(writer->WriteRecordBatch(*parameter_binding_));
+ } else {
+ const std::shared_ptr<Schema> schema = arrow::schema({});
+ ARROW_RETURN_NOT_OK(client_->DoPut(options_, descriptor, schema, &writer, &reader));
+ const auto& record_batch =
+ arrow::RecordBatch::Make(schema, 0, (std::vector<std::shared_ptr<Array>>){});
+ ARROW_RETURN_NOT_OK(writer->WriteRecordBatch(*record_batch));
+ }
+
+ ARROW_RETURN_NOT_OK(writer->DoneWriting());
+ std::shared_ptr<Buffer> metadata;
+ ARROW_RETURN_NOT_OK(reader->ReadMetadata(&metadata));
+ ARROW_RETURN_NOT_OK(writer->Close());
+
+ flight_sql_pb::DoPutUpdateResult result;
+ if (!result.ParseFromArray(metadata->data(), static_cast<int>(metadata->size()))) {
+ return Status::Invalid("Unable to parse DoPutUpdateResult object.");
+ }
+
+ return result.record_count();
+}
+
+Status PreparedStatement::SetParameters(std::shared_ptr<RecordBatch> parameter_binding) {
+ parameter_binding_ = std::move(parameter_binding);
+
+ return Status::OK();
+}
+
+bool PreparedStatement::IsClosed() const { return is_closed_; }
+
+std::shared_ptr<Schema> PreparedStatement::dataset_schema() const {
+ return dataset_schema_;
+}
+
+std::shared_ptr<Schema> PreparedStatement::parameter_schema() const {
+ return parameter_schema_;
+}
+
+Status PreparedStatement::Close() {
+ if (is_closed_) {
+ return Status::Invalid("Statement already closed.");
+ }
+ google::protobuf::Any command;
+ flight_sql_pb::ActionClosePreparedStatementRequest request;
+ request.set_prepared_statement_handle(handle_);
+
+ command.PackFrom(request);
+
+ Action action;
+ action.type = "ClosePreparedStatement";
+ action.body = Buffer::FromString(command.SerializeAsString());
+
+ std::unique_ptr<ResultStream> results;
+
+ ARROW_RETURN_NOT_OK(client_->DoAction(options_, action, &results));
+
+ is_closed_ = true;
+
+ return Status::OK();
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> FlightSqlClient::GetSqlInfo(
+ const FlightCallOptions& options, const std::vector<int>& sql_info) {
+ flight_sql_pb::CommandGetSqlInfo command;
+ for (const int& info : sql_info) command.add_info(info);
+
+ return GetFlightInfoForCommand(*this, options, command);
+}
+
+} // namespace sql
+} // namespace flight
+} // namespace arrow
diff --git a/cpp/src/arrow/flight/sql/client.h b/cpp/src/arrow/flight/sql/client.h
new file mode 100644
index 0000000..5bf1b3e
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/client.h
@@ -0,0 +1,247 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include "arrow/flight/client.h"
+#include "arrow/flight/sql/types.h"
+#include "arrow/flight/types.h"
+#include "arrow/result.h"
+#include "arrow/status.h"
+
+namespace arrow {
+namespace flight {
+namespace sql {
+
+class PreparedStatement;
+
+/// \brief Flight client with Flight SQL semantics.
+class ARROW_EXPORT FlightSqlClient {
+ friend class PreparedStatement;
+
+ private:
+ std::shared_ptr<FlightClient> impl_;
+
+ public:
+ explicit FlightSqlClient(std::shared_ptr<FlightClient> client);
+
+ virtual ~FlightSqlClient() = default;
+
+ /// \brief Execute a query on the server.
+ /// \param[in] options RPC-layer hints for this call.
+ /// \param[in] query The query to be executed in the UTF-8 format.
+ /// \return The FlightInfo describing where to access the dataset.
+ arrow::Result<std::unique_ptr<FlightInfo>> Execute(const FlightCallOptions& options,
+ const std::string& query);
+
+ /// \brief Execute an update query on the server.
+ /// \param[in] options RPC-layer hints for this call.
+ /// \param[in] query The query to be executed in the UTF-8 format.
+ /// \return The quantity of rows affected by the operation.
+ arrow::Result<int64_t> ExecuteUpdate(const FlightCallOptions& options,
+ const std::string& query);
+
+ /// \brief Request a list of catalogs.
+ /// \param[in] options RPC-layer hints for this call.
+ /// \return The FlightInfo describing where to access the dataset.
+ arrow::Result<std::unique_ptr<FlightInfo>> GetCatalogs(
+ const FlightCallOptions& options);
+
+ /// \brief Request a list of database schemas.
+ /// \param[in] options RPC-layer hints for this call.
+ /// \param[in] catalog The catalog.
+ /// \param[in] db_schema_filter_pattern The schema filter pattern.
+ /// \return The FlightInfo describing where to access the dataset.
+ arrow::Result<std::unique_ptr<FlightInfo>> GetDbSchemas(
+ const FlightCallOptions& options, const std::string* catalog,
+ const std::string* db_schema_filter_pattern);
+
+ /// \brief Given a flight ticket and schema, request to be sent the
+ /// stream. Returns record batch stream reader
+ /// \param[in] options Per-RPC options
+ /// \param[in] ticket The flight ticket to use
+ /// \return The returned RecordBatchReader
+ arrow::Result<std::unique_ptr<FlightStreamReader>> DoGet(
+ const FlightCallOptions& options, const Ticket& ticket);
+
+ /// \brief Request a list of tables.
+ /// \param[in] options RPC-layer hints for this call.
+ /// \param[in] catalog The catalog.
+ /// \param[in] db_schema_filter_pattern The schema filter pattern.
+ /// \param[in] table_filter_pattern The table filter pattern.
+ /// \param[in] include_schema True to include the schema upon return,
+ /// false to not include the schema.
+ /// \param[in] table_types The table types to include.
+ /// \return The FlightInfo describing where to access the dataset.
+ arrow::Result<std::unique_ptr<FlightInfo>> GetTables(
+ const FlightCallOptions& options, const std::string* catalog,
+ const std::string* db_schema_filter_pattern,
+ const std::string* table_filter_pattern, bool include_schema,
+ const std::vector<std::string>* table_types);
+
+ /// \brief Request the primary keys for a table.
+ /// \param[in] options RPC-layer hints for this call.
+ /// \param[in] table_ref The table reference.
+ /// \return The FlightInfo describing where to access the dataset.
+ arrow::Result<std::unique_ptr<FlightInfo>> GetPrimaryKeys(
+ const FlightCallOptions& options, const TableRef& table_ref);
+
+ /// \brief Retrieves a description about the foreign key columns that reference the
+ /// primary key columns of the given table.
+ /// \param[in] options RPC-layer hints for this call.
+ /// \param[in] table_ref The table reference.
+ /// \return The FlightInfo describing where to access the dataset.
+ arrow::Result<std::unique_ptr<FlightInfo>> GetExportedKeys(
+ const FlightCallOptions& options, const TableRef& table_ref);
+
+ /// \brief Retrieves the foreign key columns for the given table.
+ /// \param[in] options RPC-layer hints for this call.
+ /// \param[in] table_ref The table reference.
+ /// \return The FlightInfo describing where to access the dataset.
+ arrow::Result<std::unique_ptr<FlightInfo>> GetImportedKeys(
+ const FlightCallOptions& options, const TableRef& table_ref);
+
+ /// \brief Retrieves a description of the foreign key columns in the given foreign key
+ /// table that reference the primary key or the columns representing a unique
+ /// constraint of the parent table (could be the same or a different table).
+ /// \param[in] options RPC-layer hints for this call.
+ /// \param[in] pk_table_ref The table reference that exports the key.
+ /// \param[in] fk_table_ref The table reference that imports the key.
+ /// \return The FlightInfo describing where to access the dataset.
+ arrow::Result<std::unique_ptr<FlightInfo>> GetCrossReference(
+ const FlightCallOptions& options, const TableRef& pk_table_ref,
+ const TableRef& fk_table_ref);
+
+ /// \brief Request a list of table types.
+ /// \param[in] options RPC-layer hints for this call.
+ /// \return The FlightInfo describing where to access the dataset.
+ arrow::Result<std::unique_ptr<FlightInfo>> GetTableTypes(
+ const FlightCallOptions& options);
+
+ /// \brief Request a list of SQL information.
+ /// \param[in] options RPC-layer hints for this call.
+ /// \param[in] sql_info the SQL info required.
+ /// \return The FlightInfo describing where to access the dataset.
+ arrow::Result<std::unique_ptr<FlightInfo>> GetSqlInfo(const FlightCallOptions& options,
+ const std::vector<int>& sql_info);
+
+ /// \brief Create a prepared statement object.
+ /// \param[in] options RPC-layer hints for this call.
+ /// \param[in] query The query that will be executed.
+ /// \return The created prepared statement.
+ arrow::Result<std::shared_ptr<PreparedStatement>> Prepare(
+ const FlightCallOptions& options, const std::string& query);
+
+ /// \brief Retrieve the FlightInfo.
+ /// \param[in] options RPC-layer hints for this call.
+ /// \param[in] descriptor The flight descriptor.
+ /// \return The flight info with the metadata.
+ // NOTE: This is public because it is been used by the anonymous
+ // function GetFlightInfoForCommand.
+ virtual arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfo(
+ const FlightCallOptions& options, const FlightDescriptor& descriptor) {
+ std::unique_ptr<FlightInfo> info;
+ ARROW_RETURN_NOT_OK(impl_->GetFlightInfo(options, descriptor, &info));
+
+ return info;
+ }
+
+ protected:
+ virtual Status DoPut(const FlightCallOptions& options,
+ const FlightDescriptor& descriptor,
+ const std::shared_ptr<Schema>& schema,
+ std::unique_ptr<FlightStreamWriter>* stream,
+ std::unique_ptr<FlightMetadataReader>* reader) {
+ return impl_->DoPut(options, descriptor, schema, stream, reader);
+ }
+
+ virtual Status DoGet(const FlightCallOptions& options, const Ticket& ticket,
+ std::unique_ptr<FlightStreamReader>* stream) {
+ return impl_->DoGet(options, ticket, stream);
+ }
+
+ virtual Status DoAction(const FlightCallOptions& options, const Action& action,
+ std::unique_ptr<ResultStream>* results) {
+ return impl_->DoAction(options, action, results);
+ }
+};
+
+/// \brief PreparedStatement class from flight sql.
+class ARROW_EXPORT PreparedStatement {
+ FlightSqlClient* client_;
+ FlightCallOptions options_;
+ std::string handle_;
+ std::shared_ptr<Schema> dataset_schema_;
+ std::shared_ptr<Schema> parameter_schema_;
+ std::shared_ptr<RecordBatch> parameter_binding_;
+ bool is_closed_;
+
+ public:
+ /// \brief Constructor for the PreparedStatement class.
+ /// \param[in] client Client object used to make the RPC requests.
+ /// \param[in] handle Handle for this prepared statement.
+ /// \param[in] dataset_schema Schema of the resulting dataset.
+ /// \param[in] parameter_schema Schema of the parameters (if any).
+ /// \param[in] options RPC-layer hints for this call.
+ PreparedStatement(FlightSqlClient* client, std::string handle,
+ std::shared_ptr<Schema> dataset_schema,
+ std::shared_ptr<Schema> parameter_schema, FlightCallOptions options);
+
+ /// \brief Default destructor for the PreparedStatement class.
+ /// The destructor will call the Close method from the class in order,
+ /// to send a request to close the PreparedStatement.
+ /// NOTE: It is best to explicitly close the PreparedStatement, otherwise
+ /// errors can't be caught.
+ ~PreparedStatement();
+
+ /// \brief Executes the prepared statement query on the server.
+ /// \return A FlightInfo object representing the stream(s) to fetch.
+ arrow::Result<std::unique_ptr<FlightInfo>> Execute();
+
+ /// \brief Executes the prepared statement update query on the server.
+ /// \return The number of rows affected.
+ arrow::Result<int64_t> ExecuteUpdate();
+
+ /// \brief Retrieve the parameter schema from the query.
+ /// \return The parameter schema from the query.
+ std::shared_ptr<Schema> parameter_schema() const;
+
+ /// \brief Retrieve the ResultSet schema from the query.
+ /// \return The ResultSet schema from the query.
+ std::shared_ptr<Schema> dataset_schema() const;
+
+ /// \brief Set a RecordBatch that contains the parameters that will be bind.
+ /// \param parameter_binding The parameters that will be bind.
+ /// \return Status.
+ Status SetParameters(std::shared_ptr<RecordBatch> parameter_binding);
+
+ /// \brief Close the prepared statement, so that this PreparedStatement can not used
+ /// anymore and server can free up any resources.
+ /// \return Status.
+ Status Close();
+
+ /// \brief Check if the prepared statement is closed.
+ /// \return The state of the prepared statement.
+ bool IsClosed() const;
+};
+
+} // namespace sql
+} // namespace flight
+} // namespace arrow
diff --git a/cpp/src/arrow/flight/sql/client_test.cc b/cpp/src/arrow/flight/sql/client_test.cc
new file mode 100644
index 0000000..8c0c833
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/client_test.cc
@@ -0,0 +1,515 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "arrow/flight/client.h"
+
+#include <gmock/gmock.h>
+#include <google/protobuf/any.pb.h>
+#include <gtest/gtest.h>
+
+#include <utility>
+
+#include "arrow/flight/sql/FlightSql.pb.h"
+#include "arrow/flight/sql/api.h"
+#include "arrow/testing/gtest_util.h"
+
+namespace pb = arrow::flight::protocol;
+using ::testing::_;
+using ::testing::Ref;
+
+namespace arrow {
+namespace flight {
+namespace sql {
+
+class FlightSqlClientMock : public FlightSqlClient {
+ public:
+ FlightSqlClientMock() : FlightSqlClient(nullptr) {}
+
+ ~FlightSqlClientMock() = default;
+
+ MOCK_METHOD(arrow::Result<std::unique_ptr<FlightInfo>>, GetFlightInfo,
+ (const FlightCallOptions&, const FlightDescriptor&));
+ MOCK_METHOD(Status, DoGet,
+ (const FlightCallOptions& options, const Ticket& ticket,
+ std::unique_ptr<FlightStreamReader>* stream));
+ MOCK_METHOD(Status, DoPut,
+ (const FlightCallOptions&, const FlightDescriptor&,
+ const std::shared_ptr<Schema>& schema,
+ std::unique_ptr<FlightStreamWriter>*,
+ std::unique_ptr<FlightMetadataReader>*));
+ MOCK_METHOD(Status, DoAction,
+ (const FlightCallOptions& options, const Action& action,
+ std::unique_ptr<ResultStream>* results));
+};
+
+class TestFlightSqlClient : public ::testing::Test {
+ protected:
+ FlightSqlClientMock sql_client_;
+ FlightCallOptions call_options_;
+
+ void SetUp() override {}
+
+ void TearDown() override {}
+};
+
+class FlightMetadataReaderMock : public FlightMetadataReader {
+ public:
+ std::shared_ptr<Buffer>* buffer;
+
+ explicit FlightMetadataReaderMock(std::shared_ptr<Buffer>* buffer) {
+ this->buffer = buffer;
+ }
+
+ Status ReadMetadata(std::shared_ptr<Buffer>* out) override {
+ *out = *buffer;
+ return Status::OK();
+ }
+};
+
+class FlightStreamWriterMock : public FlightStreamWriter {
+ public:
+ FlightStreamWriterMock() = default;
+
+ Status DoneWriting() override { return Status::OK(); }
+
+ Status WriteMetadata(std::shared_ptr<Buffer> app_metadata) override {
+ return Status::OK();
+ }
+
+ Status Begin(const std::shared_ptr<Schema>& schema,
+ const ipc::IpcWriteOptions& options) override {
+ return Status::OK();
+ }
+
+ Status Begin(const std::shared_ptr<Schema>& schema) override {
+ return MetadataRecordBatchWriter::Begin(schema);
+ }
+
+ ipc::WriteStats stats() const override { return ipc::WriteStats(); }
+
+ Status WriteWithMetadata(const RecordBatch& batch,
+ std::shared_ptr<Buffer> app_metadata) override {
+ return Status::OK();
+ }
+
+ Status Close() override { return Status::OK(); }
+
+ Status WriteRecordBatch(const RecordBatch& batch) override { return Status::OK(); }
+};
+
+FlightDescriptor getDescriptor(google::protobuf::Message& command) {
+ google::protobuf::Any any;
+ any.PackFrom(command);
+
+ const std::string& string = any.SerializeAsString();
+ return FlightDescriptor::Command(string);
+}
+
+auto ReturnEmptyFlightInfo = [](const FlightCallOptions& options,
+ const FlightDescriptor& descriptor) {
+ std::unique_ptr<FlightInfo> flight_info;
+ return flight_info;
+};
+
+TEST_F(TestFlightSqlClient, TestGetCatalogs) {
+ pb::sql::CommandGetCatalogs command;
+ FlightDescriptor descriptor = getDescriptor(command);
+
+ ON_CALL(sql_client_, GetFlightInfo).WillByDefault(ReturnEmptyFlightInfo);
+ EXPECT_CALL(sql_client_, GetFlightInfo(Ref(call_options_), descriptor));
+
+ ASSERT_OK(sql_client_.GetCatalogs(call_options_));
+}
+
+TEST_F(TestFlightSqlClient, TestGetDbSchemas) {
+ std::string schema_filter_pattern = "schema_filter_pattern";
+ std::string catalog = "catalog";
+
+ pb::sql::CommandGetDbSchemas command;
+ command.set_catalog(catalog);
+ command.set_db_schema_filter_pattern(schema_filter_pattern);
+ FlightDescriptor descriptor = getDescriptor(command);
+
+ ON_CALL(sql_client_, GetFlightInfo).WillByDefault(ReturnEmptyFlightInfo);
+ EXPECT_CALL(sql_client_, GetFlightInfo(Ref(call_options_), descriptor));
+
+ ASSERT_OK(sql_client_.GetDbSchemas(call_options_, &catalog, &schema_filter_pattern));
+}
+
+TEST_F(TestFlightSqlClient, TestGetTables) {
+ std::string catalog = "catalog";
+ std::string schema_filter_pattern = "schema_filter_pattern";
+ std::string table_name_filter_pattern = "table_name_filter_pattern";
+ bool include_schema = true;
+ std::vector<std::string> table_types = {"type1", "type2"};
+
+ pb::sql::CommandGetTables command;
+ command.set_catalog(catalog);
+ command.set_db_schema_filter_pattern(schema_filter_pattern);
+ command.set_table_name_filter_pattern(table_name_filter_pattern);
+ command.set_include_schema(include_schema);
+ for (const std::string& table_type : table_types) {
+ command.add_table_types(table_type);
+ }
+ FlightDescriptor descriptor = getDescriptor(command);
+
+ ON_CALL(sql_client_, GetFlightInfo).WillByDefault(ReturnEmptyFlightInfo);
+ EXPECT_CALL(sql_client_, GetFlightInfo(Ref(call_options_), descriptor));
+
+ ASSERT_OK(sql_client_.GetTables(call_options_, &catalog, &schema_filter_pattern,
+ &table_name_filter_pattern, include_schema,
+ &table_types));
+}
+
+TEST_F(TestFlightSqlClient, TestGetTableTypes) {
+ pb::sql::CommandGetTableTypes command;
+ FlightDescriptor descriptor = getDescriptor(command);
+
+ ON_CALL(sql_client_, GetFlightInfo).WillByDefault(ReturnEmptyFlightInfo);
+ EXPECT_CALL(sql_client_, GetFlightInfo(Ref(call_options_), descriptor));
+
+ ASSERT_OK(sql_client_.GetTableTypes(call_options_));
+}
+
+TEST_F(TestFlightSqlClient, TestGetExported) {
+ std::string catalog = "catalog";
+ std::string schema = "schema";
+ std::string table = "table";
+
+ pb::sql::CommandGetExportedKeys command;
+ command.set_catalog(catalog);
+ command.set_db_schema(schema);
+ command.set_table(table);
+ FlightDescriptor descriptor = getDescriptor(command);
+
+ ON_CALL(sql_client_, GetFlightInfo).WillByDefault(ReturnEmptyFlightInfo);
+ EXPECT_CALL(sql_client_, GetFlightInfo(Ref(call_options_), descriptor));
+
+ TableRef table_ref = {util::make_optional(catalog), util::make_optional(schema), table};
+ ASSERT_OK(sql_client_.GetExportedKeys(call_options_, table_ref));
+}
+
+TEST_F(TestFlightSqlClient, TestGetImported) {
+ std::string catalog = "catalog";
+ std::string schema = "schema";
+ std::string table = "table";
+
+ pb::sql::CommandGetImportedKeys command;
+ command.set_catalog(catalog);
+ command.set_db_schema(schema);
+ command.set_table(table);
+ FlightDescriptor descriptor = getDescriptor(command);
+
+ ON_CALL(sql_client_, GetFlightInfo).WillByDefault(ReturnEmptyFlightInfo);
+ EXPECT_CALL(sql_client_, GetFlightInfo(Ref(call_options_), descriptor));
+
+ TableRef table_ref = {util::make_optional(catalog), util::make_optional(schema), table};
+ ASSERT_OK(sql_client_.GetImportedKeys(call_options_, table_ref));
+}
+
+TEST_F(TestFlightSqlClient, TestGetPrimary) {
+ std::string catalog = "catalog";
+ std::string schema = "schema";
+ std::string table = "table";
+
+ pb::sql::CommandGetPrimaryKeys command;
+ command.set_catalog(catalog);
+ command.set_db_schema(schema);
+ command.set_table(table);
+ FlightDescriptor descriptor = getDescriptor(command);
+
+ ON_CALL(sql_client_, GetFlightInfo).WillByDefault(ReturnEmptyFlightInfo);
+ EXPECT_CALL(sql_client_, GetFlightInfo(Ref(call_options_), descriptor));
+
+ TableRef table_ref = {util::make_optional(catalog), util::make_optional(schema), table};
+ ASSERT_OK(sql_client_.GetPrimaryKeys(call_options_, table_ref));
+}
+
+TEST_F(TestFlightSqlClient, TestGetCrossReference) {
+ std::string pk_catalog = "pk_catalog";
+ std::string pk_schema = "pk_schema";
+ std::string pk_table = "pk_table";
+ std::string fk_catalog = "fk_catalog";
+ std::string fk_schema = "fk_schema";
+ std::string fk_table = "fk_table";
+
+ pb::sql::CommandGetCrossReference command;
+ command.set_pk_catalog(pk_catalog);
+ command.set_pk_db_schema(pk_schema);
+ command.set_pk_table(pk_table);
+ command.set_fk_catalog(fk_catalog);
+ command.set_fk_db_schema(fk_schema);
+ command.set_fk_table(fk_table);
+ FlightDescriptor descriptor = getDescriptor(command);
+
+ ON_CALL(sql_client_, GetFlightInfo).WillByDefault(ReturnEmptyFlightInfo);
+ EXPECT_CALL(sql_client_, GetFlightInfo(Ref(call_options_), descriptor));
+
+ TableRef pk_table_ref = {util::make_optional(pk_catalog),
+ util::make_optional(pk_schema), pk_table};
+ TableRef fk_table_ref = {util::make_optional(fk_catalog),
+ util::make_optional(fk_schema), fk_table};
+ ASSERT_OK(sql_client_.GetCrossReference(call_options_, pk_table_ref, fk_table_ref));
+}
+
+TEST_F(TestFlightSqlClient, TestExecute) {
+ std::string query = "query";
+
+ pb::sql::CommandStatementQuery command;
+ command.set_query(query);
+ FlightDescriptor descriptor = getDescriptor(command);
+
+ ON_CALL(sql_client_, GetFlightInfo).WillByDefault(ReturnEmptyFlightInfo);
+ EXPECT_CALL(sql_client_, GetFlightInfo(Ref(call_options_), descriptor));
+
+ ASSERT_OK(sql_client_.Execute(call_options_, query));
+}
+
+TEST_F(TestFlightSqlClient, TestPreparedStatementExecute) {
+ const std::string query = "query";
+
+ ON_CALL(sql_client_, DoAction)
+ .WillByDefault([](const FlightCallOptions& options, const Action& action,
+ std::unique_ptr<ResultStream>* results) {
+ google::protobuf::Any command;
+
+ pb::sql::ActionCreatePreparedStatementResult prepared_statement_result;
+
+ prepared_statement_result.set_prepared_statement_handle("query");
+
+ command.PackFrom(prepared_statement_result);
+
+ *results = std::unique_ptr<ResultStream>(new SimpleResultStream(
+ {Result{Buffer::FromString(command.SerializeAsString())}}));
+
+ return Status::OK();
+ });
+
+ EXPECT_CALL(sql_client_, DoAction(_, _, _)).Times(2);
+
+ ASSERT_OK_AND_ASSIGN(auto prepared_statement,
+ sql_client_.Prepare(call_options_, query));
+
+ ON_CALL(sql_client_, GetFlightInfo).WillByDefault(ReturnEmptyFlightInfo);
+ EXPECT_CALL(sql_client_, GetFlightInfo(_, _));
+
+ ASSERT_OK(prepared_statement->Execute());
+}
+
+TEST_F(TestFlightSqlClient, TestPreparedStatementExecuteParameterBinding) {
+ const std::string query = "query";
+
+ ON_CALL(sql_client_, DoAction)
+ .WillByDefault([](const FlightCallOptions& options, const Action& action,
+ std::unique_ptr<ResultStream>* results) {
+ google::protobuf::Any command;
+
+ pb::sql::ActionCreatePreparedStatementResult prepared_statement_result;
+
+ prepared_statement_result.set_prepared_statement_handle("query");
+
+ auto schema = arrow::schema({arrow::field("id", int64())});
+
+ std::shared_ptr<Buffer> schema_buffer;
+ const arrow::Result<std::shared_ptr<Buffer>>& result =
+ arrow::ipc::SerializeSchema(*schema);
+
+ ARROW_ASSIGN_OR_RAISE(schema_buffer, result);
+
+ prepared_statement_result.set_parameter_schema(schema_buffer->ToString());
+
+ command.PackFrom(prepared_statement_result);
+
+ *results = std::unique_ptr<ResultStream>(new SimpleResultStream(
+ {Result{Buffer::FromString(command.SerializeAsString())}}));
+
+ return Status::OK();
+ });
+
+ std::shared_ptr<Buffer> buffer_ptr;
+ ON_CALL(sql_client_, DoPut)
+ .WillByDefault([&buffer_ptr](const FlightCallOptions& options,
+ const FlightDescriptor& descriptor1,
+ const std::shared_ptr<Schema>& schema,
+ std::unique_ptr<FlightStreamWriter>* writer,
+ std::unique_ptr<FlightMetadataReader>* reader) {
+ writer->reset(new FlightStreamWriterMock());
+ reader->reset(new FlightMetadataReaderMock(&buffer_ptr));
+
+ return Status::OK();
+ });
+
+ EXPECT_CALL(sql_client_, DoAction(_, _, _)).Times(2);
+ EXPECT_CALL(sql_client_, DoPut(_, _, _, _, _));
+
+ ASSERT_OK_AND_ASSIGN(auto prepared_statement,
+ sql_client_.Prepare(call_options_, query));
+
+ auto parameter_schema = prepared_statement->parameter_schema();
+
+ auto result = RecordBatchFromJSON(parameter_schema, "[[1]]");
+ ASSERT_OK(prepared_statement->SetParameters(result));
+
+ ON_CALL(sql_client_, GetFlightInfo).WillByDefault(ReturnEmptyFlightInfo);
+ EXPECT_CALL(sql_client_, GetFlightInfo(_, _));
+
+ ASSERT_OK(prepared_statement->Execute());
+}
+
+TEST_F(TestFlightSqlClient, TestExecuteUpdate) {
+ std::string query = "query";
+
+ pb::sql::CommandStatementUpdate command;
+
+ command.set_query(query);
+
+ google::protobuf::Any any;
+ any.PackFrom(command);
+
+ const FlightDescriptor& descriptor = FlightDescriptor::Command(any.SerializeAsString());
+
+ pb::sql::DoPutUpdateResult doPutUpdateResult;
+ doPutUpdateResult.set_record_count(100);
+ const std::string& string = doPutUpdateResult.SerializeAsString();
+
+ auto buffer_ptr = std::make_shared<Buffer>(
+ reinterpret_cast<const uint8_t*>(string.data()), doPutUpdateResult.ByteSizeLong());
+
+ ON_CALL(sql_client_, DoPut)
+ .WillByDefault([&buffer_ptr](const FlightCallOptions& options,
+ const FlightDescriptor& descriptor1,
+ const std::shared_ptr<Schema>& schema,
+ std::unique_ptr<FlightStreamWriter>* writer,
+ std::unique_ptr<FlightMetadataReader>* reader) {
+ reader->reset(new FlightMetadataReaderMock(&buffer_ptr));
+
+ return Status::OK();
+ });
+
+ std::unique_ptr<FlightInfo> flight_info;
+ std::unique_ptr<FlightStreamWriter> writer;
+ std::unique_ptr<FlightMetadataReader> reader;
+ EXPECT_CALL(sql_client_, DoPut(Ref(call_options_), descriptor, _, _, _));
+
+ ASSERT_OK_AND_ASSIGN(auto num_rows, sql_client_.ExecuteUpdate(call_options_, query));
+
+ ASSERT_EQ(num_rows, 100);
+}
+
+TEST_F(TestFlightSqlClient, TestGetSqlInfo) {
+ std::vector<int> sql_info{pb::sql::SqlInfo::FLIGHT_SQL_SERVER_NAME,
+ pb::sql::SqlInfo::FLIGHT_SQL_SERVER_VERSION,
+ pb::sql::SqlInfo::FLIGHT_SQL_SERVER_ARROW_VERSION};
+ pb::sql::CommandGetSqlInfo command;
+
+ for (const auto& info : sql_info) command.add_info(info);
+ google::protobuf::Any any;
+ any.PackFrom(command);
+ const FlightDescriptor& descriptor = FlightDescriptor::Command(any.SerializeAsString());
+
+ ON_CALL(sql_client_, GetFlightInfo).WillByDefault(ReturnEmptyFlightInfo);
+ EXPECT_CALL(sql_client_, GetFlightInfo(Ref(call_options_), descriptor));
+
+ ASSERT_OK(sql_client_.GetSqlInfo(call_options_, sql_info));
+}
+
+template <class Func>
+inline void AssertTestPreparedStatementExecuteUpdateOk(
+ Func func, const std::shared_ptr<Schema>* schema, FlightSqlClientMock& sql_client_) {
+ const std::string query = "SELECT * FROM IRRELEVANT";
+ int64_t expected_rows = 100L;
+ pb::sql::DoPutUpdateResult result;
+ result.set_record_count(expected_rows);
+
+ ON_CALL(sql_client_, DoAction)
+ .WillByDefault([&query, &schema](const FlightCallOptions& options,
+ const Action& action,
+ std::unique_ptr<ResultStream>* results) {
+ google::protobuf::Any command;
+ pb::sql::ActionCreatePreparedStatementResult prepared_statement_result;
+
+ prepared_statement_result.set_prepared_statement_handle(query);
+
+ if (schema != NULLPTR) {
+ std::shared_ptr<Buffer> schema_buffer;
+ const arrow::Result<std::shared_ptr<Buffer>>& result =
+ arrow::ipc::SerializeSchema(**schema);
+
+ ARROW_ASSIGN_OR_RAISE(schema_buffer, result);
+ prepared_statement_result.set_parameter_schema(schema_buffer->ToString());
+ }
+
+ command.PackFrom(prepared_statement_result);
+ *results = std::unique_ptr<ResultStream>(new SimpleResultStream(
+ {Result{Buffer::FromString(command.SerializeAsString())}}));
+
+ return Status::OK();
+ });
+ EXPECT_CALL(sql_client_, DoAction(_, _, _)).Times(2);
+
+ auto buffer = Buffer::FromString(result.SerializeAsString());
+ ON_CALL(sql_client_, DoPut)
+ .WillByDefault([&buffer](const FlightCallOptions& options,
+ const FlightDescriptor& descriptor1,
+ const std::shared_ptr<Schema>& schema,
+ std::unique_ptr<FlightStreamWriter>* writer,
+ std::unique_ptr<FlightMetadataReader>* reader) {
+ reader->reset(new FlightMetadataReaderMock(&buffer));
+ writer->reset(new FlightStreamWriterMock());
+ return Status::OK();
+ });
+ if (schema == NULLPTR) {
+ EXPECT_CALL(sql_client_, DoPut(_, _, _, _, _));
+ } else {
+ EXPECT_CALL(sql_client_, DoPut(_, _, *schema, _, _));
+ }
+
+ ASSERT_OK_AND_ASSIGN(auto prepared_statement, sql_client_.Prepare({}, query));
+ func(prepared_statement, sql_client_, schema, expected_rows);
+ ASSERT_OK_AND_ASSIGN(auto rows, prepared_statement->ExecuteUpdate());
+ ASSERT_EQ(expected_rows, rows);
+ ASSERT_OK(prepared_statement->Close());
+}
+
+TEST_F(TestFlightSqlClient, TestPreparedStatementExecuteUpdateNoParameterBinding) {
+ AssertTestPreparedStatementExecuteUpdateOk(
+ [](const std::shared_ptr<PreparedStatement>& prepared_statement,
+ FlightSqlClient& sql_client_, const std::shared_ptr<Schema>* schema,
+ const int64_t& row_count) {},
+ NULLPTR, sql_client_);
+}
+
+TEST_F(TestFlightSqlClient, TestPreparedStatementExecuteUpdateWithParameterBinding) {
+ const auto schema = arrow::schema(
+ {arrow::field("field0", arrow::utf8()), arrow::field("field1", arrow::uint8())});
+ AssertTestPreparedStatementExecuteUpdateOk(
+ [](const std::shared_ptr<PreparedStatement>& prepared_statement,
+ FlightSqlClient& sql_client_, const std::shared_ptr<Schema>* schema,
+ const int64_t& row_count) {
+ auto string_array =
+ ArrayFromJSON(utf8(), R"(["Lorem", "Ipsum", "Foo", "Bar", "Baz"])");
+ auto uint8_array = ArrayFromJSON(uint8(), R"([0, 10, 15, 20, 25])");
+ std::shared_ptr<RecordBatch> recordBatch =
+ RecordBatch::Make(*schema, row_count, {string_array, uint8_array});
+ ASSERT_OK(prepared_statement->SetParameters(recordBatch));
+ },
+ &schema, sql_client_);
+}
+
+} // namespace sql
+} // namespace flight
+} // namespace arrow
diff --git a/cpp/src/arrow/flight/sql/example/sqlite_server.cc b/cpp/src/arrow/flight/sql/example/sqlite_server.cc
new file mode 100644
index 0000000..dde364f
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/example/sqlite_server.cc
@@ -0,0 +1,813 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "arrow/flight/sql/example/sqlite_server.h"
+
+#include <sqlite3.h>
+
+#include <boost/algorithm/string.hpp>
+#include <map>
+#include <random>
+#include <sstream>
+
+#include "arrow/api.h"
+#include "arrow/flight/sql/example/sqlite_sql_info.h"
+#include "arrow/flight/sql/example/sqlite_statement.h"
+#include "arrow/flight/sql/example/sqlite_statement_batch_reader.h"
+#include "arrow/flight/sql/example/sqlite_tables_schema_batch_reader.h"
+#include "arrow/flight/sql/server.h"
+
+namespace arrow {
+namespace flight {
+namespace sql {
+namespace example {
+
+namespace {
+
+/// \brief Gets a SqliteStatement by given handle
+arrow::Result<std::shared_ptr<SqliteStatement>> GetStatementByHandle(
+ const std::map<std::string, std::shared_ptr<SqliteStatement>>& prepared_statements,
+ const std::string& handle) {
+ auto search = prepared_statements.find(handle);
+ if (search == prepared_statements.end()) {
+ return Status::Invalid("Prepared statement not found");
+ }
+
+ return search->second;
+}
+
+std::string PrepareQueryForGetTables(const GetTables& command) {
+ std::stringstream table_query;
+
+ table_query << "SELECT null as catalog_name, null as schema_name, name as "
+ "table_name, type as table_type FROM sqlite_master where 1=1";
+
+ if (command.catalog.has_value()) {
+ table_query << " and catalog_name='" << command.catalog.value() << "'";
+ }
+
+ if (command.db_schema_filter_pattern.has_value()) {
+ table_query << " and schema_name LIKE '" << command.db_schema_filter_pattern.value()
+ << "'";
+ }
+
+ if (command.table_name_filter_pattern.has_value()) {
+ table_query << " and table_name LIKE '" << command.table_name_filter_pattern.value()
+ << "'";
+ }
+
+ if (!command.table_types.empty()) {
+ table_query << " and table_type IN (";
+ size_t size = command.table_types.size();
+ for (size_t i = 0; i < size; i++) {
+ table_query << "'" << command.table_types[i] << "'";
+ if (size - 1 != i) {
+ table_query << ",";
+ }
+ }
+
+ table_query << ")";
+ }
+
+ table_query << " order by table_name";
+ return table_query.str();
+}
+
+Status SetParametersOnSQLiteStatement(sqlite3_stmt* stmt, FlightMessageReader* reader) {
+ FlightStreamChunk chunk;
+ while (true) {
+ RETURN_NOT_OK(reader->Next(&chunk));
+ std::shared_ptr<RecordBatch>& record_batch = chunk.data;
+ if (record_batch == nullptr) break;
+
+ const int64_t num_rows = record_batch->num_rows();
+ const int& num_columns = record_batch->num_columns();
+
+ for (int i = 0; i < num_rows; ++i) {
+ for (int c = 0; c < num_columns; ++c) {
+ const std::shared_ptr<Array>& column = record_batch->column(c);
+ ARROW_ASSIGN_OR_RAISE(std::shared_ptr<Scalar> scalar, column->GetScalar(i));
+
+ auto& holder = static_cast<DenseUnionScalar&>(*scalar).value;
+
+ switch (holder->type->id()) {
+ case Type::INT64: {
+ int64_t value = static_cast<Int64Scalar&>(*holder).value;
+ sqlite3_bind_int64(stmt, c + 1, value);
+ break;
+ }
+ case Type::FLOAT: {
+ double value = static_cast<FloatScalar&>(*holder).value;
+ sqlite3_bind_double(stmt, c + 1, value);
+ break;
+ }
+ case Type::STRING: {
+ std::shared_ptr<Buffer> buffer = static_cast<StringScalar&>(*holder).value;
+ sqlite3_bind_text(stmt, c + 1, reinterpret_cast<const char*>(buffer->data()),
+ static_cast<int>(buffer->size()), SQLITE_TRANSIENT);
+ break;
+ }
+ case Type::BINARY: {
+ std::shared_ptr<Buffer> buffer = static_cast<BinaryScalar&>(*holder).value;
+ sqlite3_bind_blob(stmt, c + 1, buffer->data(),
+ static_cast<int>(buffer->size()), SQLITE_TRANSIENT);
+ break;
+ }
+ default:
+ return Status::Invalid("Received unsupported data type: ",
+ holder->type->ToString());
+ }
+ }
+ }
+ }
+
+ return Status::OK();
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>> DoGetSQLiteQuery(
+ sqlite3* db, const std::string& query, const std::shared_ptr<Schema>& schema) {
+ std::shared_ptr<SqliteStatement> statement;
+
+ ARROW_ASSIGN_OR_RAISE(statement, SqliteStatement::Create(db, query));
+
+ std::shared_ptr<SqliteStatementBatchReader> reader;
+ ARROW_ASSIGN_OR_RAISE(reader, SqliteStatementBatchReader::Create(statement, schema));
+
+ return std::unique_ptr<FlightDataStream>(new RecordBatchStream(reader));
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoForCommand(
+ const FlightDescriptor& descriptor, const std::shared_ptr<Schema>& schema) {
+ std::vector<FlightEndpoint> endpoints{FlightEndpoint{{descriptor.cmd}, {}}};
+ ARROW_ASSIGN_OR_RAISE(auto result,
+ FlightInfo::Make(*schema, descriptor, endpoints, -1, -1))
+
+ return std::unique_ptr<FlightInfo>(new FlightInfo(result));
+}
+
+std::string PrepareQueryForGetImportedOrExportedKeys(const std::string& filter) {
+ return R"(SELECT * FROM (SELECT NULL AS pk_catalog_name,
+ NULL AS pk_schema_name,
+ p."table" AS pk_table_name,
+ p."to" AS pk_column_name,
+ NULL AS fk_catalog_name,
+ NULL AS fk_schema_name,
+ m.name AS fk_table_name,
+ p."from" AS fk_column_name,
+ p.seq AS key_sequence,
+ NULL AS pk_key_name,
+ NULL AS fk_key_name,
+ CASE
+ WHEN p.on_update = 'CASCADE' THEN 0
+ WHEN p.on_update = 'RESTRICT' THEN 1
+ WHEN p.on_update = 'SET NULL' THEN 2
+ WHEN p.on_update = 'NO ACTION' THEN 3
+ WHEN p.on_update = 'SET DEFAULT' THEN 4
+ END AS update_rule,
+ CASE
+ WHEN p.on_delete = 'CASCADE' THEN 0
+ WHEN p.on_delete = 'RESTRICT' THEN 1
+ WHEN p.on_delete = 'SET NULL' THEN 2
+ WHEN p.on_delete = 'NO ACTION' THEN 3
+ WHEN p.on_delete = 'SET DEFAULT' THEN 4
+ END AS delete_rule
+ FROM sqlite_master m
+ JOIN pragma_foreign_key_list(m.name) p ON m.name != p."table"
+ WHERE m.type = 'table') WHERE )" +
+ filter + R"( ORDER BY
+ pk_catalog_name, pk_schema_name, pk_table_name, pk_key_name, key_sequence)";
+}
+
+} // namespace
+
+std::shared_ptr<DataType> GetArrowType(const char* sqlite_type) {
+ if (sqlite_type == NULLPTR) {
+ // SQLite may not know the column type yet.
+ return null();
+ }
+
+ if (boost::iequals(sqlite_type, "int") || boost::iequals(sqlite_type, "integer")) {
+ return int64();
+ } else if (boost::iequals(sqlite_type, "REAL")) {
+ return float64();
+ } else if (boost::iequals(sqlite_type, "BLOB")) {
+ return binary();
+ } else if (boost::iequals(sqlite_type, "TEXT") ||
+ boost::istarts_with(sqlite_type, "char") ||
+ boost::istarts_with(sqlite_type, "varchar")) {
+ return utf8();
+ } else {
+ throw std::invalid_argument("Invalid SQLite type: " + std::string(sqlite_type));
+ }
+}
+
+class SQLiteFlightSqlServer::Impl {
+ sqlite3* db_;
+ std::map<std::string, std::shared_ptr<SqliteStatement>> prepared_statements_;
+ std::default_random_engine gen_;
+
+ public:
+ explicit Impl(sqlite3* db) : db_(db) {}
+
+ ~Impl() { sqlite3_close(db_); }
+
+ std::string GenerateRandomString() {
+ uint32_t length = 16;
+
+ std::uniform_int_distribution<char> dist('0', 'z');
+ std::string ret(length, 0);
+ auto get_random_char = [&]() { return dist(gen_); };
+ std::generate_n(ret.begin(), length, get_random_char);
+ return ret;
+ }
+
+ arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoStatement(
+ const ServerCallContext& context, const StatementQuery& command,
+ const FlightDescriptor& descriptor) {
+ const std::string& query = command.query;
+
+ ARROW_ASSIGN_OR_RAISE(auto statement, SqliteStatement::Create(db_, query));
+
+ ARROW_ASSIGN_OR_RAISE(auto schema, statement->GetSchema());
+
+ ARROW_ASSIGN_OR_RAISE(auto ticket_string, CreateStatementQueryTicket(query));
+ std::vector<FlightEndpoint> endpoints{FlightEndpoint{{ticket_string}, {}}};
+ ARROW_ASSIGN_OR_RAISE(auto result,
+ FlightInfo::Make(*schema, descriptor, endpoints, -1, -1))
+
+ return std::unique_ptr<FlightInfo>(new FlightInfo(result));
+ }
+
+ arrow::Result<std::unique_ptr<FlightDataStream>> DoGetStatement(
+ const ServerCallContext& context, const StatementQueryTicket& command) {
+ const std::string& sql = command.statement_handle;
+
+ std::shared_ptr<SqliteStatement> statement;
+ ARROW_ASSIGN_OR_RAISE(statement, SqliteStatement::Create(db_, sql));
+
+ std::shared_ptr<SqliteStatementBatchReader> reader;
+ ARROW_ASSIGN_OR_RAISE(reader, SqliteStatementBatchReader::Create(statement));
+
+ return std::unique_ptr<FlightDataStream>(new RecordBatchStream(reader));
+ }
+
+ arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoCatalogs(
+ const ServerCallContext& context, const FlightDescriptor& descriptor) {
+ return GetFlightInfoForCommand(descriptor, SqlSchema::GetCatalogsSchema());
+ }
+
+ arrow::Result<std::unique_ptr<FlightDataStream>> DoGetCatalogs(
+ const ServerCallContext& context) {
+ // As SQLite doesn't support catalogs, this will return an empty record batch.
+
+ const std::shared_ptr<Schema>& schema = SqlSchema::GetCatalogsSchema();
+
+ StringBuilder catalog_name_builder;
+ ARROW_ASSIGN_OR_RAISE(auto catalog_name, catalog_name_builder.Finish());
+
+ const std::shared_ptr<RecordBatch>& batch =
+ RecordBatch::Make(schema, 0, {catalog_name});
+
+ ARROW_ASSIGN_OR_RAISE(auto reader, RecordBatchReader::Make({batch}));
+
+ return std::unique_ptr<FlightDataStream>(new RecordBatchStream(reader));
+ }
+
+ arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoSchemas(
+ const ServerCallContext& context, const GetDbSchemas& command,
+ const FlightDescriptor& descriptor) {
+ return GetFlightInfoForCommand(descriptor, SqlSchema::GetDbSchemasSchema());
+ }
+
+ arrow::Result<std::unique_ptr<FlightDataStream>> DoGetDbSchemas(
+ const ServerCallContext& context, const GetDbSchemas& command) {
+ // As SQLite doesn't support schemas, this will return an empty record batch.
+
+ const std::shared_ptr<Schema>& schema = SqlSchema::GetDbSchemasSchema();
+
+ StringBuilder catalog_name_builder;
+ ARROW_ASSIGN_OR_RAISE(auto catalog_name, catalog_name_builder.Finish());
+ StringBuilder schema_name_builder;
+ ARROW_ASSIGN_OR_RAISE(auto schema_name, schema_name_builder.Finish());
+
+ const std::shared_ptr<RecordBatch>& batch =
+ RecordBatch::Make(schema, 0, {catalog_name, schema_name});
+
+ ARROW_ASSIGN_OR_RAISE(auto reader, RecordBatchReader::Make({batch}));
+
+ return std::unique_ptr<FlightDataStream>(new RecordBatchStream(reader));
+ }
+
+ arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoTables(
+ const ServerCallContext& context, const GetTables& command,
+ const FlightDescriptor& descriptor) {
+ std::vector<FlightEndpoint> endpoints{FlightEndpoint{{descriptor.cmd}, {}}};
+
+ bool include_schema = command.include_schema;
+
+ ARROW_ASSIGN_OR_RAISE(
+ auto result,
+ FlightInfo::Make(include_schema ? *SqlSchema::GetTablesSchemaWithIncludedSchema()
+ : *SqlSchema::GetTablesSchema(),
+ descriptor, endpoints, -1, -1))
+
+ return std::unique_ptr<FlightInfo>(new FlightInfo(result));
+ }
+
+ arrow::Result<std::unique_ptr<FlightDataStream>> DoGetTables(
+ const ServerCallContext& context, const GetTables& command) {
+ std::string query = PrepareQueryForGetTables(command);
+
+ std::shared_ptr<SqliteStatement> statement;
+ ARROW_ASSIGN_OR_RAISE(statement, SqliteStatement::Create(db_, query));
+
+ std::shared_ptr<SqliteStatementBatchReader> reader;
+ ARROW_ASSIGN_OR_RAISE(reader, SqliteStatementBatchReader::Create(
+ statement, SqlSchema::GetTablesSchema()));
+
+ if (command.include_schema) {
+ std::shared_ptr<SqliteTablesWithSchemaBatchReader> table_schema_reader =
+ std::make_shared<SqliteTablesWithSchemaBatchReader>(reader, query, db_);
+ return std::unique_ptr<FlightDataStream>(
+ new RecordBatchStream(table_schema_reader));
+ } else {
+ return std::unique_ptr<FlightDataStream>(new RecordBatchStream(reader));
+ }
+ }
+
+ arrow::Result<int64_t> DoPutCommandStatementUpdate(const ServerCallContext& context,
+ const StatementUpdate& command) {
+ const std::string& sql = command.query;
+
+ ARROW_ASSIGN_OR_RAISE(auto statement, SqliteStatement::Create(db_, sql));
+
+ return statement->ExecuteUpdate();
+ }
+
+ arrow::Result<ActionCreatePreparedStatementResult> CreatePreparedStatement(
+ const ServerCallContext& context,
+ const ActionCreatePreparedStatementRequest& request) {
+ std::shared_ptr<SqliteStatement> statement;
+ ARROW_ASSIGN_OR_RAISE(statement, SqliteStatement::Create(db_, request.query));
+ const std::string handle = GenerateRandomString();
+ prepared_statements_[handle] = statement;
+
+ ARROW_ASSIGN_OR_RAISE(auto dataset_schema, statement->GetSchema());
+
+ sqlite3_stmt* stmt = statement->GetSqlite3Stmt();
+ const int parameter_count = sqlite3_bind_parameter_count(stmt);
+ std::vector<std::shared_ptr<arrow::Field>> parameter_fields;
+ parameter_fields.reserve(parameter_count);
+
+ // As SQLite doesn't know the parameter types before executing the query, the
+ // example server is accepting any SQLite supported type as input by using a dense
+ // union.
+ const std::shared_ptr<DataType>& dense_union_type = GetUnknownColumnDataType();
+
+ for (int i = 0; i < parameter_count; i++) {
+ const char* parameter_name_chars = sqlite3_bind_parameter_name(stmt, i + 1);
+ std::string parameter_name;
+ if (parameter_name_chars == NULLPTR) {
+ parameter_name = std::string("parameter_") + std::to_string(i + 1);
+ } else {
+ parameter_name = parameter_name_chars;
+ }
+ parameter_fields.push_back(field(parameter_name, dense_union_type));
+ }
+
+ const std::shared_ptr<Schema>& parameter_schema = arrow::schema(parameter_fields);
+
+ ActionCreatePreparedStatementResult result{.dataset_schema = dataset_schema,
+ .parameter_schema = parameter_schema,
+ .prepared_statement_handle = handle};
+
+ return result;
+ }
+
+ Status ClosePreparedStatement(const ServerCallContext& context,
+ const ActionClosePreparedStatementRequest& request) {
+ const std::string& prepared_statement_handle = request.prepared_statement_handle;
+
+ auto search = prepared_statements_.find(prepared_statement_handle);
+ if (search != prepared_statements_.end()) {
+ prepared_statements_.erase(prepared_statement_handle);
+ } else {
+ return Status::Invalid("Prepared statement not found");
+ }
+
+ return Status::OK();
+ }
+
+ arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoPreparedStatement(
+ const ServerCallContext& context, const PreparedStatementQuery& command,
+ const FlightDescriptor& descriptor) {
+ const std::string& prepared_statement_handle = command.prepared_statement_handle;
+
+ auto search = prepared_statements_.find(prepared_statement_handle);
+ if (search == prepared_statements_.end()) {
+ return Status::Invalid("Prepared statement not found");
+ }
+
+ std::shared_ptr<SqliteStatement> statement = search->second;
+
+ ARROW_ASSIGN_OR_RAISE(auto schema, statement->GetSchema());
+
+ return GetFlightInfoForCommand(descriptor, schema);
+ }
+
+ arrow::Result<std::unique_ptr<FlightDataStream>> DoGetPreparedStatement(
+ const ServerCallContext& context, const PreparedStatementQuery& command) {
+ const std::string& prepared_statement_handle = command.prepared_statement_handle;
+
+ auto search = prepared_statements_.find(prepared_statement_handle);
+ if (search == prepared_statements_.end()) {
+ return Status::Invalid("Prepared statement not found");
+ }
+
+ std::shared_ptr<SqliteStatement> statement = search->second;
+
+ std::shared_ptr<SqliteStatementBatchReader> reader;
+ ARROW_ASSIGN_OR_RAISE(reader, SqliteStatementBatchReader::Create(statement));
+
+ return std::unique_ptr<FlightDataStream>(new RecordBatchStream(reader));
+ }
+
+ Status DoPutPreparedStatementQuery(const ServerCallContext& context,
+ const PreparedStatementQuery& command,
+ FlightMessageReader* reader,
+ FlightMetadataWriter* writer) {
+ const std::string& prepared_statement_handle = command.prepared_statement_handle;
+ ARROW_ASSIGN_OR_RAISE(
+ auto statement,
+ GetStatementByHandle(prepared_statements_, prepared_statement_handle));
+
+ sqlite3_stmt* stmt = statement->GetSqlite3Stmt();
+ ARROW_RETURN_NOT_OK(SetParametersOnSQLiteStatement(stmt, reader));
+
+ return Status::OK();
+ }
+
+ arrow::Result<int64_t> DoPutPreparedStatementUpdate(
+ const ServerCallContext& context, const PreparedStatementUpdate& command,
+ FlightMessageReader* reader) {
+ const std::string& prepared_statement_handle = command.prepared_statement_handle;
+ ARROW_ASSIGN_OR_RAISE(
+ auto statement,
+ GetStatementByHandle(prepared_statements_, prepared_statement_handle));
+
+ sqlite3_stmt* stmt = statement->GetSqlite3Stmt();
+ ARROW_RETURN_NOT_OK(SetParametersOnSQLiteStatement(stmt, reader));
+
+ return statement->ExecuteUpdate();
+ }
+
+ arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoTableTypes(
+ const ServerCallContext& context, const FlightDescriptor& descriptor) {
+ return GetFlightInfoForCommand(descriptor, SqlSchema::GetTableTypesSchema());
+ }
+
+ arrow::Result<std::unique_ptr<FlightDataStream>> DoGetTableTypes(
+ const ServerCallContext& context) {
+ std::string query = "SELECT DISTINCT type as table_type FROM sqlite_master";
+
+ return DoGetSQLiteQuery(db_, query, SqlSchema::GetTableTypesSchema());
+ }
+
+ arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoPrimaryKeys(
+ const ServerCallContext& context, const GetPrimaryKeys& command,
+ const FlightDescriptor& descriptor) {
+ return GetFlightInfoForCommand(descriptor, SqlSchema::GetPrimaryKeysSchema());
+ }
+
+ arrow::Result<std::unique_ptr<FlightDataStream>> DoGetPrimaryKeys(
+ const ServerCallContext& context, const GetPrimaryKeys& command) {
+ std::stringstream table_query;
+
+ // The field key_name can not be recovered by the sqlite, so it is being set
+ // to null following the same pattern for catalog_name and schema_name.
+ table_query << "SELECT null as catalog_name, null as schema_name, table_name, "
+ "name as column_name, pk as key_sequence, null as key_name\n"
+ "FROM pragma_table_info(table_name)\n"
+ " JOIN (SELECT null as catalog_name, null as schema_name, name as "
+ "table_name, type as table_type\n"
+ "FROM sqlite_master) where 1=1 and pk != 0";
+
+ const TableRef& table_ref = command.table_ref;
+ if (table_ref.catalog.has_value()) {
+ table_query << " and catalog_name LIKE '" << table_ref.catalog.value() << "'";
+ }
+
+ if (table_ref.db_schema.has_value()) {
+ table_query << " and schema_name LIKE '" << table_ref.db_schema.value() << "'";
+ }
+
+ table_query << " and table_name LIKE '" << table_ref.table << "'";
+
+ return DoGetSQLiteQuery(db_, table_query.str(), SqlSchema::GetPrimaryKeysSchema());
+ }
+
+ arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoImportedKeys(
+ const ServerCallContext& context, const GetImportedKeys& command,
+ const FlightDescriptor& descriptor) {
+ return GetFlightInfoForCommand(descriptor, SqlSchema::GetImportedKeysSchema());
+ }
+
+ arrow::Result<std::unique_ptr<FlightDataStream>> DoGetImportedKeys(
+ const ServerCallContext& context, const GetImportedKeys& command) {
+ const TableRef& table_ref = command.table_ref;
+ std::string filter = "fk_table_name = '" + table_ref.table + "'";
+ if (table_ref.catalog.has_value()) {
+ filter += " AND fk_catalog_name = '" + table_ref.catalog.value() + "'";
+ }
+ if (table_ref.db_schema.has_value()) {
+ filter += " AND fk_schema_name = '" + table_ref.db_schema.value() + "'";
+ }
+ std::string query = PrepareQueryForGetImportedOrExportedKeys(filter);
+
+ return DoGetSQLiteQuery(db_, query, SqlSchema::GetImportedKeysSchema());
+ }
+
+ arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoExportedKeys(
+ const ServerCallContext& context, const GetExportedKeys& command,
+ const FlightDescriptor& descriptor) {
+ return GetFlightInfoForCommand(descriptor, SqlSchema::GetExportedKeysSchema());
+ }
+
+ arrow::Result<std::unique_ptr<FlightDataStream>> DoGetExportedKeys(
+ const ServerCallContext& context, const GetExportedKeys& command) {
+ const TableRef& table_ref = command.table_ref;
+ std::string filter = "pk_table_name = '" + table_ref.table + "'";
+ if (table_ref.catalog.has_value()) {
+ filter += " AND pk_catalog_name = '" + table_ref.catalog.value() + "'";
+ }
+ if (table_ref.db_schema.has_value()) {
+ filter += " AND pk_schema_name = '" + table_ref.db_schema.value() + "'";
+ }
+ std::string query = PrepareQueryForGetImportedOrExportedKeys(filter);
+
+ return DoGetSQLiteQuery(db_, query, SqlSchema::GetExportedKeysSchema());
+ }
+
+ arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoCrossReference(
+ const ServerCallContext& context, const GetCrossReference& command,
+ const FlightDescriptor& descriptor) {
+ return GetFlightInfoForCommand(descriptor, SqlSchema::GetCrossReferenceSchema());
+ }
+
+ arrow::Result<std::unique_ptr<FlightDataStream>> DoGetCrossReference(
+ const ServerCallContext& context, const GetCrossReference& command) {
+ const TableRef& pk_table_ref = command.pk_table_ref;
+ std::string filter = "pk_table_name = '" + pk_table_ref.table + "'";
+ if (pk_table_ref.catalog.has_value()) {
+ filter += " AND pk_catalog_name = '" + pk_table_ref.catalog.value() + "'";
+ }
+ if (pk_table_ref.db_schema.has_value()) {
+ filter += " AND pk_schema_name = '" + pk_table_ref.db_schema.value() + "'";
+ }
+
+ const TableRef& fk_table_ref = command.fk_table_ref;
+ filter += " AND fk_table_name = '" + fk_table_ref.table + "'";
+ if (fk_table_ref.catalog.has_value()) {
+ filter += " AND fk_catalog_name = '" + fk_table_ref.catalog.value() + "'";
+ }
+ if (fk_table_ref.db_schema.has_value()) {
+ filter += " AND fk_schema_name = '" + fk_table_ref.db_schema.value() + "'";
+ }
+ std::string query = PrepareQueryForGetImportedOrExportedKeys(filter);
+
+ return DoGetSQLiteQuery(db_, query, SqlSchema::GetCrossReferenceSchema());
+ }
+
+ Status ExecuteSql(const std::string& sql) {
+ char* err_msg = nullptr;
+ int rc = sqlite3_exec(db_, sql.c_str(), nullptr, nullptr, &err_msg);
+ if (rc != SQLITE_OK) {
+ std::string error_msg;
+ if (err_msg != nullptr) {
+ error_msg = err_msg;
+ }
+ sqlite3_free(err_msg);
+ return Status::ExecutionError(error_msg);
+ }
+ return Status::OK();
+ }
+};
+
+SQLiteFlightSqlServer::SQLiteFlightSqlServer(std::shared_ptr<Impl> impl)
+ : impl_(std::move(impl)) {}
+
+arrow::Result<std::shared_ptr<SQLiteFlightSqlServer>> SQLiteFlightSqlServer::Create() {
+ sqlite3* db = nullptr;
+
+ if (sqlite3_open(":memory:", &db)) {
+ std::string err_msg = "Can't open database: ";
+ if (db != nullptr) {
+ err_msg += sqlite3_errmsg(db);
+ sqlite3_close(db);
+ } else {
+ err_msg += "Unable to start SQLite. Insufficient memory";
+ }
+
+ return Status::Invalid(err_msg);
+ }
+
+ std::shared_ptr<Impl> impl = std::make_shared<Impl>(db);
+
+ std::shared_ptr<SQLiteFlightSqlServer> result(new SQLiteFlightSqlServer(impl));
+ for (const auto& id_to_result : GetSqlInfoResultMap()) {
+ result->RegisterSqlInfo(id_to_result.first, id_to_result.second);
+ }
+
+ ARROW_RETURN_NOT_OK(result->ExecuteSql(R"(
+ CREATE TABLE foreignTable (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ foreignName varchar(100),
+ value int);
+
+ CREATE TABLE intTable (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ keyName varchar(100),
+ value int,
+ foreignId int references foreignTable(id));
+
+ INSERT INTO foreignTable (foreignName, value) VALUES ('keyOne', 1);
+ INSERT INTO foreignTable (foreignName, value) VALUES ('keyTwo', 0);
+ INSERT INTO foreignTable (foreignName, value) VALUES ('keyThree', -1);
+ INSERT INTO intTable (keyName, value, foreignId) VALUES ('one', 1, 1);
+ INSERT INTO intTable (keyName, value, foreignId) VALUES ('zero', 0, 1);
+ INSERT INTO intTable (keyName, value, foreignId) VALUES ('negative one', -1, 1);
+ INSERT INTO intTable (keyName, value, foreignId) VALUES (NULL, NULL, NULL);
+ )"));
+
+ return result;
+}
+
+SQLiteFlightSqlServer::~SQLiteFlightSqlServer() = default;
+
+Status SQLiteFlightSqlServer::ExecuteSql(const std::string& sql) {
+ return impl_->ExecuteSql(sql);
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> SQLiteFlightSqlServer::GetFlightInfoStatement(
+ const ServerCallContext& context, const StatementQuery& command,
+ const FlightDescriptor& descriptor) {
+ return impl_->GetFlightInfoStatement(context, command, descriptor);
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>> SQLiteFlightSqlServer::DoGetStatement(
+ const ServerCallContext& context, const StatementQueryTicket& command) {
+ return impl_->DoGetStatement(context, command);
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> SQLiteFlightSqlServer::GetFlightInfoCatalogs(
+ const ServerCallContext& context, const FlightDescriptor& descriptor) {
+ return impl_->GetFlightInfoCatalogs(context, descriptor);
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>> SQLiteFlightSqlServer::DoGetCatalogs(
+ const ServerCallContext& context) {
+ return impl_->DoGetCatalogs(context);
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> SQLiteFlightSqlServer::GetFlightInfoSchemas(
+ const ServerCallContext& context, const GetDbSchemas& command,
+ const FlightDescriptor& descriptor) {
+ return impl_->GetFlightInfoSchemas(context, command, descriptor);
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>> SQLiteFlightSqlServer::DoGetDbSchemas(
+ const ServerCallContext& context, const GetDbSchemas& command) {
+ return impl_->DoGetDbSchemas(context, command);
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> SQLiteFlightSqlServer::GetFlightInfoTables(
+ const ServerCallContext& context, const GetTables& command,
+ const FlightDescriptor& descriptor) {
+ return impl_->GetFlightInfoTables(context, command, descriptor);
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>> SQLiteFlightSqlServer::DoGetTables(
+ const ServerCallContext& context, const GetTables& command) {
+ return impl_->DoGetTables(context, command);
+}
+
+arrow::Result<int64_t> SQLiteFlightSqlServer::DoPutCommandStatementUpdate(
+ const ServerCallContext& context, const StatementUpdate& command) {
+ return impl_->DoPutCommandStatementUpdate(context, command);
+}
+
+arrow::Result<ActionCreatePreparedStatementResult>
+SQLiteFlightSqlServer::CreatePreparedStatement(
+ const ServerCallContext& context,
+ const ActionCreatePreparedStatementRequest& request) {
+ return impl_->CreatePreparedStatement(context, request);
+}
+
+Status SQLiteFlightSqlServer::ClosePreparedStatement(
+ const ServerCallContext& context,
+ const ActionClosePreparedStatementRequest& request) {
+ return impl_->ClosePreparedStatement(context, request);
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>>
+SQLiteFlightSqlServer::GetFlightInfoPreparedStatement(
+ const ServerCallContext& context, const PreparedStatementQuery& command,
+ const FlightDescriptor& descriptor) {
+ return impl_->GetFlightInfoPreparedStatement(context, command, descriptor);
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>>
+SQLiteFlightSqlServer::DoGetPreparedStatement(const ServerCallContext& context,
+ const PreparedStatementQuery& command) {
+ return impl_->DoGetPreparedStatement(context, command);
+}
+
+Status SQLiteFlightSqlServer::DoPutPreparedStatementQuery(
+ const ServerCallContext& context, const PreparedStatementQuery& command,
+ FlightMessageReader* reader, FlightMetadataWriter* writer) {
+ return impl_->DoPutPreparedStatementQuery(context, command, reader, writer);
+}
+
+arrow::Result<int64_t> SQLiteFlightSqlServer::DoPutPreparedStatementUpdate(
+ const ServerCallContext& context, const PreparedStatementUpdate& command,
+ FlightMessageReader* reader) {
+ return impl_->DoPutPreparedStatementUpdate(context, command, reader);
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> SQLiteFlightSqlServer::GetFlightInfoTableTypes(
+ const ServerCallContext& context, const FlightDescriptor& descriptor) {
+ return impl_->GetFlightInfoTableTypes(context, descriptor);
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>> SQLiteFlightSqlServer::DoGetTableTypes(
+ const ServerCallContext& context) {
+ return impl_->DoGetTableTypes(context);
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>>
+SQLiteFlightSqlServer::GetFlightInfoPrimaryKeys(const ServerCallContext& context,
+ const GetPrimaryKeys& command,
+ const FlightDescriptor& descriptor) {
+ return impl_->GetFlightInfoPrimaryKeys(context, command, descriptor);
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>> SQLiteFlightSqlServer::DoGetPrimaryKeys(
+ const ServerCallContext& context, const GetPrimaryKeys& command) {
+ return impl_->DoGetPrimaryKeys(context, command);
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>>
+SQLiteFlightSqlServer::GetFlightInfoImportedKeys(const ServerCallContext& context,
+ const GetImportedKeys& command,
+ const FlightDescriptor& descriptor) {
+ return impl_->GetFlightInfoImportedKeys(context, command, descriptor);
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>> SQLiteFlightSqlServer::DoGetImportedKeys(
+ const ServerCallContext& context, const GetImportedKeys& command) {
+ return impl_->DoGetImportedKeys(context, command);
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>>
+SQLiteFlightSqlServer::GetFlightInfoExportedKeys(const ServerCallContext& context,
+ const GetExportedKeys& command,
+ const FlightDescriptor& descriptor) {
+ return impl_->GetFlightInfoExportedKeys(context, command, descriptor);
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>> SQLiteFlightSqlServer::DoGetExportedKeys(
+ const ServerCallContext& context, const GetExportedKeys& command) {
+ return impl_->DoGetExportedKeys(context, command);
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>>
+SQLiteFlightSqlServer::GetFlightInfoCrossReference(const ServerCallContext& context,
+ const GetCrossReference& command,
+ const FlightDescriptor& descriptor) {
+ return impl_->GetFlightInfoCrossReference(context, command, descriptor);
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>>
+SQLiteFlightSqlServer::DoGetCrossReference(const ServerCallContext& context,
+ const GetCrossReference& command) {
+ return impl_->DoGetCrossReference(context, command);
+}
+
+} // namespace example
+} // namespace sql
+} // namespace flight
+} // namespace arrow
diff --git a/cpp/src/arrow/flight/sql/example/sqlite_server.h b/cpp/src/arrow/flight/sql/example/sqlite_server.h
new file mode 100644
index 0000000..b2954b8
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/example/sqlite_server.h
@@ -0,0 +1,142 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <sqlite3.h>
+
+#include <memory>
+#include <string>
+
+#include "arrow/api.h"
+#include "arrow/flight/sql/example/sqlite_statement.h"
+#include "arrow/flight/sql/example/sqlite_statement_batch_reader.h"
+#include "arrow/flight/sql/server.h"
+
+namespace arrow {
+namespace flight {
+namespace sql {
+namespace example {
+
+/// \brief Convert a column type to a ArrowType.
+/// \param sqlite_type the sqlite type.
+/// \return The equivalent ArrowType.
+std::shared_ptr<DataType> GetArrowType(const char* sqlite_type);
+
+/// \brief Get the DataType used when parameter type is not known.
+/// \return DataType used when parameter type is not known.
+inline std::shared_ptr<DataType> GetUnknownColumnDataType() {
+ return dense_union({
+ field("string", utf8()),
+ field("bytes", binary()),
+ field("bigint", int64()),
+ field("double", float64()),
+ });
+}
+
+/// \brief Example implementation of FlightSqlServerBase backed by an in-memory SQLite3
+/// database.
+class SQLiteFlightSqlServer : public FlightSqlServerBase {
+ public:
+ ~SQLiteFlightSqlServer() override;
+
+ static arrow::Result<std::shared_ptr<SQLiteFlightSqlServer>> Create();
+
+ /// \brief Auxiliary method used to execute an arbitrary SQL statement on the underlying
+ /// SQLite database.
+ Status ExecuteSql(const std::string& sql);
+
+ arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoStatement(
+ const ServerCallContext& context, const StatementQuery& command,
+ const FlightDescriptor& descriptor) override;
+
+ arrow::Result<std::unique_ptr<FlightDataStream>> DoGetStatement(
+ const ServerCallContext& context, const StatementQueryTicket& command) override;
+ arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoCatalogs(
+ const ServerCallContext& context, const FlightDescriptor& descriptor) override;
+ arrow::Result<std::unique_ptr<FlightDataStream>> DoGetCatalogs(
+ const ServerCallContext& context) override;
+ arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoSchemas(
+ const ServerCallContext& context, const GetDbSchemas& command,
+ const FlightDescriptor& descriptor) override;
+ arrow::Result<std::unique_ptr<FlightDataStream>> DoGetDbSchemas(
+ const ServerCallContext& context, const GetDbSchemas& command) override;
+ arrow::Result<int64_t> DoPutCommandStatementUpdate(
+ const ServerCallContext& context, const StatementUpdate& update) override;
+ arrow::Result<ActionCreatePreparedStatementResult> CreatePreparedStatement(
+ const ServerCallContext& context,
+ const ActionCreatePreparedStatementRequest& request) override;
+ Status ClosePreparedStatement(
+ const ServerCallContext& context,
+ const ActionClosePreparedStatementRequest& request) override;
+ arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoPreparedStatement(
+ const ServerCallContext& context, const PreparedStatementQuery& command,
+ const FlightDescriptor& descriptor) override;
+ arrow::Result<std::unique_ptr<FlightDataStream>> DoGetPreparedStatement(
+ const ServerCallContext& context, const PreparedStatementQuery& command) override;
+ Status DoPutPreparedStatementQuery(const ServerCallContext& context,
+ const PreparedStatementQuery& command,
+ FlightMessageReader* reader,
+ FlightMetadataWriter* writer) override;
+ arrow::Result<int64_t> DoPutPreparedStatementUpdate(
+ const ServerCallContext& context, const PreparedStatementUpdate& command,
+ FlightMessageReader* reader) override;
+
+ arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoTables(
+ const ServerCallContext& context, const GetTables& command,
+ const FlightDescriptor& descriptor) override;
+
+ arrow::Result<std::unique_ptr<FlightDataStream>> DoGetTables(
+ const ServerCallContext& context, const GetTables& command) override;
+ arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoTableTypes(
+ const ServerCallContext& context, const FlightDescriptor& descriptor) override;
+ arrow::Result<std::unique_ptr<FlightDataStream>> DoGetTableTypes(
+ const ServerCallContext& context) override;
+ arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoImportedKeys(
+ const ServerCallContext& context, const GetImportedKeys& command,
+ const FlightDescriptor& descriptor) override;
+ arrow::Result<std::unique_ptr<FlightDataStream>> DoGetImportedKeys(
+ const ServerCallContext& context, const GetImportedKeys& command) override;
+ arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoExportedKeys(
+ const ServerCallContext& context, const GetExportedKeys& command,
+ const FlightDescriptor& descriptor) override;
+ arrow::Result<std::unique_ptr<FlightDataStream>> DoGetExportedKeys(
+ const ServerCallContext& context, const GetExportedKeys& command) override;
+ arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoCrossReference(
+ const ServerCallContext& context, const GetCrossReference& command,
+ const FlightDescriptor& descriptor) override;
+ arrow::Result<std::unique_ptr<FlightDataStream>> DoGetCrossReference(
+ const ServerCallContext& context, const GetCrossReference& command) override;
+
+ arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoPrimaryKeys(
+ const ServerCallContext& context, const GetPrimaryKeys& command,
+ const FlightDescriptor& descriptor) override;
+
+ arrow::Result<std::unique_ptr<FlightDataStream>> DoGetPrimaryKeys(
+ const ServerCallContext& context, const GetPrimaryKeys& command) override;
+
+ private:
+ class Impl;
+ std::shared_ptr<Impl> impl_;
+
+ explicit SQLiteFlightSqlServer(std::shared_ptr<Impl> impl);
+};
+
+} // namespace example
+} // namespace sql
+} // namespace flight
+} // namespace arrow
diff --git a/cpp/src/arrow/flight/sql/example/sqlite_sql_info.cc b/cpp/src/arrow/flight/sql/example/sqlite_sql_info.cc
new file mode 100644
index 0000000..94f25b3
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/example/sqlite_sql_info.cc
@@ -0,0 +1,223 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "arrow/flight/sql/example/sqlite_sql_info.h"
+
+#include "arrow/flight/sql/types.h"
+
+namespace arrow {
+namespace flight {
+namespace sql {
+namespace example {
+
+/// \brief Gets the mapping from SQL info ids to SqlInfoResult instances.
+/// \return the cache.
+SqlInfoResultMap GetSqlInfoResultMap() {
+ return {
+ {SqlInfoOptions::SqlInfo::FLIGHT_SQL_SERVER_NAME,
+ SqlInfoResult(std::string("db_name"))},
+ {SqlInfoOptions::SqlInfo::FLIGHT_SQL_SERVER_VERSION,
+ SqlInfoResult(std::string("sqlite 3"))},
+ {SqlInfoOptions::SqlInfo::FLIGHT_SQL_SERVER_ARROW_VERSION,
+ SqlInfoResult(std::string("7.0.0-SNAPSHOT" /* Only an example */))},
+ {SqlInfoOptions::SqlInfo::FLIGHT_SQL_SERVER_READ_ONLY, SqlInfoResult(false)},
+ {SqlInfoOptions::SqlInfo::SQL_DDL_CATALOG,
+ SqlInfoResult(false /* SQLite 3 does not support catalogs */)},
+ {SqlInfoOptions::SqlInfo::SQL_DDL_SCHEMA,
+ SqlInfoResult(false /* SQLite 3 does not support schemas */)},
+ {SqlInfoOptions::SqlInfo::SQL_DDL_TABLE, SqlInfoResult(true)},
+ {SqlInfoOptions::SqlInfo::SQL_IDENTIFIER_CASE,
+ SqlInfoResult(int64_t(SqlInfoOptions::SqlSupportedCaseSensitivity::
+ SQL_CASE_SENSITIVITY_CASE_INSENSITIVE))},
+ {SqlInfoOptions::SqlInfo::SQL_IDENTIFIER_QUOTE_CHAR,
+ SqlInfoResult(std::string("\""))},
+ {SqlInfoOptions::SqlInfo::SQL_QUOTED_IDENTIFIER_CASE,
+ SqlInfoResult(int64_t(SqlInfoOptions::SqlSupportedCaseSensitivity::
+ SQL_CASE_SENSITIVITY_CASE_INSENSITIVE))},
+ {SqlInfoOptions::SqlInfo::SQL_ALL_TABLES_ARE_SELECTABLE, SqlInfoResult(true)},
+ {SqlInfoOptions::SqlInfo::SQL_NULL_ORDERING,
+ SqlInfoResult(
+ int64_t(SqlInfoOptions::SqlNullOrdering::SQL_NULLS_SORTED_AT_START))},
+ {SqlInfoOptions::SqlInfo::SQL_KEYWORDS,
+ SqlInfoResult(std::vector<std::string>({"ABORT",
+ "ACTION",
+ "ADD",
+ "AFTER",
+ "ALL",
+ "ALTER",
+ "ALWAYS",
+ "ANALYZE",
+ "AND",
+ "AS",
+ "ASC",
+ "ATTACH",
+ "AUTOINCREMENT",
+ "BEFORE",
+ "BEGIN",
+ "BETWEEN",
+ "BY",
+ "CASCADE",
+ "CASE",
+ "CAST",
+ "CHECK",
+ "COLLATE",
+ "COLUMN",
+ "COMMIT",
+ "CONFLICT",
+ "CONSTRAINT",
+ "CREATE",
+ "CROSS",
+ "CURRENT",
+ "CURRENT_DATE",
+ "CURRENT_TIME",
+ "CURRENT_TIMESTAMP",
+ "DATABASE",
+ "DEFAULT",
+ "DEFERRABLE",
+ "DEFERRED",
+ "DELETE",
+ "DESC",
+ "DETACH",
+ "DISTINCT",
+ "DO",
+ "DROP",
+ "EACH",
+ "ELSE",
+ "END",
+ "ESCAPE",
+ "EXCEPT",
+ "EXCLUDE",
+ "EXCLUSIVE",
+ "EXISTS",
+ "EXPLAIN",
+ "FAIL",
+ "FILTER",
+ "FIRST",
+ "FOLLOWING",
+ "FOR",
+ "FOREIGN",
+ "FROM",
+ "FULL",
+ "GENERATED",
+ "GLOB",
+ "GROUP",
+ "GROUPS",
+ "HAVING",
+ "IF",
+ "IGNORE",
+ "IMMEDIATE",
+ "IN",
+ "INDEX",
+ "INDEXED",
+ "INITIALLY",
+ "INNER",
+ "INSERT",
+ "INSTEAD",
+ "INTERSECT",
+ "INTO",
+ "IS",
+ "ISNULL",
+ "JOIN",
+ "KEY",
+ "LAST",
+ "LEFT",
+ "LIKE",
+ "LIMIT",
+ "MATCH",
+ "MATERIALIZED",
+ "NATURAL",
+ "NO",
+ "NOT",
+ "NOTHING",
+ "NOTNULL",
+ "NULL",
+ "NULLS",
+ "OF",
+ "OFFSET",
+ "ON",
+ "OR",
+ "ORDER",
+ "OTHERS",
+ "OUTER",
+ "OVER",
+ "PARTITION",
+ "PLAN",
+ "PRAGMA",
+ "PRECEDING",
+ "PRIMARY",
+ "QUERY",
+ "RAISE",
+ "RANGE",
+ "RECURSIVE",
+ "REFERENCES",
+ "REGEXP",
+ "REINDEX",
+ "RELEASE",
+ "RENAME",
+ "REPLACE",
+ "RESTRICT",
+ "RETURNING",
+ "RIGHT",
+ "ROLLBACK",
+ "ROW",
+ "ROWS",
+ "SAVEPOINT",
+ "SELECT",
+ "SET",
+ "TABLE",
+ "TEMP",
+ "TEMPORARY",
+ "THEN",
+ "TIES",
+ "TO",
+ "TRANSACTION",
+ "TRIGGER",
+ "UNBOUNDED",
+ "UNION",
+ "UNIQUE",
+ "UPDATE",
+ "USING",
+ "VACUUM",
+ "VALUES",
+ "VIEW",
+ "VIRTUAL",
+ "WHEN",
+ "WHERE",
+ "WINDOW",
+ "WITH",
+ "WITHOUT"}))},
+ {SqlInfoOptions::SqlInfo::SQL_NUMERIC_FUNCTIONS,
+ SqlInfoResult(std::vector<std::string>(
+ {"ACOS", "ACOSH", "ASIN", "ASINH", "ATAN", "ATAN2", "ATANH", "CEIL",
+ "CEILING", "COS", "COSH", "DEGREES", "EXP", "FLOOR", "LN", "LOG",
+ "LOG", "LOG10", "LOG2", "MOD", "PI", "POW", "POWER", "RADIANS",
+ "SIN", "SINH", "SQRT", "TAN", "TANH", "TRUNC"}))},
+ {SqlInfoOptions::SqlInfo::SQL_STRING_FUNCTIONS,
+ SqlInfoResult(
+ std::vector<std::string>({"SUBSTR", "TRIM", "LTRIM", "RTRIM", "LENGTH",
+ "REPLACE", "UPPER", "LOWER", "INSTR"}))},
+ {SqlInfoOptions::SqlInfo::SQL_SUPPORTS_CONVERT,
+ SqlInfoResult(std::unordered_map<int32_t, std::vector<int32_t>>(
+ {{SqlInfoOptions::SqlSupportsConvert::SQL_CONVERT_BIGINT,
+ std::vector<int32_t>(
+ {SqlInfoOptions::SqlSupportsConvert::SQL_CONVERT_INTEGER})}}))}};
+}
+
+} // namespace example
+} // namespace sql
+} // namespace flight
+} // namespace arrow
diff --git a/cpp/src/arrow/flight/sql/example/sqlite_sql_info.h b/cpp/src/arrow/flight/sql/example/sqlite_sql_info.h
new file mode 100644
index 0000000..3c6dd42
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/example/sqlite_sql_info.h
@@ -0,0 +1,34 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include "arrow/flight/sql/types.h"
+
+namespace arrow {
+namespace flight {
+namespace sql {
+namespace example {
+
+/// \brief Gets the mapping from SQL info ids to SqlInfoResult instances.
+/// \return the cache.
+SqlInfoResultMap GetSqlInfoResultMap();
+
+} // namespace example
+} // namespace sql
+} // namespace flight
+} // namespace arrow
diff --git a/cpp/src/arrow/flight/sql/example/sqlite_statement.cc b/cpp/src/arrow/flight/sql/example/sqlite_statement.cc
new file mode 100644
index 0000000..018f8de
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/example/sqlite_statement.cc
@@ -0,0 +1,137 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "arrow/flight/sql/example/sqlite_statement.h"
+
+#include <sqlite3.h>
+
+#include <boost/algorithm/string.hpp>
+
+#include "arrow/flight/sql/example/sqlite_server.h"
+
+namespace arrow {
+namespace flight {
+namespace sql {
+namespace example {
+
+std::shared_ptr<DataType> GetDataTypeFromSqliteType(const int column_type) {
+ switch (column_type) {
+ case SQLITE_INTEGER:
+ return int64();
+ case SQLITE_FLOAT:
+ return float64();
+ case SQLITE_BLOB:
+ return binary();
+ case SQLITE_TEXT:
+ return utf8();
+ case SQLITE_NULL:
+ default:
+ return null();
+ }
+}
+
+arrow::Result<std::shared_ptr<SqliteStatement>> SqliteStatement::Create(
+ sqlite3* db, const std::string& sql) {
+ sqlite3_stmt* stmt = nullptr;
+ int rc =
+ sqlite3_prepare_v2(db, sql.c_str(), static_cast<int>(sql.size()), &stmt, NULLPTR);
+
+ if (rc != SQLITE_OK) {
+ std::string err_msg = "Can't prepare statement: " + std::string(sqlite3_errmsg(db));
+ if (stmt != nullptr) {
+ rc = sqlite3_finalize(stmt);
+ if (rc != SQLITE_OK) {
+ err_msg += "; Failed to finalize SQLite statement: ";
+ err_msg += std::string(sqlite3_errmsg(db));
+ }
+ }
+ return Status::Invalid(err_msg);
+ }
+
+ std::shared_ptr<SqliteStatement> result(new SqliteStatement(db, stmt));
+ return result;
+}
+
+arrow::Result<std::shared_ptr<Schema>> SqliteStatement::GetSchema() const {
+ std::vector<std::shared_ptr<Field>> fields;
+ int column_count = sqlite3_column_count(stmt_);
+ for (int i = 0; i < column_count; i++) {
+ const char* column_name = sqlite3_column_name(stmt_, i);
+
+ // SQLite does not always provide column types, especially when the statement has not
+ // been executed yet. Because of this behaviour this method tries to get the column
+ // types in two attempts:
+ // 1. Use sqlite3_column_type(), which return SQLITE_NULL if the statement has not
+ // been executed yet
+ // 2. Use sqlite3_column_decltype(), which returns correctly if given column is
+ // declared in the table.
+ // Because of this limitation, it is not possible to know the column types for some
+ // prepared statements, in this case it returns a dense_union type covering any type
+ // SQLite supports.
+ const int column_type = sqlite3_column_type(stmt_, i);
+ std::shared_ptr<DataType> data_type = GetDataTypeFromSqliteType(column_type);
+ if (data_type->id() == Type::NA) {
+ // Try to retrieve column type from sqlite3_column_decltype
+ const char* column_decltype = sqlite3_column_decltype(stmt_, i);
+ if (column_decltype != NULLPTR) {
+ data_type = GetArrowType(column_decltype);
+ } else {
+ // If it can not determine the actual column type, return a dense_union type
+ // covering any type SQLite supports.
+ data_type = GetUnknownColumnDataType();
+ }
+ }
+
+ fields.push_back(arrow::field(column_name, data_type));
+ }
+
+ return arrow::schema(fields);
+}
+
+SqliteStatement::~SqliteStatement() { sqlite3_finalize(stmt_); }
+
+arrow::Result<int> SqliteStatement::Step() {
+ int rc = sqlite3_step(stmt_);
+ if (rc == SQLITE_ERROR) {
+ return Status::ExecutionError("A SQLite runtime error has occurred: ",
+ sqlite3_errmsg(db_));
+ }
+
+ return rc;
+}
+
+arrow::Result<int> SqliteStatement::Reset() {
+ int rc = sqlite3_reset(stmt_);
+ if (rc == SQLITE_ERROR) {
+ return Status::ExecutionError("A SQLite runtime error has occurred: ",
+ sqlite3_errmsg(db_));
+ }
+
+ return rc;
+}
+
+sqlite3_stmt* SqliteStatement::GetSqlite3Stmt() const { return stmt_; }
+
+arrow::Result<int64_t> SqliteStatement::ExecuteUpdate() {
+ ARROW_RETURN_NOT_OK(Step());
+ return sqlite3_changes(db_);
+}
+
+} // namespace example
+} // namespace sql
+} // namespace flight
+} // namespace arrow
diff --git a/cpp/src/arrow/flight/sql/example/sqlite_statement.h b/cpp/src/arrow/flight/sql/example/sqlite_statement.h
new file mode 100644
index 0000000..a3f086a
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/example/sqlite_statement.h
@@ -0,0 +1,73 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <sqlite3.h>
+
+#include <memory>
+#include <string>
+
+#include "arrow/type_fwd.h"
+
+namespace arrow {
+namespace flight {
+namespace sql {
+namespace example {
+
+class SqliteStatement {
+ public:
+ /// \brief Creates a SQLite3 statement.
+ /// \param[in] db SQLite3 database instance.
+ /// \param[in] sql SQL statement.
+ /// \return A SqliteStatement object.
+ static arrow::Result<std::shared_ptr<SqliteStatement>> Create(sqlite3* db,
+ const std::string& sql);
+
+ ~SqliteStatement();
+
+ /// \brief Creates an Arrow Schema based on the results of this statement.
+ /// \return The resulting Schema.
+ arrow::Result<std::shared_ptr<Schema>> GetSchema() const;
+
+ /// \brief Steps on underlying sqlite3_stmt.
+ /// \return The resulting return code from SQLite.
+ arrow::Result<int> Step();
+
+ /// \brief Reset the state of the sqlite3_stmt.
+ /// \return The resulting return code from SQLite.
+ arrow::Result<int> Reset();
+
+ /// \brief Returns the underlying sqlite3_stmt.
+ /// \return A sqlite statement.
+ sqlite3_stmt* GetSqlite3Stmt() const;
+
+ /// \brief Executes an UPDATE, INSERT or DELETE statement.
+ /// \return The number of rows changed by execution.
+ arrow::Result<int64_t> ExecuteUpdate();
+
+ private:
+ sqlite3* db_;
+ sqlite3_stmt* stmt_;
+
+ SqliteStatement(sqlite3* db, sqlite3_stmt* stmt) : db_(db), stmt_(stmt) {}
+};
+
+} // namespace example
+} // namespace sql
+} // namespace flight
+} // namespace arrow
diff --git a/cpp/src/arrow/flight/sql/example/sqlite_statement_batch_reader.cc b/cpp/src/arrow/flight/sql/example/sqlite_statement_batch_reader.cc
new file mode 100644
index 0000000..a5824ae
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/example/sqlite_statement_batch_reader.cc
@@ -0,0 +1,189 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "arrow/flight/sql/example/sqlite_statement_batch_reader.h"
+
+#include <sqlite3.h>
+
+#include "arrow/builder.h"
+#include "arrow/flight/sql/example/sqlite_statement.h"
+
+#define STRING_BUILDER_CASE(TYPE_CLASS, STMT, COLUMN) \
+ case TYPE_CLASS##Type::type_id: { \
+ int bytes = sqlite3_column_bytes(STMT, COLUMN); \
+ const unsigned char* string = sqlite3_column_text(STMT, COLUMN); \
+ if (string == nullptr) { \
+ ARROW_RETURN_NOT_OK( \
+ (reinterpret_cast<TYPE_CLASS##Builder&>(builder)).AppendNull()); \
+ break; \
+ } \
+ ARROW_RETURN_NOT_OK( \
+ (reinterpret_cast<TYPE_CLASS##Builder&>(builder)).Append(string, bytes)); \
+ break; \
+ }
+
+#define BINARY_BUILDER_CASE(TYPE_CLASS, STMT, COLUMN) \
+ case TYPE_CLASS##Type::type_id: { \
+ int bytes = sqlite3_column_bytes(STMT, COLUMN); \
+ const void* blob = sqlite3_column_blob(STMT, COLUMN); \
+ if (blob == nullptr) { \
+ ARROW_RETURN_NOT_OK( \
+ (reinterpret_cast<TYPE_CLASS##Builder&>(builder)).AppendNull()); \
+ break; \
+ } \
+ ARROW_RETURN_NOT_OK( \
+ (reinterpret_cast<TYPE_CLASS##Builder&>(builder)).Append((char*)blob, bytes)); \
+ break; \
+ }
+
+#define INT_BUILDER_CASE(TYPE_CLASS, STMT, COLUMN) \
+ case TYPE_CLASS##Type::type_id: { \
+ if (sqlite3_column_type(stmt_, i) == SQLITE_NULL) { \
+ ARROW_RETURN_NOT_OK( \
+ (reinterpret_cast<TYPE_CLASS##Builder&>(builder)).AppendNull()); \
+ break; \
+ } \
+ sqlite3_int64 value = sqlite3_column_int64(STMT, COLUMN); \
+ ARROW_RETURN_NOT_OK( \
+ (reinterpret_cast<TYPE_CLASS##Builder&>(builder)).Append(value)); \
+ break; \
+ }
+
+#define FLOAT_BUILDER_CASE(TYPE_CLASS, STMT, COLUMN) \
+ case TYPE_CLASS##Type::type_id: { \
+ if (sqlite3_column_type(stmt_, i) == SQLITE_NULL) { \
+ ARROW_RETURN_NOT_OK( \
+ (reinterpret_cast<TYPE_CLASS##Builder&>(builder)).AppendNull()); \
+ break; \
+ } \
+ double value = sqlite3_column_double(STMT, COLUMN); \
+ ARROW_RETURN_NOT_OK( \
+ (reinterpret_cast<TYPE_CLASS##Builder&>(builder)).Append(value)); \
+ break; \
+ }
+
+namespace arrow {
+namespace flight {
+namespace sql {
+namespace example {
+
+// Batch size for SQLite statement results
+static constexpr int kMaxBatchSize = 1024;
+
+std::shared_ptr<Schema> SqliteStatementBatchReader::schema() const { return schema_; }
+
+SqliteStatementBatchReader::SqliteStatementBatchReader(
+ std::shared_ptr<SqliteStatement> statement, std::shared_ptr<Schema> schema)
+ : statement_(std::move(statement)),
+ schema_(std::move(schema)),
+ rc_(SQLITE_OK),
+ already_executed_(false) {}
+
+Result<std::shared_ptr<SqliteStatementBatchReader>> SqliteStatementBatchReader::Create(
+ const std::shared_ptr<SqliteStatement>& statement_) {
+ ARROW_RETURN_NOT_OK(statement_->Step());
+
+ ARROW_ASSIGN_OR_RAISE(auto schema, statement_->GetSchema());
+
+ std::shared_ptr<SqliteStatementBatchReader> result(
+ new SqliteStatementBatchReader(statement_, schema));
+
+ return result;
+}
+
+arrow::Result<std::shared_ptr<SqliteStatementBatchReader>>
+SqliteStatementBatchReader::Create(const std::shared_ptr<SqliteStatement>& statement,
+ const std::shared_ptr<Schema>& schema) {
+ std::shared_ptr<SqliteStatementBatchReader> result(
+ new SqliteStatementBatchReader(statement, schema));
+
+ return result;
+}
+
+Status SqliteStatementBatchReader::ReadNext(std::shared_ptr<RecordBatch>* out) {
+ sqlite3_stmt* stmt_ = statement_->GetSqlite3Stmt();
+
+ const int num_fields = schema_->num_fields();
+ std::vector<std::unique_ptr<arrow::ArrayBuilder>> builders(num_fields);
+
+ for (int i = 0; i < num_fields; i++) {
+ const std::shared_ptr<Field>& field = schema_->field(i);
+ const std::shared_ptr<DataType>& field_type = field->type();
+
+ ARROW_RETURN_NOT_OK(MakeBuilder(default_memory_pool(), field_type, &builders[i]));
+ }
+
+ if (!already_executed_) {
+ ARROW_ASSIGN_OR_RAISE(rc_, statement_->Reset());
+ ARROW_ASSIGN_OR_RAISE(rc_, statement_->Step());
+ already_executed_ = true;
+ }
+
+ int64_t rows = 0;
+ while (rows < kMaxBatchSize && rc_ == SQLITE_ROW) {
+ rows++;
+ for (int i = 0; i < num_fields; i++) {
+ const std::shared_ptr<Field>& field = schema_->field(i);
+ const std::shared_ptr<DataType>& field_type = field->type();
+ ArrayBuilder& builder = *builders[i];
+
+ // NOTE: This is not the optimal way of building Arrow vectors.
+ // That would be to presize the builders to avoiding several resizing operations
+ // when appending values and also to build one vector at a time.
+ switch (field_type->id()) {
+ INT_BUILDER_CASE(Int64, stmt_, i)
+ INT_BUILDER_CASE(UInt64, stmt_, i)
+ INT_BUILDER_CASE(Int32, stmt_, i)
+ INT_BUILDER_CASE(UInt32, stmt_, i)
+ INT_BUILDER_CASE(Int16, stmt_, i)
+ INT_BUILDER_CASE(UInt16, stmt_, i)
+ INT_BUILDER_CASE(Int8, stmt_, i)
+ INT_BUILDER_CASE(UInt8, stmt_, i)
+ FLOAT_BUILDER_CASE(Double, stmt_, i)
+ FLOAT_BUILDER_CASE(Float, stmt_, i)
+ FLOAT_BUILDER_CASE(HalfFloat, stmt_, i)
+ BINARY_BUILDER_CASE(Binary, stmt_, i)
+ BINARY_BUILDER_CASE(LargeBinary, stmt_, i)
+ STRING_BUILDER_CASE(String, stmt_, i)
+ STRING_BUILDER_CASE(LargeString, stmt_, i)
+ default:
+ return Status::NotImplemented("Not implemented SQLite data conversion to ",
+ field_type->name());
+ }
+ }
+
+ ARROW_ASSIGN_OR_RAISE(rc_, statement_->Step());
+ }
+
+ if (rows > 0) {
+ std::vector<std::shared_ptr<Array>> arrays(builders.size());
+ for (int i = 0; i < num_fields; i++) {
+ ARROW_RETURN_NOT_OK(builders[i]->Finish(&arrays[i]));
+ }
+
+ *out = RecordBatch::Make(schema_, rows, arrays);
+ } else {
+ *out = NULLPTR;
+ }
+
+ return Status::OK();
+}
+
+} // namespace example
+} // namespace sql
+} // namespace flight
+} // namespace arrow
diff --git a/cpp/src/arrow/flight/sql/example/sqlite_statement_batch_reader.h b/cpp/src/arrow/flight/sql/example/sqlite_statement_batch_reader.h
new file mode 100644
index 0000000..8a6bc60
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/example/sqlite_statement_batch_reader.h
@@ -0,0 +1,65 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <sqlite3.h>
+
+#include <memory>
+
+#include "arrow/flight/sql/example/sqlite_statement.h"
+#include "arrow/record_batch.h"
+
+namespace arrow {
+namespace flight {
+namespace sql {
+namespace example {
+
+class SqliteStatementBatchReader : public RecordBatchReader {
+ public:
+ /// \brief Creates a RecordBatchReader backed by a SQLite statement.
+ /// \param[in] statement SQLite statement to be read.
+ /// \return A SqliteStatementBatchReader.
+ static arrow::Result<std::shared_ptr<SqliteStatementBatchReader>> Create(
+ const std::shared_ptr<SqliteStatement>& statement);
+
+ /// \brief Creates a RecordBatchReader backed by a SQLite statement.
+ /// \param[in] statement SQLite statement to be read.
+ /// \param[in] schema Schema to be used on results.
+ /// \return A SqliteStatementBatchReader..
+ static arrow::Result<std::shared_ptr<SqliteStatementBatchReader>> Create(
+ const std::shared_ptr<SqliteStatement>& statement,
+ const std::shared_ptr<Schema>& schema);
+
+ std::shared_ptr<Schema> schema() const override;
+
+ Status ReadNext(std::shared_ptr<RecordBatch>* out) override;
+
+ private:
+ std::shared_ptr<SqliteStatement> statement_;
+ std::shared_ptr<Schema> schema_;
+ int rc_;
+ bool already_executed_;
+
+ SqliteStatementBatchReader(std::shared_ptr<SqliteStatement> statement,
+ std::shared_ptr<Schema> schema);
+};
+
+} // namespace example
+} // namespace sql
+} // namespace flight
+} // namespace arrow
diff --git a/cpp/src/arrow/flight/sql/example/sqlite_tables_schema_batch_reader.cc b/cpp/src/arrow/flight/sql/example/sqlite_tables_schema_batch_reader.cc
new file mode 100644
index 0000000..7fb68a7
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/example/sqlite_tables_schema_batch_reader.cc
@@ -0,0 +1,106 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "arrow/flight/sql/example/sqlite_tables_schema_batch_reader.h"
+
+#include <sqlite3.h>
+
+#include <sstream>
+
+#include "arrow/flight/sql/example/sqlite_server.h"
+#include "arrow/flight/sql/example/sqlite_statement.h"
+#include "arrow/flight/sql/server.h"
+#include "arrow/ipc/writer.h"
+#include "arrow/record_batch.h"
+
+namespace arrow {
+namespace flight {
+namespace sql {
+namespace example {
+
+std::shared_ptr<Schema> SqliteTablesWithSchemaBatchReader::schema() const {
+ return SqlSchema::GetTablesSchemaWithIncludedSchema();
+}
+
+Status SqliteTablesWithSchemaBatchReader::ReadNext(std::shared_ptr<RecordBatch>* batch) {
+ std::stringstream schema_query;
+
+ schema_query
+ << "SELECT table_name, name, type, [notnull] FROM pragma_table_info(table_name)"
+ << "JOIN(" << main_query_ << ") order by table_name";
+
+ std::shared_ptr<example::SqliteStatement> schema_statement;
+ ARROW_ASSIGN_OR_RAISE(schema_statement,
+ example::SqliteStatement::Create(db_, schema_query.str()))
+
+ std::shared_ptr<RecordBatch> first_batch;
+
+ ARROW_RETURN_NOT_OK(reader_->ReadNext(&first_batch));
+
+ if (!first_batch) {
+ *batch = NULLPTR;
+ return Status::OK();
+ }
+
+ const std::shared_ptr<Array> table_name_array =
+ first_batch->GetColumnByName("table_name");
+
+ BinaryBuilder schema_builder;
+
+ auto* string_array = reinterpret_cast<StringArray*>(table_name_array.get());
+
+ std::vector<std::shared_ptr<Field>> column_fields;
+ for (int i = 0; i < table_name_array->length(); i++) {
+ const std::string& table_name = string_array->GetString(i);
+
+ while (sqlite3_step(schema_statement->GetSqlite3Stmt()) == SQLITE_ROW) {
+ std::string sqlite_table_name = std::string(reinterpret_cast<const char*>(
+ sqlite3_column_text(schema_statement->GetSqlite3Stmt(), 0)));
+ if (sqlite_table_name == table_name) {
+ const char* column_name = reinterpret_cast<const char*>(
+ sqlite3_column_text(schema_statement->GetSqlite3Stmt(), 1));
+ const char* column_type = reinterpret_cast<const char*>(
+ sqlite3_column_text(schema_statement->GetSqlite3Stmt(), 2));
+ int nullable = sqlite3_column_int(schema_statement->GetSqlite3Stmt(), 3);
+
+ column_fields.push_back(
+ arrow::field(column_name, GetArrowType(column_type), nullable == 0, NULL));
+ }
+ }
+ const arrow::Result<std::shared_ptr<Buffer>>& value =
+ ipc::SerializeSchema(*arrow::schema(column_fields));
+
+ std::shared_ptr<Buffer> schema_buffer;
+ ARROW_ASSIGN_OR_RAISE(schema_buffer, value);
+
+ column_fields.clear();
+ ARROW_RETURN_NOT_OK(
+ schema_builder.Append(schema_buffer->data(), schema_buffer->size()));
+ }
+
+ std::shared_ptr<Array> schema_array;
+ ARROW_RETURN_NOT_OK(schema_builder.Finish(&schema_array));
+
+ ARROW_ASSIGN_OR_RAISE(*batch, first_batch->AddColumn(4, "table_schema", schema_array));
+
+ return Status::OK();
+}
+
+} // namespace example
+} // namespace sql
+} // namespace flight
+} // namespace arrow
diff --git a/cpp/src/arrow/flight/sql/example/sqlite_tables_schema_batch_reader.h b/cpp/src/arrow/flight/sql/example/sqlite_tables_schema_batch_reader.h
new file mode 100644
index 0000000..ecba88e
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/example/sqlite_tables_schema_batch_reader.h
@@ -0,0 +1,58 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <sqlite3.h>
+
+#include <memory>
+#include <string>
+
+#include "arrow/flight/sql/example/sqlite_statement.h"
+#include "arrow/flight/sql/example/sqlite_statement_batch_reader.h"
+#include "arrow/record_batch.h"
+
+namespace arrow {
+namespace flight {
+namespace sql {
+namespace example {
+
+class SqliteTablesWithSchemaBatchReader : public RecordBatchReader {
+ private:
+ std::shared_ptr<example::SqliteStatementBatchReader> reader_;
+ std::string main_query_;
+ sqlite3* db_;
+
+ public:
+ /// Constructor for SqliteTablesWithSchemaBatchReader class
+ /// \param reader an shared_ptr from a SqliteStatementBatchReader.
+ /// \param main_query SQL query that originated reader's data.
+ /// \param db a pointer to the sqlite3 db.
+ SqliteTablesWithSchemaBatchReader(
+ std::shared_ptr<example::SqliteStatementBatchReader> reader, std::string main_query,
+ sqlite3* db)
+ : reader_(std::move(reader)), main_query_(std::move(main_query)), db_(db) {}
+
+ std::shared_ptr<Schema> schema() const override;
+
+ Status ReadNext(std::shared_ptr<RecordBatch>* batch) override;
+};
+
+} // namespace example
+} // namespace sql
+} // namespace flight
+} // namespace arrow
diff --git a/cpp/src/arrow/flight/sql/server.cc b/cpp/src/arrow/flight/sql/server.cc
new file mode 100644
index 0000000..6d328c0
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/server.cc
@@ -0,0 +1,761 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// Interfaces to use for defining Flight RPC servers. API should be considered
+// experimental for now
+
+#include "arrow/flight/sql/server.h"
+
+#include <google/protobuf/any.pb.h>
+
+#include "arrow/buffer.h"
+#include "arrow/builder.h"
+#include "arrow/flight/sql/FlightSql.pb.h"
+#include "arrow/flight/sql/sql_info_internal.h"
+#include "arrow/type.h"
+#include "arrow/util/checked_cast.h"
+
+#define PROPERTY_TO_OPTIONAL(COMMAND, PROPERTY) \
+ COMMAND.has_##PROPERTY() ? util::make_optional(COMMAND.PROPERTY()) : util::nullopt
+
+namespace arrow {
+namespace flight {
+namespace sql {
+
+namespace pb = arrow::flight::protocol;
+
+using arrow::internal::checked_cast;
+using arrow::internal::checked_pointer_cast;
+
+namespace {
+
+arrow::Result<GetCrossReference> ParseCommandGetCrossReference(
+ const google::protobuf::Any& any) {
+ pb::sql::CommandGetCrossReference command;
+ if (!any.UnpackTo(&command)) {
+ return Status::Invalid("Unable to unpack CommandGetCrossReference.");
+ }
+
+ GetCrossReference result;
+ result.pk_table_ref = {PROPERTY_TO_OPTIONAL(command, pk_catalog),
+ PROPERTY_TO_OPTIONAL(command, pk_db_schema), command.pk_table()};
+ result.fk_table_ref = {PROPERTY_TO_OPTIONAL(command, fk_catalog),
+ PROPERTY_TO_OPTIONAL(command, fk_db_schema), command.fk_table()};
+ return result;
+}
+
+arrow::Result<GetImportedKeys> ParseCommandGetImportedKeys(
+ const google::protobuf::Any& any) {
+ pb::sql::CommandGetImportedKeys command;
+ if (!any.UnpackTo(&command)) {
+ return Status::Invalid("Unable to unpack CommandGetImportedKeys.");
+ }
+
+ GetImportedKeys result;
+ result.table_ref = {PROPERTY_TO_OPTIONAL(command, catalog),
+ PROPERTY_TO_OPTIONAL(command, db_schema), command.table()};
+ return result;
+}
+
+arrow::Result<GetExportedKeys> ParseCommandGetExportedKeys(
+ const google::protobuf::Any& any) {
+ pb::sql::CommandGetExportedKeys command;
+ if (!any.UnpackTo(&command)) {
+ return Status::Invalid("Unable to unpack CommandGetExportedKeys.");
+ }
+
+ GetExportedKeys result;
+ result.table_ref = {PROPERTY_TO_OPTIONAL(command, catalog),
+ PROPERTY_TO_OPTIONAL(command, db_schema), command.table()};
+ return result;
+}
+
+arrow::Result<GetPrimaryKeys> ParseCommandGetPrimaryKeys(
+ const google::protobuf::Any& any) {
+ pb::sql::CommandGetPrimaryKeys command;
+ if (!any.UnpackTo(&command)) {
+ return Status::Invalid("Unable to unpack CommandGetPrimaryKeys.");
+ }
+
+ GetPrimaryKeys result;
+ result.table_ref = {PROPERTY_TO_OPTIONAL(command, catalog),
+ PROPERTY_TO_OPTIONAL(command, db_schema), command.table()};
+ return result;
+}
+
+arrow::Result<GetSqlInfo> ParseCommandGetSqlInfo(
+ const google::protobuf::Any& any, const SqlInfoResultMap& sql_info_id_to_result) {
+ pb::sql::CommandGetSqlInfo command;
+ if (!any.UnpackTo(&command)) {
+ return Status::Invalid("Unable to unpack CommandGetSqlInfo.");
+ }
+
+ GetSqlInfo result;
+ if (command.info_size() > 0) {
+ result.info.reserve(command.info_size());
+ result.info.assign(command.info().begin(), command.info().end());
+ } else {
+ result.info.reserve(sql_info_id_to_result.size());
+ for (const auto& it : sql_info_id_to_result) {
+ result.info.push_back(it.first);
+ }
+ }
+ return result;
+}
+
+arrow::Result<GetDbSchemas> ParseCommandGetDbSchemas(const google::protobuf::Any& any) {
+ pb::sql::CommandGetDbSchemas command;
+ if (!any.UnpackTo(&command)) {
+ return Status::Invalid("Unable to unpack CommandGetDbSchemas.");
+ }
+
+ GetDbSchemas result;
+ result.catalog = PROPERTY_TO_OPTIONAL(command, catalog);
+ result.db_schema_filter_pattern =
+ PROPERTY_TO_OPTIONAL(command, db_schema_filter_pattern);
+ return result;
+}
+
+arrow::Result<PreparedStatementQuery> ParseCommandPreparedStatementQuery(
+ const google::protobuf::Any& any) {
+ pb::sql::CommandPreparedStatementQuery command;
+ if (!any.UnpackTo(&command)) {
+ return Status::Invalid("Unable to unpack CommandPreparedStatementQuery.");
+ }
+
+ PreparedStatementQuery result;
+ result.prepared_statement_handle = command.prepared_statement_handle();
+ return result;
+}
+
+arrow::Result<StatementQuery> ParseCommandStatementQuery(
+ const google::protobuf::Any& any) {
+ pb::sql::CommandStatementQuery command;
+ if (!any.UnpackTo(&command)) {
+ return Status::Invalid("Unable to unpack CommandStatementQuery.");
+ }
+
+ StatementQuery result;
+ result.query = command.query();
+ return result;
+}
+
+arrow::Result<GetTables> ParseCommandGetTables(const google::protobuf::Any& any) {
+ pb::sql::CommandGetTables command;
+ if (!any.UnpackTo(&command)) {
+ return Status::Invalid("Unable to unpack CommandGetTables.");
+ }
+
+ std::vector<std::string> table_types(command.table_types_size());
+ std::copy(command.table_types().begin(), command.table_types().end(),
+ table_types.begin());
+
+ GetTables result;
+ result.catalog = PROPERTY_TO_OPTIONAL(command, catalog);
+ result.db_schema_filter_pattern =
+ PROPERTY_TO_OPTIONAL(command, db_schema_filter_pattern);
+ result.table_name_filter_pattern =
+ PROPERTY_TO_OPTIONAL(command, table_name_filter_pattern);
+ result.table_types = table_types;
+ result.include_schema = command.include_schema();
+ return result;
+}
+
+arrow::Result<StatementQueryTicket> ParseStatementQueryTicket(
+ const google::protobuf::Any& any) {
+ pb::sql::TicketStatementQuery command;
+ if (!any.UnpackTo(&command)) {
+ return Status::Invalid("Unable to unpack TicketStatementQuery.");
+ }
+
+ StatementQueryTicket result;
+ result.statement_handle = command.statement_handle();
+ return result;
+}
+
+arrow::Result<StatementUpdate> ParseCommandStatementUpdate(
+ const google::protobuf::Any& any) {
+ pb::sql::CommandStatementUpdate command;
+ if (!any.UnpackTo(&command)) {
+ return Status::Invalid("Unable to unpack CommandStatementUpdate.");
+ }
+
+ StatementUpdate result;
+ result.query = command.query();
+ return result;
+}
+
+arrow::Result<PreparedStatementUpdate> ParseCommandPreparedStatementUpdate(
+ const google::protobuf::Any& any) {
+ pb::sql::CommandPreparedStatementUpdate command;
+ if (!any.UnpackTo(&command)) {
+ return Status::Invalid("Unable to unpack CommandPreparedStatementUpdate.");
+ }
+
+ PreparedStatementUpdate result;
+ result.prepared_statement_handle = command.prepared_statement_handle();
+ return result;
+}
+
+arrow::Result<ActionCreatePreparedStatementRequest>
+ParseActionCreatePreparedStatementRequest(const google::protobuf::Any& any) {
+ pb::sql::ActionCreatePreparedStatementRequest command;
+ if (!any.UnpackTo(&command)) {
+ return Status::Invalid("Unable to unpack ActionCreatePreparedStatementRequest.");
+ }
+
+ ActionCreatePreparedStatementRequest result;
+ result.query = command.query();
+ return result;
+}
+
+arrow::Result<ActionClosePreparedStatementRequest>
+ParseActionClosePreparedStatementRequest(const google::protobuf::Any& any) {
+ pb::sql::ActionClosePreparedStatementRequest command;
+ if (!any.UnpackTo(&command)) {
+ return Status::Invalid("Unable to unpack ActionClosePreparedStatementRequest.");
+ }
+
+ ActionClosePreparedStatementRequest result;
+ result.prepared_statement_handle = command.prepared_statement_handle();
+ return result;
+}
+
+} // namespace
+
+arrow::Result<std::string> CreateStatementQueryTicket(
+ const std::string& statement_handle) {
+ protocol::sql::TicketStatementQuery ticket_statement_query;
+ ticket_statement_query.set_statement_handle(statement_handle);
+
+ google::protobuf::Any ticket;
+ ticket.PackFrom(ticket_statement_query);
+
+ std::string ticket_string;
+
+ if (!ticket.SerializeToString(&ticket_string)) {
+ return Status::IOError("Invalid ticket.");
+ }
+ return ticket_string;
+}
+
+Status FlightSqlServerBase::GetFlightInfo(const ServerCallContext& context,
+ const FlightDescriptor& request,
+ std::unique_ptr<FlightInfo>* info) {
+ google::protobuf::Any any;
+ if (!any.ParseFromArray(request.cmd.data(), static_cast<int>(request.cmd.size()))) {
+ return Status::Invalid("Unable to parse command");
+ }
+
+ if (any.Is<pb::sql::CommandStatementQuery>()) {
+ ARROW_ASSIGN_OR_RAISE(StatementQuery internal_command,
+ ParseCommandStatementQuery(any));
+ ARROW_ASSIGN_OR_RAISE(*info,
+ GetFlightInfoStatement(context, internal_command, request));
+ return Status::OK();
+ } else if (any.Is<pb::sql::CommandPreparedStatementQuery>()) {
+ ARROW_ASSIGN_OR_RAISE(PreparedStatementQuery internal_command,
+ ParseCommandPreparedStatementQuery(any));
+ ARROW_ASSIGN_OR_RAISE(
+ *info, GetFlightInfoPreparedStatement(context, internal_command, request));
+ return Status::OK();
+ } else if (any.Is<pb::sql::CommandGetCatalogs>()) {
+ ARROW_ASSIGN_OR_RAISE(*info, GetFlightInfoCatalogs(context, request));
+ return Status::OK();
+ } else if (any.Is<pb::sql::CommandGetDbSchemas>()) {
+ ARROW_ASSIGN_OR_RAISE(GetDbSchemas internal_command, ParseCommandGetDbSchemas(any));
+ ARROW_ASSIGN_OR_RAISE(*info,
+ GetFlightInfoSchemas(context, internal_command, request));
+ return Status::OK();
+ } else if (any.Is<pb::sql::CommandGetTables>()) {
+ ARROW_ASSIGN_OR_RAISE(GetTables command, ParseCommandGetTables(any));
+ ARROW_ASSIGN_OR_RAISE(*info, GetFlightInfoTables(context, command, request));
+ return Status::OK();
+ } else if (any.Is<pb::sql::CommandGetTableTypes>()) {
+ ARROW_ASSIGN_OR_RAISE(*info, GetFlightInfoTableTypes(context, request));
+ return Status::OK();
+ } else if (any.Is<pb::sql::CommandGetSqlInfo>()) {
+ ARROW_ASSIGN_OR_RAISE(GetSqlInfo internal_command,
+ ParseCommandGetSqlInfo(any, sql_info_id_to_result_));
+ ARROW_ASSIGN_OR_RAISE(*info,
+ GetFlightInfoSqlInfo(context, internal_command, request));
+ return Status::OK();
+ } else if (any.Is<pb::sql::CommandGetPrimaryKeys>()) {
+ ARROW_ASSIGN_OR_RAISE(GetPrimaryKeys internal_command,
+ ParseCommandGetPrimaryKeys(any));
+ ARROW_ASSIGN_OR_RAISE(*info,
+ GetFlightInfoPrimaryKeys(context, internal_command, request));
+ return Status::OK();
+ } else if (any.Is<pb::sql::CommandGetExportedKeys>()) {
+ ARROW_ASSIGN_OR_RAISE(GetExportedKeys internal_command,
+ ParseCommandGetExportedKeys(any));
+ ARROW_ASSIGN_OR_RAISE(*info,
+ GetFlightInfoExportedKeys(context, internal_command, request));
+ return Status::OK();
+ } else if (any.Is<pb::sql::CommandGetImportedKeys>()) {
+ ARROW_ASSIGN_OR_RAISE(GetImportedKeys internal_command,
+ ParseCommandGetImportedKeys(any));
+ ARROW_ASSIGN_OR_RAISE(*info,
+ GetFlightInfoImportedKeys(context, internal_command, request));
+ return Status::OK();
+ } else if (any.Is<pb::sql::CommandGetCrossReference>()) {
+ ARROW_ASSIGN_OR_RAISE(GetCrossReference internal_command,
+ ParseCommandGetCrossReference(any));
+ ARROW_ASSIGN_OR_RAISE(
+ *info, GetFlightInfoCrossReference(context, internal_command, request));
+ return Status::OK();
+ }
+
+ return Status::Invalid("The defined request is invalid.");
+}
+
+Status FlightSqlServerBase::DoGet(const ServerCallContext& context, const Ticket& request,
+ std::unique_ptr<FlightDataStream>* stream) {
+ google::protobuf::Any any;
+
+ if (!any.ParseFromArray(request.ticket.data(),
+ static_cast<int>(request.ticket.size()))) {
+ return Status::Invalid("Unable to parse ticket.");
+ }
+
+ if (any.Is<pb::sql::TicketStatementQuery>()) {
+ ARROW_ASSIGN_OR_RAISE(StatementQueryTicket command, ParseStatementQueryTicket(any));
+ ARROW_ASSIGN_OR_RAISE(*stream, DoGetStatement(context, command));
+ return Status::OK();
+ } else if (any.Is<pb::sql::CommandPreparedStatementQuery>()) {
+ ARROW_ASSIGN_OR_RAISE(PreparedStatementQuery internal_command,
+ ParseCommandPreparedStatementQuery(any));
+ ARROW_ASSIGN_OR_RAISE(*stream, DoGetPreparedStatement(context, internal_command));
+ return Status::OK();
+ } else if (any.Is<pb::sql::CommandGetCatalogs>()) {
+ ARROW_ASSIGN_OR_RAISE(*stream, DoGetCatalogs(context));
+ return Status::OK();
+ } else if (any.Is<pb::sql::CommandGetDbSchemas>()) {
+ ARROW_ASSIGN_OR_RAISE(GetDbSchemas internal_command, ParseCommandGetDbSchemas(any));
+ ARROW_ASSIGN_OR_RAISE(*stream, DoGetDbSchemas(context, internal_command));
+ return Status::OK();
+ } else if (any.Is<pb::sql::CommandGetTables>()) {
+ ARROW_ASSIGN_OR_RAISE(GetTables command, ParseCommandGetTables(any));
+ ARROW_ASSIGN_OR_RAISE(*stream, DoGetTables(context, command));
+ return Status::OK();
+ } else if (any.Is<pb::sql::CommandGetTableTypes>()) {
+ ARROW_ASSIGN_OR_RAISE(*stream, DoGetTableTypes(context));
+ return Status::OK();
+ } else if (any.Is<pb::sql::CommandGetSqlInfo>()) {
+ ARROW_ASSIGN_OR_RAISE(GetSqlInfo internal_command,
+ ParseCommandGetSqlInfo(any, sql_info_id_to_result_));
+ ARROW_ASSIGN_OR_RAISE(*stream, DoGetSqlInfo(context, internal_command));
+ return Status::OK();
+ } else if (any.Is<pb::sql::CommandGetPrimaryKeys>()) {
+ ARROW_ASSIGN_OR_RAISE(GetPrimaryKeys internal_command,
+ ParseCommandGetPrimaryKeys(any));
+ ARROW_ASSIGN_OR_RAISE(*stream, DoGetPrimaryKeys(context, internal_command));
+ return Status::OK();
+ } else if (any.Is<pb::sql::CommandGetExportedKeys>()) {
+ ARROW_ASSIGN_OR_RAISE(GetExportedKeys internal_command,
+ ParseCommandGetExportedKeys(any));
+ ARROW_ASSIGN_OR_RAISE(*stream, DoGetExportedKeys(context, internal_command));
+ return Status::OK();
+ } else if (any.Is<pb::sql::CommandGetImportedKeys>()) {
+ ARROW_ASSIGN_OR_RAISE(GetImportedKeys internal_command,
+ ParseCommandGetImportedKeys(any));
+ ARROW_ASSIGN_OR_RAISE(*stream, DoGetImportedKeys(context, internal_command));
+ return Status::OK();
+ } else if (any.Is<pb::sql::CommandGetCrossReference>()) {
+ ARROW_ASSIGN_OR_RAISE(GetCrossReference internal_command,
+ ParseCommandGetCrossReference(any));
+ ARROW_ASSIGN_OR_RAISE(*stream, DoGetCrossReference(context, internal_command));
+ return Status::OK();
+ }
+
+ return Status::Invalid("The defined request is invalid.");
+}
+
+Status FlightSqlServerBase::DoPut(const ServerCallContext& context,
+ std::unique_ptr<FlightMessageReader> reader,
+ std::unique_ptr<FlightMetadataWriter> writer) {
+ const FlightDescriptor& request = reader->descriptor();
+
+ google::protobuf::Any any;
+ if (!any.ParseFromArray(request.cmd.data(), static_cast<int>(request.cmd.size()))) {
+ return Status::Invalid("Unable to parse command.");
+ }
+
+ if (any.Is<pb::sql::CommandStatementUpdate>()) {
+ ARROW_ASSIGN_OR_RAISE(StatementUpdate internal_command,
+ ParseCommandStatementUpdate(any));
+ ARROW_ASSIGN_OR_RAISE(auto record_count,
+ DoPutCommandStatementUpdate(context, internal_command))
+
+ pb::sql::DoPutUpdateResult result;
+ result.set_record_count(record_count);
+
+ const auto buffer = Buffer::FromString(result.SerializeAsString());
+ ARROW_RETURN_NOT_OK(writer->WriteMetadata(*buffer));
+
+ return Status::OK();
+ } else if (any.Is<pb::sql::CommandPreparedStatementQuery>()) {
+ ARROW_ASSIGN_OR_RAISE(PreparedStatementQuery internal_command,
+ ParseCommandPreparedStatementQuery(any));
+ return DoPutPreparedStatementQuery(context, internal_command, reader.get(),
+ writer.get());
+ } else if (any.Is<pb::sql::CommandPreparedStatementUpdate>()) {
+ ARROW_ASSIGN_OR_RAISE(PreparedStatementUpdate internal_command,
+ ParseCommandPreparedStatementUpdate(any));
+ ARROW_ASSIGN_OR_RAISE(auto record_count, DoPutPreparedStatementUpdate(
+ context, internal_command, reader.get()))
+
+ pb::sql::DoPutUpdateResult result;
+ result.set_record_count(record_count);
+
+ const auto buffer = Buffer::FromString(result.SerializeAsString());
+ ARROW_RETURN_NOT_OK(writer->WriteMetadata(*buffer));
+
+ return Status::OK();
+ }
+
+ return Status::Invalid("The defined request is invalid.");
+}
+
+Status FlightSqlServerBase::ListActions(const ServerCallContext& context,
+ std::vector<ActionType>* actions) {
+ *actions = {FlightSqlServerBase::kCreatePreparedStatementActionType,
+ FlightSqlServerBase::kClosePreparedStatementActionType};
+ return Status::OK();
+}
+
+Status FlightSqlServerBase::DoAction(const ServerCallContext& context,
+ const Action& action,
+ std::unique_ptr<ResultStream>* result_stream) {
+ if (action.type == FlightSqlServerBase::kCreatePreparedStatementActionType.type) {
+ google::protobuf::Any any_command;
+ if (!any_command.ParseFromArray(action.body->data(),
+ static_cast<int>(action.body->size()))) {
+ return Status::Invalid("Unable to parse action.");
+ }
+
+ ARROW_ASSIGN_OR_RAISE(ActionCreatePreparedStatementRequest internal_command,
+ ParseActionCreatePreparedStatementRequest(any_command));
+ ARROW_ASSIGN_OR_RAISE(auto result, CreatePreparedStatement(context, internal_command))
+
+ pb::sql::ActionCreatePreparedStatementResult action_result;
+ action_result.set_prepared_statement_handle(result.prepared_statement_handle);
+ if (result.dataset_schema != nullptr) {
+ ARROW_ASSIGN_OR_RAISE(auto serialized_dataset_schema,
+ ipc::SerializeSchema(*result.dataset_schema))
+ action_result.set_dataset_schema(serialized_dataset_schema->ToString());
+ }
+ if (result.parameter_schema != nullptr) {
+ ARROW_ASSIGN_OR_RAISE(auto serialized_parameter_schema,
+ ipc::SerializeSchema(*result.parameter_schema))
+ action_result.set_parameter_schema(serialized_parameter_schema->ToString());
+ }
+
+ google::protobuf::Any any;
+ any.PackFrom(action_result);
+
+ auto buf = Buffer::FromString(any.SerializeAsString());
+ *result_stream = std::unique_ptr<ResultStream>(new SimpleResultStream({Result{buf}}));
+
+ return Status::OK();
+ } else if (action.type == FlightSqlServerBase::kClosePreparedStatementActionType.type) {
+ google::protobuf::Any any;
+ if (!any.ParseFromArray(action.body->data(), static_cast<int>(action.body->size()))) {
+ return Status::Invalid("Unable to parse action.");
+ }
+
+ ARROW_ASSIGN_OR_RAISE(ActionClosePreparedStatementRequest internal_command,
+ ParseActionClosePreparedStatementRequest(any));
+
+ ARROW_RETURN_NOT_OK(ClosePreparedStatement(context, internal_command));
+
+ // Need to instantiate a ResultStream, otherwise clients can not wait for completion.
+ *result_stream = std::unique_ptr<ResultStream>(new SimpleResultStream({}));
+ return Status::OK();
+ }
+ return Status::Invalid("The defined request is invalid.");
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> FlightSqlServerBase::GetFlightInfoCatalogs(
+ const ServerCallContext& context, const FlightDescriptor& descriptor) {
+ return Status::NotImplemented("GetFlightInfoCatalogs not implemented");
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>> FlightSqlServerBase::DoGetCatalogs(
+ const ServerCallContext& context) {
+ return Status::NotImplemented("DoGetCatalogs not implemented");
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> FlightSqlServerBase::GetFlightInfoStatement(
+ const ServerCallContext& context, const StatementQuery& command,
+ const FlightDescriptor& descriptor) {
+ return Status::NotImplemented("GetFlightInfoStatement not implemented");
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>> FlightSqlServerBase::DoGetStatement(
+ const ServerCallContext& context, const StatementQueryTicket& command) {
+ return Status::NotImplemented("DoGetStatement not implemented");
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>>
+FlightSqlServerBase::GetFlightInfoPreparedStatement(const ServerCallContext& context,
+ const PreparedStatementQuery& command,
+ const FlightDescriptor& descriptor) {
+ return Status::NotImplemented("GetFlightInfoPreparedStatement not implemented");
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>>
+FlightSqlServerBase::DoGetPreparedStatement(const ServerCallContext& context,
+ const PreparedStatementQuery& command) {
+ return Status::NotImplemented("DoGetPreparedStatement not implemented");
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> FlightSqlServerBase::GetFlightInfoSqlInfo(
+ const ServerCallContext& context, const GetSqlInfo& command,
+ const FlightDescriptor& descriptor) {
+ if (sql_info_id_to_result_.empty()) {
+ return Status::KeyError("No SQL information available.");
+ }
+
+ std::vector<FlightEndpoint> endpoints{FlightEndpoint{{descriptor.cmd}, {}}};
+ ARROW_ASSIGN_OR_RAISE(auto result, FlightInfo::Make(*SqlSchema::GetSqlInfoSchema(),
+ descriptor, endpoints, -1, -1))
+
+ return std::unique_ptr<FlightInfo>(new FlightInfo(result));
+}
+
+void FlightSqlServerBase::RegisterSqlInfo(int32_t id, const SqlInfoResult& result) {
+ sql_info_id_to_result_[id] = result;
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>> FlightSqlServerBase::DoGetSqlInfo(
+ const ServerCallContext& context, const GetSqlInfo& command) {
+ MemoryPool* memory_pool = default_memory_pool();
+ UInt32Builder name_field_builder(memory_pool);
+ std::unique_ptr<ArrayBuilder> value_field_builder;
+ const auto& value_field_type = checked_pointer_cast<DenseUnionType>(
+ SqlSchema::GetSqlInfoSchema()->fields()[1]->type());
+ ARROW_RETURN_NOT_OK(MakeBuilder(memory_pool, value_field_type, &value_field_builder));
+
+ internal::SqlInfoResultAppender sql_info_result_appender(
+ checked_cast<DenseUnionBuilder*>(value_field_builder.get()));
+
+ // Populate both name_field_builder and value_field_builder for each element
+ // on command.info.
+ // value_field_builder is populated differently depending on the data type (as it is
+ // a DenseUnionBuilder). The population for each data type is implemented on
+ // internal::SqlInfoResultAppender.
+ for (const auto& info : command.info) {
+ const auto it = sql_info_id_to_result_.find(info);
+ if (it == sql_info_id_to_result_.end()) {
+ return Status::KeyError("No information for SQL info number ", info);
+ }
+ ARROW_RETURN_NOT_OK(name_field_builder.Append(info));
+ ARROW_RETURN_NOT_OK(arrow::util::visit(sql_info_result_appender, it->second));
+ }
+
+ std::shared_ptr<Array> name;
+ ARROW_RETURN_NOT_OK(name_field_builder.Finish(&name));
+ std::shared_ptr<Array> value;
+ ARROW_RETURN_NOT_OK(value_field_builder->Finish(&value));
+
+ auto row_count = static_cast<int64_t>(command.info.size());
+ const std::shared_ptr<RecordBatch>& batch =
+ RecordBatch::Make(SqlSchema::GetSqlInfoSchema(), row_count, {name, value});
+ ARROW_ASSIGN_OR_RAISE(const auto reader, RecordBatchReader::Make({batch}));
+
+ return std::unique_ptr<FlightDataStream>(new RecordBatchStream(reader));
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> FlightSqlServerBase::GetFlightInfoSchemas(
+ const ServerCallContext& context, const GetDbSchemas& command,
+ const FlightDescriptor& descriptor) {
+ return Status::NotImplemented("GetFlightInfoSchemas not implemented");
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>> FlightSqlServerBase::DoGetDbSchemas(
+ const ServerCallContext& context, const GetDbSchemas& command) {
+ return Status::NotImplemented("DoGetDbSchemas not implemented");
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> FlightSqlServerBase::GetFlightInfoTables(
+ const ServerCallContext& context, const GetTables& command,
+ const FlightDescriptor& descriptor) {
+ return Status::NotImplemented("GetFlightInfoTables not implemented");
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>> FlightSqlServerBase::DoGetTables(
+ const ServerCallContext& context, const GetTables& command) {
+ return Status::NotImplemented("DoGetTables not implemented");
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> FlightSqlServerBase::GetFlightInfoTableTypes(
+ const ServerCallContext& context, const FlightDescriptor& descriptor) {
+ return Status::NotImplemented("GetFlightInfoTableTypes not implemented");
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>> FlightSqlServerBase::DoGetTableTypes(
+ const ServerCallContext& context) {
+ return Status::NotImplemented("DoGetTableTypes not implemented");
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> FlightSqlServerBase::GetFlightInfoPrimaryKeys(
+ const ServerCallContext& context, const GetPrimaryKeys& command,
+ const FlightDescriptor& descriptor) {
+ return Status::NotImplemented("GetFlightInfoPrimaryKeys not implemented");
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>> FlightSqlServerBase::DoGetPrimaryKeys(
+ const ServerCallContext& context, const GetPrimaryKeys& command) {
+ return Status::NotImplemented("DoGetPrimaryKeys not implemented");
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> FlightSqlServerBase::GetFlightInfoExportedKeys(
+ const ServerCallContext& context, const GetExportedKeys& command,
+ const FlightDescriptor& descriptor) {
+ return Status::NotImplemented("GetFlightInfoExportedKeys not implemented");
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>> FlightSqlServerBase::DoGetExportedKeys(
+ const ServerCallContext& context, const GetExportedKeys& command) {
+ return Status::NotImplemented("DoGetExportedKeys not implemented");
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>> FlightSqlServerBase::GetFlightInfoImportedKeys(
+ const ServerCallContext& context, const GetImportedKeys& command,
+ const FlightDescriptor& descriptor) {
+ return Status::NotImplemented("GetFlightInfoImportedKeys not implemented");
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>> FlightSqlServerBase::DoGetImportedKeys(
+ const ServerCallContext& context, const GetImportedKeys& command) {
+ return Status::NotImplemented("DoGetImportedKeys not implemented");
+}
+
+arrow::Result<std::unique_ptr<FlightInfo>>
+FlightSqlServerBase::GetFlightInfoCrossReference(const ServerCallContext& context,
+ const GetCrossReference& command,
+ const FlightDescriptor& descriptor) {
+ return Status::NotImplemented("GetFlightInfoCrossReference not implemented");
+}
+
+arrow::Result<std::unique_ptr<FlightDataStream>> FlightSqlServerBase::DoGetCrossReference(
+ const ServerCallContext& context, const GetCrossReference& command) {
+ return Status::NotImplemented("DoGetCrossReference not implemented");
+}
+
+arrow::Result<ActionCreatePreparedStatementResult>
+FlightSqlServerBase::CreatePreparedStatement(
+ const ServerCallContext& context,
+ const ActionCreatePreparedStatementRequest& request) {
+ return Status::NotImplemented("CreatePreparedStatement not implemented");
+}
+
+Status FlightSqlServerBase::ClosePreparedStatement(
+ const ServerCallContext& context,
+ const ActionClosePreparedStatementRequest& request) {
+ return Status::NotImplemented("ClosePreparedStatement not implemented");
+}
+
+Status FlightSqlServerBase::DoPutPreparedStatementQuery(
+ const ServerCallContext& context, const PreparedStatementQuery& command,
+ FlightMessageReader* reader, FlightMetadataWriter* writer) {
+ return Status::NotImplemented("DoPutPreparedStatementQuery not implemented");
+}
+
+arrow::Result<int64_t> FlightSqlServerBase::DoPutPreparedStatementUpdate(
+ const ServerCallContext& context, const PreparedStatementUpdate& command,
+ FlightMessageReader* reader) {
+ return Status::NotImplemented("DoPutPreparedStatementUpdate not implemented");
+}
+
+arrow::Result<int64_t> FlightSqlServerBase::DoPutCommandStatementUpdate(
+ const ServerCallContext& context, const StatementUpdate& command) {
+ return Status::NotImplemented("DoPutCommandStatementUpdate not implemented");
+}
+
+std::shared_ptr<Schema> SqlSchema::GetCatalogsSchema() {
+ return arrow::schema({field("catalog_name", utf8())});
+}
+
+std::shared_ptr<Schema> SqlSchema::GetDbSchemasSchema() {
+ return arrow::schema(
+ {field("catalog_name", utf8()), field("db_schema_name", utf8(), false)});
+}
+
+std::shared_ptr<Schema> SqlSchema::GetTablesSchema() {
+ return arrow::schema({field("catalog_name", utf8()), field("db_schema_name", utf8()),
+ field("table_name", utf8()), field("table_type", utf8())});
+}
+
+std::shared_ptr<Schema> SqlSchema::GetTablesSchemaWithIncludedSchema() {
+ return arrow::schema({field("catalog_name", utf8()), field("db_schema_name", utf8()),
+ field("table_name", utf8()), field("table_type", utf8()),
+ field("table_schema", binary())});
+}
+
+std::shared_ptr<Schema> SqlSchema::GetTableTypesSchema() {
+ return arrow::schema({field("table_type", utf8())});
+}
+
+std::shared_ptr<Schema> SqlSchema::GetPrimaryKeysSchema() {
+ return arrow::schema({field("catalog_name", utf8()), field("db_schema_name", utf8()),
+ field("table_name", utf8()), field("column_name", utf8()),
+ field("key_sequence", int64()), field("key_name", utf8())});
+}
+
+std::shared_ptr<Schema> GetImportedExportedKeysAndCrossReferenceSchema() {
+ return arrow::schema(
+ {field("pk_catalog_name", utf8(), true), field("pk_db_schema_name", utf8(), true),
+ field("pk_table_name", utf8(), false), field("pk_column_name", utf8(), false),
+ field("fk_catalog_name", utf8(), true), field("fk_db_schema_name", utf8(), true),
+ field("fk_table_name", utf8(), false), field("fk_column_name", utf8(), false),
+ field("key_sequence", int32(), false), field("fk_key_name", utf8(), true),
+ field("pk_key_name", utf8(), true), field("update_rule", uint8(), false),
+ field("delete_rule", uint8(), false)});
+}
+
+std::shared_ptr<Schema> SqlSchema::GetImportedKeysSchema() {
+ return GetImportedExportedKeysAndCrossReferenceSchema();
+}
+
+std::shared_ptr<Schema> SqlSchema::GetExportedKeysSchema() {
+ return GetImportedExportedKeysAndCrossReferenceSchema();
+}
+
+std::shared_ptr<Schema> SqlSchema::GetCrossReferenceSchema() {
+ return GetImportedExportedKeysAndCrossReferenceSchema();
+}
+
+std::shared_ptr<Schema> SqlSchema::GetSqlInfoSchema() {
+ return arrow::schema({field("name", uint32(), false),
+ field("value",
+ dense_union({field("string_value", utf8(), false),
+ field("bool_value", boolean(), false),
+ field("bigint_value", int64(), false),
+ field("int32_bitmask", int32(), false),
+ field("string_list", list(utf8()), false),
+ field("int32_to_int32_list_map",
+ map(int32(), list(int32())), false)}),
+ false)});
+}
+
+} // namespace sql
+} // namespace flight
+} // namespace arrow
+
+#undef PROPERTY_TO_OPTIONAL
diff --git a/cpp/src/arrow/flight/sql/server.h b/cpp/src/arrow/flight/sql/server.h
new file mode 100644
index 0000000..1d61016
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/server.h
@@ -0,0 +1,443 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// Interfaces to use for defining Flight RPC servers. API should be considered
+// experimental for now
+
+#pragma once
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include "arrow/flight/server.h"
+#include "arrow/flight/sql/server.h"
+#include "arrow/flight/sql/types.h"
+#include "arrow/util/optional.h"
+
+namespace arrow {
+namespace flight {
+namespace sql {
+
+struct StatementQuery {
+ std::string query;
+};
+
+struct StatementUpdate {
+ std::string query;
+};
+
+struct StatementQueryTicket {
+ std::string statement_handle;
+};
+
+struct PreparedStatementQuery {
+ std::string prepared_statement_handle;
+};
+
+struct PreparedStatementUpdate {
+ std::string prepared_statement_handle;
+};
+
+struct GetSqlInfo {
+ std::vector<int32_t> info;
+};
+
+struct GetDbSchemas {
+ util::optional<std::string> catalog;
+ util::optional<std::string> db_schema_filter_pattern;
+};
+
+struct GetTables {
+ util::optional<std::string> catalog;
+ util::optional<std::string> db_schema_filter_pattern;
+ util::optional<std::string> table_name_filter_pattern;
+ std::vector<std::string> table_types;
+ bool include_schema;
+};
+
+struct GetPrimaryKeys {
+ TableRef table_ref;
+};
+
+struct GetExportedKeys {
+ TableRef table_ref;
+};
+
+struct GetImportedKeys {
+ TableRef table_ref;
+};
+
+struct GetCrossReference {
+ TableRef pk_table_ref;
+ TableRef fk_table_ref;
+};
+
+struct ActionCreatePreparedStatementRequest {
+ std::string query;
+};
+
+struct ActionClosePreparedStatementRequest {
+ std::string prepared_statement_handle;
+};
+
+struct ActionCreatePreparedStatementResult {
+ std::shared_ptr<Schema> dataset_schema;
+ std::shared_ptr<Schema> parameter_schema;
+ std::string prepared_statement_handle;
+};
+
+/// \brief A utility function to create a ticket (a opaque binary token that the server
+/// uses to identify this query) for a statement query.
+/// Intended for Flight SQL server implementations.
+/// \param[in] statement_handle The statement handle that will originate the ticket.
+/// \return The parsed ticket as an string.
+arrow::Result<std::string> CreateStatementQueryTicket(
+ const std::string& statement_handle);
+
+class ARROW_EXPORT FlightSqlServerBase : public FlightServerBase {
+ private:
+ SqlInfoResultMap sql_info_id_to_result_;
+
+ public:
+ Status GetFlightInfo(const ServerCallContext& context, const FlightDescriptor& request,
+ std::unique_ptr<FlightInfo>* info) override;
+
+ Status DoGet(const ServerCallContext& context, const Ticket& request,
+ std::unique_ptr<FlightDataStream>* stream) override;
+
+ Status DoPut(const ServerCallContext& context,
+ std::unique_ptr<FlightMessageReader> reader,
+ std::unique_ptr<FlightMetadataWriter> writer) override;
+
+ const ActionType kCreatePreparedStatementActionType =
+ ActionType{"CreatePreparedStatement",
+ "Creates a reusable prepared statement resource on the server.\n"
+ "Request Message: ActionCreatePreparedStatementRequest\n"
+ "Response Message: ActionCreatePreparedStatementResult"};
+ const ActionType kClosePreparedStatementActionType =
+ ActionType{"ClosePreparedStatement",
+ "Closes a reusable prepared statement resource on the server.\n"
+ "Request Message: ActionClosePreparedStatementRequest\n"
+ "Response Message: N/A"};
+
+ Status ListActions(const ServerCallContext& context,
+ std::vector<ActionType>* actions) override;
+
+ Status DoAction(const ServerCallContext& context, const Action& action,
+ std::unique_ptr<ResultStream>* result) override;
+
+ /// \brief Get a FlightInfo for executing a SQL query.
+ /// \param[in] context Per-call context.
+ /// \param[in] command The StatementQuery object containing the SQL statement.
+ /// \param[in] descriptor The descriptor identifying the data stream.
+ /// \return The FlightInfo describing where to access the dataset.
+ virtual arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoStatement(
+ const ServerCallContext& context, const StatementQuery& command,
+ const FlightDescriptor& descriptor);
+
+ /// \brief Get a FlightDataStream containing the query results.
+ /// \param[in] context Per-call context.
+ /// \param[in] command The StatementQueryTicket containing the statement handle.
+ /// \return The FlightDataStream containing the results.
+ virtual arrow::Result<std::unique_ptr<FlightDataStream>> DoGetStatement(
+ const ServerCallContext& context, const StatementQueryTicket& command);
+
+ /// \brief Get a FlightInfo for executing an already created prepared statement.
+ /// \param[in] context Per-call context.
+ /// \param[in] command The PreparedStatementQuery object containing the
+ /// prepared statement handle.
+ /// \param[in] descriptor The descriptor identifying the data stream.
+ /// \return The FlightInfo describing where to access the
+ /// dataset.
+ virtual arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoPreparedStatement(
+ const ServerCallContext& context, const PreparedStatementQuery& command,
+ const FlightDescriptor& descriptor);
+
+ /// \brief Get a FlightDataStream containing the prepared statement query results.
+ /// \param[in] context Per-call context.
+ /// \param[in] command The PreparedStatementQuery object containing the
+ /// prepared statement handle.
+ /// \return The FlightDataStream containing the results.
+ virtual arrow::Result<std::unique_ptr<FlightDataStream>> DoGetPreparedStatement(
+ const ServerCallContext& context, const PreparedStatementQuery& command);
+
+ /// \brief Get a FlightInfo for listing catalogs.
+ /// \param[in] context Per-call context.
+ /// \param[in] descriptor The descriptor identifying the data stream.
+ /// \return The FlightInfo describing where to access the dataset.
+ virtual arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoCatalogs(
+ const ServerCallContext& context, const FlightDescriptor& descriptor);
+
+ /// \brief Get a FlightDataStream containing the list of catalogs.
+ /// \param[in] context Per-call context.
+ /// \return An interface for sending data back to the client.
+ virtual arrow::Result<std::unique_ptr<FlightDataStream>> DoGetCatalogs(
+ const ServerCallContext& context);
+
+ /// \brief Get a FlightInfo for retrieving other information (See SqlInfo).
+ /// \param[in] context Per-call context.
+ /// \param[in] command The GetSqlInfo object containing the list of SqlInfo
+ /// to be returned.
+ /// \param[in] descriptor The descriptor identifying the data stream.
+ /// \return The FlightInfo describing where to access the dataset.
+ virtual arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoSqlInfo(
+ const ServerCallContext& context, const GetSqlInfo& command,
+ const FlightDescriptor& descriptor);
+
+ /// \brief Get a FlightDataStream containing the list of SqlInfo results.
+ /// \param[in] context Per-call context.
+ /// \param[in] command The GetSqlInfo object containing the list of SqlInfo
+ /// to be returned.
+ /// \return The FlightDataStream containing the results.
+ virtual arrow::Result<std::unique_ptr<FlightDataStream>> DoGetSqlInfo(
+ const ServerCallContext& context, const GetSqlInfo& command);
+
+ /// \brief Get a FlightInfo for listing schemas.
+ /// \param[in] context Per-call context.
+ /// \param[in] command The GetDbSchemas object which may contain filters for
+ /// catalog and schema name.
+ /// \param[in] descriptor The descriptor identifying the data stream.
+ /// \return The FlightInfo describing where to access the dataset.
+ virtual arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoSchemas(
+ const ServerCallContext& context, const GetDbSchemas& command,
+ const FlightDescriptor& descriptor);
+
+ /// \brief Get a FlightDataStream containing the list of schemas.
+ /// \param[in] context Per-call context.
+ /// \param[in] command The GetDbSchemas object which may contain filters for
+ /// catalog and schema name.
+ /// \return The FlightDataStream containing the results.
+ virtual arrow::Result<std::unique_ptr<FlightDataStream>> DoGetDbSchemas(
+ const ServerCallContext& context, const GetDbSchemas& command);
+
+ ///\brief Get a FlightInfo for listing tables.
+ /// \param[in] context Per-call context.
+ /// \param[in] command The GetTables object which may contain filters for
+ /// catalog, schema and table names.
+ /// \param[in] descriptor The descriptor identifying the data stream.
+ /// \return The FlightInfo describing where to access the dataset.
+ virtual arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoTables(
+ const ServerCallContext& context, const GetTables& command,
+ const FlightDescriptor& descriptor);
+
+ /// \brief Get a FlightDataStream containing the list of tables.
+ /// \param[in] context Per-call context.
+ /// \param[in] command The GetTables object which may contain filters for
+ /// catalog, schema and table names.
+ /// \return The FlightDataStream containing the results.
+ virtual arrow::Result<std::unique_ptr<FlightDataStream>> DoGetTables(
+ const ServerCallContext& context, const GetTables& command);
+
+ /// \brief Get a FlightInfo to extract information about the table types.
+ /// \param[in] context Per-call context.
+ /// \param[in] descriptor The descriptor identifying the data stream.
+ /// \return The FlightInfo describing where to access the
+ /// dataset.
+ virtual arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoTableTypes(
+ const ServerCallContext& context, const FlightDescriptor& descriptor);
+
+ /// \brief Get a FlightDataStream containing the data related to the table types.
+ /// \param[in] context Per-call context.
+ /// \return The FlightDataStream containing the results.
+ virtual arrow::Result<std::unique_ptr<FlightDataStream>> DoGetTableTypes(
+ const ServerCallContext& context);
+
+ /// \brief Get a FlightInfo to extract information about primary and foreign keys.
+ /// \param[in] context Per-call context.
+ /// \param[in] command The GetPrimaryKeys object with necessary information
+ /// to execute the request.
+ /// \param[in] descriptor The descriptor identifying the data stream.
+ /// \return The FlightInfo describing where to access the
+ /// dataset.
+ virtual arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoPrimaryKeys(
+ const ServerCallContext& context, const GetPrimaryKeys& command,
+ const FlightDescriptor& descriptor);
+
+ /// \brief Get a FlightDataStream containing the data related to the primary and
+ /// foreign
+ /// keys.
+ /// \param[in] context Per-call context.
+ /// \param[in] command The GetPrimaryKeys object with necessary information
+ /// to execute the request.
+ /// \return The FlightDataStream containing the results.
+ virtual arrow::Result<std::unique_ptr<FlightDataStream>> DoGetPrimaryKeys(
+ const ServerCallContext& context, const GetPrimaryKeys& command);
+
+ /// \brief Get a FlightInfo to extract information about foreign and primary keys.
+ /// \param[in] context Per-call context.
+ /// \param[in] command The GetExportedKeys object with necessary information
+ /// to execute the request.
+ /// \param[in] descriptor The descriptor identifying the data stream.
+ /// \return The FlightInfo describing where to access the
+ /// dataset.
+ virtual arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoExportedKeys(
+ const ServerCallContext& context, const GetExportedKeys& command,
+ const FlightDescriptor& descriptor);
+
+ /// \brief Get a FlightDataStream containing the data related to the foreign and
+ /// primary
+ /// keys.
+ /// \param[in] context Per-call context.
+ /// \param[in] command The GetExportedKeys object with necessary information
+ /// to execute the request.
+ /// \return The FlightDataStream containing the results.
+ virtual arrow::Result<std::unique_ptr<FlightDataStream>> DoGetExportedKeys(
+ const ServerCallContext& context, const GetExportedKeys& command);
+
+ /// \brief Get a FlightInfo to extract information about foreign and primary keys.
+ /// \param[in] context Per-call context.
+ /// \param[in] command The GetImportedKeys object with necessary information
+ /// to execute the request.
+ /// \param[in] descriptor The descriptor identifying the data stream.
+ /// \return The FlightInfo describing where to access the
+ /// dataset.
+ virtual arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoImportedKeys(
+ const ServerCallContext& context, const GetImportedKeys& command,
+ const FlightDescriptor& descriptor);
+
+ /// \brief Get a FlightDataStream containing the data related to the foreign and
+ /// primary keys.
+ /// \param[in] context Per-call context.
+ /// \param[in] command The GetImportedKeys object with necessary information
+ /// to execute the request.
+ /// \return The FlightDataStream containing the results.
+ virtual arrow::Result<std::unique_ptr<FlightDataStream>> DoGetImportedKeys(
+ const ServerCallContext& context, const GetImportedKeys& command);
+
+ /// \brief Get a FlightInfo to extract information about foreign and primary keys.
+ /// \param[in] context Per-call context.
+ /// \param[in] command The GetCrossReference object with necessary
+ /// information
+ /// to execute the request.
+ /// \param[in] descriptor The descriptor identifying the data stream.
+ /// \return The FlightInfo describing where to access the
+ /// dataset.
+ virtual arrow::Result<std::unique_ptr<FlightInfo>> GetFlightInfoCrossReference(
+ const ServerCallContext& context, const GetCrossReference& command,
+ const FlightDescriptor& descriptor);
+
+ /// \brief Get a FlightDataStream containing the data related to the foreign and
+ /// primary keys.
+ /// \param[in] context Per-call context.
+ /// \param[in] command The GetCrossReference object with necessary information
+ /// to execute the request.
+ /// \return The FlightDataStream containing the results.
+ virtual arrow::Result<std::unique_ptr<FlightDataStream>> DoGetCrossReference(
+ const ServerCallContext& context, const GetCrossReference& command);
+
+ /// \brief Execute an update SQL statement.
+ /// \param[in] context The call context.
+ /// \param[in] command The StatementUpdate object containing the SQL statement.
+ /// \return The changed record count.
+ virtual arrow::Result<int64_t> DoPutCommandStatementUpdate(
+ const ServerCallContext& context, const StatementUpdate& command);
+
+ /// \brief Create a prepared statement from given SQL statement.
+ /// \param[in] context The call context.
+ /// \param[in] request The ActionCreatePreparedStatementRequest object containing the
+ /// SQL statement.
+ /// \return A ActionCreatePreparedStatementResult containing the dataset
+ /// and parameter schemas and a handle for created statement.
+ virtual arrow::Result<ActionCreatePreparedStatementResult> CreatePreparedStatement(
+ const ServerCallContext& context,
+ const ActionCreatePreparedStatementRequest& request);
+
+ /// \brief Close a prepared statement.
+ /// \param[in] context The call context.
+ /// \param[in] request The ActionClosePreparedStatementRequest object containing the
+ /// prepared statement handle.
+ virtual Status ClosePreparedStatement(
+ const ServerCallContext& context,
+ const ActionClosePreparedStatementRequest& request);
+
+ /// \brief Bind parameters to given prepared statement.
+ /// \param[in] context The call context.
+ /// \param[in] command The PreparedStatementQuery object containing the
+ /// prepared statement handle.
+ /// \param[in] reader A sequence of uploaded record batches.
+ /// \param[in] writer Send metadata back to the client.
+ virtual Status DoPutPreparedStatementQuery(const ServerCallContext& context,
+ const PreparedStatementQuery& command,
+ FlightMessageReader* reader,
+ FlightMetadataWriter* writer);
+
+ /// \brief Execute an update SQL prepared statement.
+ /// \param[in] context The call context.
+ /// \param[in] command The PreparedStatementUpdate object containing the
+ /// prepared statement handle.
+ /// \param[in] reader a sequence of uploaded record batches.
+ /// \return The changed record count.
+ virtual arrow::Result<int64_t> DoPutPreparedStatementUpdate(
+ const ServerCallContext& context, const PreparedStatementUpdate& command,
+ FlightMessageReader* reader);
+
+ /// \brief Register a new SqlInfo result, making it available when calling GetSqlInfo.
+ /// \param[in] id the SqlInfo identifier.
+ /// \param[in] result the result.
+ void RegisterSqlInfo(int32_t id, const SqlInfoResult& result);
+};
+
+/// \brief Auxiliary class containing all Schemas used on Flight SQL.
+class ARROW_EXPORT SqlSchema {
+ public:
+ /// \brief Get the Schema used on GetCatalogs response.
+ /// \return The default schema template.
+ static std::shared_ptr<Schema> GetCatalogsSchema();
+
+ /// \brief Get the Schema used on GetDbSchemas response.
+ /// \return The default schema template.
+ static std::shared_ptr<Schema> GetDbSchemasSchema();
+
+ /// \brief Get the Schema used on GetTables response when included schema
+ /// flags is set to false.
+ /// \return The default schema template.
+ static std::shared_ptr<Schema> GetTablesSchema();
+
+ /// \brief Get the Schema used on GetTables response when included schema
+ /// flags is set to true.
+ /// \return The default schema template.
+ static std::shared_ptr<Schema> GetTablesSchemaWithIncludedSchema();
+
+ /// \brief Get the Schema used on GetTableTypes response.
+ /// \return The default schema template.
+ static std::shared_ptr<Schema> GetTableTypesSchema();
+
+ /// \brief Get the Schema used on GetPrimaryKeys response when included schema
+ /// flags is set to true.
+ /// \return The default schema template.
+ static std::shared_ptr<Schema> GetPrimaryKeysSchema();
+
+ /// \brief Get the Schema used on GetImportedKeys response.
+ /// \return The default schema template.
+ static std::shared_ptr<Schema> GetExportedKeysSchema();
+
+ /// \brief Get the Schema used on GetImportedKeys response.
+ /// \return The default schema template.
+ static std::shared_ptr<Schema> GetImportedKeysSchema();
+
+ /// \brief Get the Schema used on GetCrossReference response.
+ /// \return The default schema template.
+ static std::shared_ptr<Schema> GetCrossReferenceSchema();
+
+ /// \brief Get the Schema used on GetSqlInfo response.
+ /// \return The default schema template.
+ static std::shared_ptr<Schema> GetSqlInfoSchema();
+};
+} // namespace sql
+} // namespace flight
+} // namespace arrow
diff --git a/cpp/src/arrow/flight/sql/server_test.cc b/cpp/src/arrow/flight/sql/server_test.cc
new file mode 100644
index 0000000..8dfea7a
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/server_test.cc
@@ -0,0 +1,767 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "arrow/flight/sql/server.h"
+
+#include <arrow/util/logging.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <condition_variable>
+#include <thread>
+
+#include "arrow/flight/api.h"
+#include "arrow/flight/sql/api.h"
+#include "arrow/flight/sql/example/sqlite_server.h"
+#include "arrow/flight/sql/example/sqlite_sql_info.h"
+#include "arrow/flight/test_util.h"
+#include "arrow/flight/types.h"
+#include "arrow/testing/gtest_util.h"
+
+using ::testing::_;
+using ::testing::Ref;
+
+using arrow::internal::checked_cast;
+
+namespace arrow {
+namespace flight {
+namespace sql {
+
+/// \brief Auxiliary variant visitor used to assert that GetSqlInfo's values are
+/// correctly placed on its DenseUnionArray
+class SqlInfoDenseUnionValidator {
+ private:
+ const DenseUnionScalar& data;
+
+ public:
+ /// \brief Asserts that the current DenseUnionScalar equals to given string value
+ void operator()(const std::string& string_value) const {
+ const auto& scalar = checked_cast<const StringScalar&>(*data.value);
+ ASSERT_EQ(string_value, scalar.ToString());
+ }
+
+ /// \brief Asserts that the current DenseUnionScalar equals to given bool value
+ void operator()(const bool bool_value) const {
+ const auto& scalar = checked_cast<const BooleanScalar&>(*data.value);
+ ASSERT_EQ(bool_value, scalar.value);
+ }
+
+ /// \brief Asserts that the current DenseUnionScalar equals to given int64_t value
+ void operator()(const int64_t bigint_value) const {
+ const auto& scalar = checked_cast<const Int64Scalar&>(*data.value);
+ ASSERT_EQ(bigint_value, scalar.value);
+ }
+
+ /// \brief Asserts that the current DenseUnionScalar equals to given int32_t value
+ void operator()(const int32_t int32_bitmask) const {
+ const auto& scalar = checked_cast<const Int32Scalar&>(*data.value);
+ ASSERT_EQ(int32_bitmask, scalar.value);
+ }
+
+ /// \brief Asserts that the current DenseUnionScalar equals to given string list
+ void operator()(const std::vector<std::string>& string_list) const {
+ const auto& array = checked_cast<const StringArray&>(
+ *(checked_cast<const ListScalar&>(*data.value).value));
+
+ ASSERT_EQ(string_list.size(), array.length());
+
+ for (size_t index = 0; index < string_list.size(); index++) {
+ ASSERT_EQ(string_list[index], array.GetString(index));
+ }
+ }
+
+ /// \brief Asserts that the current DenseUnionScalar equals to given int32 to int32 list
+ /// map.
+ void operator()(const std::unordered_map<int32_t, std::vector<int32_t>>&
+ int32_to_int32_list) const {
+ const auto& struct_array = checked_cast<const StructArray&>(
+ *checked_cast<const MapScalar&>(*data.value).value);
+ const auto& keys = checked_cast<const Int32Array&>(*struct_array.field(0));
+ const auto& values = checked_cast<const ListArray&>(*struct_array.field(1));
+
+ // Assert that the given map has the right size
+ ASSERT_EQ(int32_to_int32_list.size(), keys.length());
+
+ // For each element on given MapScalar, assert it matches the argument
+ for (int i = 0; i < keys.length(); i++) {
+ ASSERT_OK_AND_ASSIGN(const auto& key_scalar, keys.GetScalar(i));
+ int32_t sql_info_id = checked_cast<const Int32Scalar&>(*key_scalar).value;
+
+ // Assert the key (SqlInfo id) exists
+ ASSERT_TRUE(int32_to_int32_list.count(sql_info_id));
+
+ const std::vector<int32_t>& expected_int32_list =
+ int32_to_int32_list.at(sql_info_id);
+
+ // Assert the value (int32 list) has the correct size
+ ASSERT_EQ(expected_int32_list.size(), values.value_length(i));
+
+ // For each element on current ListScalar, assert it matches with the argument
+ for (size_t j = 0; j < expected_int32_list.size(); j++) {
+ ASSERT_OK_AND_ASSIGN(auto list_item_scalar,
+ values.values()->GetScalar(values.value_offset(i) + j));
+ const auto& list_item = checked_cast<const Int32Scalar&>(*list_item_scalar).value;
+ ASSERT_EQ(expected_int32_list[j], list_item);
+ }
+ }
+ }
+
+ explicit SqlInfoDenseUnionValidator(const DenseUnionScalar& data) : data(data) {}
+
+ SqlInfoDenseUnionValidator(const SqlInfoDenseUnionValidator&) = delete;
+ SqlInfoDenseUnionValidator(SqlInfoDenseUnionValidator&&) = delete;
+ SqlInfoDenseUnionValidator& operator=(const SqlInfoDenseUnionValidator&) = delete;
+};
+
+class TestFlightSqlServer : public ::testing::Test {
+ public:
+ std::unique_ptr<FlightSqlClient> sql_client;
+
+ arrow::Result<int64_t> ExecuteCountQuery(const std::string& query) {
+ ARROW_ASSIGN_OR_RAISE(auto flight_info, sql_client->Execute({}, query));
+
+ ARROW_ASSIGN_OR_RAISE(auto stream,
+ sql_client->DoGet({}, flight_info->endpoints()[0].ticket));
+
+ std::shared_ptr<Table> table;
+ ARROW_RETURN_NOT_OK(stream->ReadAll(&table));
+
+ const std::shared_ptr<Array>& result_array = table->column(0)->chunk(0);
+ ARROW_ASSIGN_OR_RAISE(auto count_scalar, result_array->GetScalar(0));
+
+ return reinterpret_cast<Int64Scalar&>(*count_scalar).value;
+ }
+
+ protected:
+ void SetUp() override {
+ port = GetListenPort();
+ server_thread.reset(new std::thread([&]() { RunServer(); }));
+
+ std::unique_lock<std::mutex> lk(server_ready_m);
+ server_ready_cv.wait(lk);
+
+ std::stringstream ss;
+ ss << "grpc://localhost:" << port;
+ std::string uri = ss.str();
+
+ std::unique_ptr<FlightClient> client;
+ Location location;
+ ASSERT_OK(Location::Parse(uri, &location));
+ ASSERT_OK(FlightClient::Connect(location, &client));
+
+ sql_client.reset(new FlightSqlClient(std::move(client)));
+ }
+
+ void TearDown() override {
+ sql_client.reset();
+
+ ASSERT_OK(server->Shutdown());
+ server_thread->join();
+ server_thread.reset();
+ }
+
+ private:
+ int port;
+ std::shared_ptr<arrow::flight::sql::example::SQLiteFlightSqlServer> server;
+ std::unique_ptr<std::thread> server_thread;
+ std::condition_variable server_ready_cv;
+ std::mutex server_ready_m;
+
+ void RunServer() {
+ arrow::flight::Location location;
+ ARROW_CHECK_OK(arrow::flight::Location::ForGrpcTcp("localhost", port, &location));
+ arrow::flight::FlightServerOptions options(location);
+
+ ARROW_CHECK_OK(example::SQLiteFlightSqlServer::Create().Value(&server));
+
+ ARROW_CHECK_OK(server->Init(options));
+ // Exit with a clean error code (0) on SIGTERM
+ ARROW_CHECK_OK(server->SetShutdownOnSignals({SIGTERM}));
+
+ server_ready_cv.notify_all();
+ ARROW_CHECK_OK(server->Serve());
+ }
+};
+
+TEST_F(TestFlightSqlServer, TestCommandStatementQuery) {
+ ASSERT_OK_AND_ASSIGN(auto flight_info,
+ sql_client->Execute({}, "SELECT * FROM intTable"));
+
+ ASSERT_OK_AND_ASSIGN(auto stream,
+ sql_client->DoGet({}, flight_info->endpoints()[0].ticket));
+
+ std::shared_ptr<Table> table;
+ ASSERT_OK(stream->ReadAll(&table));
+
+ const std::shared_ptr<Schema>& expected_schema =
+ arrow::schema({arrow::field("id", int64()), arrow::field("keyName", utf8()),
+ arrow::field("value", int64()), arrow::field("foreignId", int64())});
+
+ const auto id_array = ArrayFromJSON(int64(), R"([1, 2, 3, 4])");
+ const auto keyname_array =
+ ArrayFromJSON(utf8(), R"(["one", "zero", "negative one", null])");
+ const auto value_array = ArrayFromJSON(int64(), R"([1, 0, -1, null])");
+ const auto foreignId_array = ArrayFromJSON(int64(), R"([1, 1, 1, null])");
+
+ const std::shared_ptr<Table>& expected_table = Table::Make(
+ expected_schema, {id_array, keyname_array, value_array, foreignId_array});
+
+ AssertTablesEqual(*expected_table, *table);
+}
+
+TEST_F(TestFlightSqlServer, TestCommandGetTables) {
+ FlightCallOptions options = {};
+ std::string* catalog = nullptr;
+ std::string* schema_filter_pattern = nullptr;
+ std::string* table_filter_pattern = nullptr;
+ bool include_schema = false;
+ std::vector<std::string>* table_types = nullptr;
+
+ ASSERT_OK_AND_ASSIGN(
+ auto flight_info,
+ sql_client->GetTables(options, catalog, schema_filter_pattern, table_filter_pattern,
+ include_schema, table_types));
+
+ ASSERT_OK_AND_ASSIGN(auto stream,
+ sql_client->DoGet({}, flight_info->endpoints()[0].ticket));
+
+ std::shared_ptr<Table> table;
+ ASSERT_OK(stream->ReadAll(&table));
+
+ ASSERT_OK_AND_ASSIGN(auto catalog_name, MakeArrayOfNull(utf8(), 3))
+ ASSERT_OK_AND_ASSIGN(auto schema_name, MakeArrayOfNull(utf8(), 3))
+
+ const auto table_name =
+ ArrayFromJSON(utf8(), R"(["foreignTable", "intTable", "sqlite_sequence"])");
+ const auto table_type = ArrayFromJSON(utf8(), R"(["table", "table", "table"])");
+
+ const std::shared_ptr<Table>& expected_table = Table::Make(
+ SqlSchema::GetTablesSchema(), {catalog_name, schema_name, table_name, table_type});
+
+ AssertTablesEqual(*expected_table, *table);
+}
+
+TEST_F(TestFlightSqlServer, TestCommandGetTablesWithTableFilter) {
+ FlightCallOptions options = {};
+ std::string* catalog = nullptr;
+ std::string* schema_filter_pattern = nullptr;
+ std::string table_filter_pattern = "int%";
+ bool include_schema = false;
+ std::vector<std::string>* table_types = nullptr;
+
+ ASSERT_OK_AND_ASSIGN(
+ auto flight_info,
+ sql_client->GetTables(options, catalog, schema_filter_pattern,
+ &table_filter_pattern, include_schema, table_types));
+
+ ASSERT_OK_AND_ASSIGN(auto stream,
+ sql_client->DoGet({}, flight_info->endpoints()[0].ticket));
+
+ std::shared_ptr<Table> table;
+ ASSERT_OK(stream->ReadAll(&table));
+
+ const auto catalog_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto schema_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto table_name = ArrayFromJSON(utf8(), R"(["intTable"])");
+ const auto table_type = ArrayFromJSON(utf8(), R"(["table"])");
+
+ const std::shared_ptr<Table>& expected_table = Table::Make(
+ SqlSchema::GetTablesSchema(), {catalog_name, schema_name, table_name, table_type});
+
+ AssertTablesEqual(*expected_table, *table);
+}
+
+TEST_F(TestFlightSqlServer, TestCommandGetTablesWithTableTypesFilter) {
+ FlightCallOptions options = {};
+ std::string* catalog = nullptr;
+ std::string* schema_filter_pattern = nullptr;
+ std::string* table_filter_pattern = nullptr;
+ bool include_schema = false;
+ std::vector<std::string> table_types{"index"};
+
+ ASSERT_OK_AND_ASSIGN(
+ auto flight_info,
+ sql_client->GetTables(options, catalog, schema_filter_pattern, table_filter_pattern,
+ include_schema, &table_types));
+
+ ASSERT_OK_AND_ASSIGN(auto stream,
+ sql_client->DoGet({}, flight_info->endpoints()[0].ticket));
+
+ std::shared_ptr<Table> table;
+ ASSERT_OK(stream->ReadAll(&table));
+
+ AssertSchemaEqual(SqlSchema::GetTablesSchema(), table->schema());
+
+ ASSERT_EQ(table->num_rows(), 0);
+}
+
+TEST_F(TestFlightSqlServer, TestCommandGetTablesWithUnexistenceTableTypeFilter) {
+ FlightCallOptions options = {};
+ std::string* catalog = nullptr;
+ std::string* schema_filter_pattern = nullptr;
+ std::string* table_filter_pattern = nullptr;
+ bool include_schema = false;
+ std::vector<std::string> table_types{"table"};
+
+ ASSERT_OK_AND_ASSIGN(
+ auto flight_info,
+ sql_client->GetTables(options, catalog, schema_filter_pattern, table_filter_pattern,
+ include_schema, &table_types));
+
+ ASSERT_OK_AND_ASSIGN(auto stream,
+ sql_client->DoGet({}, flight_info->endpoints()[0].ticket));
+
+ std::shared_ptr<Table> table;
+ ASSERT_OK(stream->ReadAll(&table));
+
+ const auto catalog_name = ArrayFromJSON(utf8(), R"([null, null, null])");
+ const auto schema_name = ArrayFromJSON(utf8(), R"([null, null, null])");
+ const auto table_name =
+ ArrayFromJSON(utf8(), R"(["foreignTable", "intTable", "sqlite_sequence"])");
+ const auto table_type = ArrayFromJSON(utf8(), R"(["table", "table", "table"])");
+
+ const std::shared_ptr<Table>& expected_table = Table::Make(
+ SqlSchema::GetTablesSchema(), {catalog_name, schema_name, table_name, table_type});
+
+ AssertTablesEqual(*expected_table, *table);
+}
+
+TEST_F(TestFlightSqlServer, TestCommandGetTablesWithIncludedSchemas) {
+ FlightCallOptions options = {};
+ std::string* catalog = nullptr;
+ std::string* schema_filter_pattern = nullptr;
+ std::string table_filter_pattern = "int%";
+ bool include_schema = true;
+ std::vector<std::string>* table_types = nullptr;
+
+ ASSERT_OK_AND_ASSIGN(
+ auto flight_info,
+ sql_client->GetTables(options, catalog, schema_filter_pattern,
+ &table_filter_pattern, include_schema, table_types));
+
+ ASSERT_OK_AND_ASSIGN(auto stream,
+ sql_client->DoGet({}, flight_info->endpoints()[0].ticket));
+
+ std::shared_ptr<Table> table;
+ ASSERT_OK(stream->ReadAll(&table));
+
+ const auto catalog_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto schema_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto table_name = ArrayFromJSON(utf8(), R"(["intTable"])");
+ const auto table_type = ArrayFromJSON(utf8(), R"(["table"])");
+
+ const std::shared_ptr<Schema> schema_table = arrow::schema(
+ {arrow::field("id", int64(), true), arrow::field("keyName", utf8(), true),
+ arrow::field("value", int64(), true), arrow::field("foreignId", int64(), true)});
+
+ ASSERT_OK_AND_ASSIGN(auto schema_buffer, ipc::SerializeSchema(*schema_table));
+
+ std::shared_ptr<Array> table_schema;
+ ArrayFromVector<BinaryType, std::string>({schema_buffer->ToString()}, &table_schema);
+
+ const std::shared_ptr<Table>& expected_table =
+ Table::Make(SqlSchema::GetTablesSchemaWithIncludedSchema(),
+ {catalog_name, schema_name, table_name, table_type, table_schema});
+
+ AssertTablesEqual(*expected_table, *table);
+}
+
+TEST_F(TestFlightSqlServer, TestCommandGetCatalogs) {
+ ASSERT_OK_AND_ASSIGN(auto flight_info, sql_client->GetCatalogs({}));
+
+ ASSERT_OK_AND_ASSIGN(auto stream,
+ sql_client->DoGet({}, flight_info->endpoints()[0].ticket));
+
+ std::shared_ptr<Table> table;
+ ASSERT_OK(stream->ReadAll(&table));
+
+ const std::shared_ptr<Schema>& expected_schema = SqlSchema::GetCatalogsSchema();
+
+ AssertSchemaEqual(expected_schema, table->schema());
+ ASSERT_EQ(0, table->num_rows());
+}
+
+TEST_F(TestFlightSqlServer, TestCommandGetDbSchemas) {
+ FlightCallOptions options = {};
+ std::string* catalog = nullptr;
+ std::string* schema_filter_pattern = nullptr;
+ ASSERT_OK_AND_ASSIGN(auto flight_info,
+ sql_client->GetDbSchemas(options, catalog, schema_filter_pattern));
+
+ ASSERT_OK_AND_ASSIGN(auto stream,
+ sql_client->DoGet({}, flight_info->endpoints()[0].ticket));
+
+ std::shared_ptr<Table> table;
+ ASSERT_OK(stream->ReadAll(&table));
+
+ const std::shared_ptr<Schema>& expected_schema = SqlSchema::GetDbSchemasSchema();
+
+ AssertSchemaEqual(expected_schema, table->schema());
+ ASSERT_EQ(0, table->num_rows());
+}
+
+TEST_F(TestFlightSqlServer, TestCommandGetTableTypes) {
+ ASSERT_OK_AND_ASSIGN(auto flight_info, sql_client->GetTableTypes({}));
+
+ ASSERT_OK_AND_ASSIGN(auto stream,
+ sql_client->DoGet({}, flight_info->endpoints()[0].ticket));
+
+ std::shared_ptr<Table> table;
+ ASSERT_OK(stream->ReadAll(&table));
+
+ const auto table_type = ArrayFromJSON(utf8(), R"(["table"])");
+
+ const std::shared_ptr<Table>& expected_table =
+ Table::Make(SqlSchema::GetTableTypesSchema(), {table_type});
+ AssertTablesEqual(*expected_table, *table);
+}
+
+TEST_F(TestFlightSqlServer, TestCommandStatementUpdate) {
+ int64_t result;
+ ASSERT_OK_AND_ASSIGN(result,
+ sql_client->ExecuteUpdate(
+ {},
+ "INSERT INTO intTable (keyName, value) VALUES "
+ "('KEYNAME1', 1001), ('KEYNAME2', 1002), ('KEYNAME3', 1003)"));
+ ASSERT_EQ(3, result);
+
+ ASSERT_OK_AND_ASSIGN(result, sql_client->ExecuteUpdate(
+ {},
+ "UPDATE intTable SET keyName = 'KEYNAME1' "
+ "WHERE keyName = 'KEYNAME2' OR keyName = 'KEYNAME3'"));
+ ASSERT_EQ(2, result);
+
+ ASSERT_OK_AND_ASSIGN(
+ result,
+ sql_client->ExecuteUpdate({}, "DELETE FROM intTable WHERE keyName = 'KEYNAME1'"));
+ ASSERT_EQ(3, result);
+}
+
+TEST_F(TestFlightSqlServer, TestCommandPreparedStatementQuery) {
+ ASSERT_OK_AND_ASSIGN(auto prepared_statement,
+ sql_client->Prepare({}, "SELECT * FROM intTable"));
+
+ ASSERT_OK_AND_ASSIGN(auto flight_info, prepared_statement->Execute());
+
+ ASSERT_OK_AND_ASSIGN(auto stream,
+ sql_client->DoGet({}, flight_info->endpoints()[0].ticket));
+
+ std::shared_ptr<Table> table;
+ ASSERT_OK(stream->ReadAll(&table));
+
+ const std::shared_ptr<Schema>& expected_schema =
+ arrow::schema({arrow::field("id", int64()), arrow::field("keyName", utf8()),
+ arrow::field("value", int64()), arrow::field("foreignId", int64())});
+
+ const auto id_array = ArrayFromJSON(int64(), R"([1, 2, 3, 4])");
+ const auto keyname_array =
+ ArrayFromJSON(utf8(), R"(["one", "zero", "negative one", null])");
+ const auto value_array = ArrayFromJSON(int64(), R"([1, 0, -1, null])");
+ const auto foreignId_array = ArrayFromJSON(int64(), R"([1, 1, 1, null])");
+
+ const std::shared_ptr<Table>& expected_table = Table::Make(
+ expected_schema, {id_array, keyname_array, value_array, foreignId_array});
+
+ AssertTablesEqual(*expected_table, *table);
+}
+
+TEST_F(TestFlightSqlServer, TestCommandPreparedStatementQueryWithParameterBinding) {
+ ASSERT_OK_AND_ASSIGN(
+ auto prepared_statement,
+ sql_client->Prepare({}, "SELECT * FROM intTable WHERE keyName LIKE ?"));
+
+ auto parameter_schema = prepared_statement->parameter_schema();
+
+ const std::shared_ptr<Schema>& expected_parameter_schema =
+ arrow::schema({arrow::field("parameter_1", example::GetUnknownColumnDataType())});
+
+ AssertSchemaEqual(expected_parameter_schema, parameter_schema);
+
+ std::shared_ptr<Array> type_ids = ArrayFromJSON(int8(), R"([0])");
+ std::shared_ptr<Array> offsets = ArrayFromJSON(int32(), R"([0])");
+ std::shared_ptr<Array> string_array = ArrayFromJSON(utf8(), R"(["%one"])");
+ std::shared_ptr<Array> bytes_array = ArrayFromJSON(binary(), R"([])");
+ std::shared_ptr<Array> bigint_array = ArrayFromJSON(int64(), R"([])");
+ std::shared_ptr<Array> double_array = ArrayFromJSON(float64(), R"([])");
+
+ ASSERT_OK_AND_ASSIGN(
+ auto parameter_1_array,
+ DenseUnionArray::Make(*type_ids, *offsets,
+ {string_array, bytes_array, bigint_array, double_array},
+ {"string", "bytes", "bigint", "double"}, {0, 1, 2, 3}));
+
+ const std::shared_ptr<RecordBatch>& record_batch =
+ RecordBatch::Make(parameter_schema, 1, {parameter_1_array});
+
+ ASSERT_OK(prepared_statement->SetParameters(record_batch));
+
+ ASSERT_OK_AND_ASSIGN(auto flight_info, prepared_statement->Execute());
+
+ ASSERT_OK_AND_ASSIGN(auto stream,
+ sql_client->DoGet({}, flight_info->endpoints()[0].ticket));
+
+ std::shared_ptr<Table> table;
+ ASSERT_OK(stream->ReadAll(&table));
+
+ const std::shared_ptr<Schema>& expected_schema =
+ arrow::schema({arrow::field("id", int64()), arrow::field("keyName", utf8()),
+ arrow::field("value", int64()), arrow::field("foreignId", int64())});
+
+ const auto id_array = ArrayFromJSON(int64(), R"([1, 3])");
+ const auto keyname_array = ArrayFromJSON(utf8(), R"(["one", "negative one"])");
+ const auto value_array = ArrayFromJSON(int64(), R"([1, -1])");
+ const auto foreignId_array = ArrayFromJSON(int64(), R"([1, 1])");
+
+ const std::shared_ptr<Table>& expected_table = Table::Make(
+ expected_schema, {id_array, keyname_array, value_array, foreignId_array});
+
+ AssertTablesEqual(*expected_table, *table);
+}
+
+TEST_F(TestFlightSqlServer, TestCommandPreparedStatementUpdateWithParameterBinding) {
+ ASSERT_OK_AND_ASSIGN(
+ auto prepared_statement,
+ sql_client->Prepare(
+ {}, "INSERT INTO INTTABLE (keyName, value) VALUES ('new_value', ?)"));
+
+ auto parameter_schema = prepared_statement->parameter_schema();
+
+ const std::shared_ptr<Schema>& expected_parameter_schema =
+ arrow::schema({arrow::field("parameter_1", example::GetUnknownColumnDataType())});
+
+ AssertSchemaEqual(expected_parameter_schema, parameter_schema);
+
+ std::shared_ptr<Array> type_ids = ArrayFromJSON(int8(), R"([2])");
+ std::shared_ptr<Array> offsets = ArrayFromJSON(int32(), R"([0])");
+ std::shared_ptr<Array> string_array = ArrayFromJSON(utf8(), R"([])");
+ std::shared_ptr<Array> bytes_array = ArrayFromJSON(binary(), R"([])");
+ std::shared_ptr<Array> bigint_array = ArrayFromJSON(int64(), R"([999])");
+ std::shared_ptr<Array> double_array = ArrayFromJSON(float64(), R"([])");
+
+ ASSERT_OK_AND_ASSIGN(
+ auto parameter_1_array,
+ DenseUnionArray::Make(*type_ids, *offsets,
+ {string_array, bytes_array, bigint_array, double_array},
+ {"string", "bytes", "bigint", "double"}, {0, 1, 2, 3}));
+
+ const std::shared_ptr<RecordBatch>& record_batch =
+ RecordBatch::Make(parameter_schema, 1, {parameter_1_array});
+
+ ASSERT_OK(prepared_statement->SetParameters(record_batch));
+
+ ASSERT_OK_AND_EQ(4, ExecuteCountQuery("SELECT COUNT(*) FROM intTable"));
+
+ ASSERT_OK_AND_EQ(1, prepared_statement->ExecuteUpdate());
+
+ ASSERT_OK_AND_EQ(5, ExecuteCountQuery("SELECT COUNT(*) FROM intTable"));
+
+ ASSERT_OK_AND_EQ(1, sql_client->ExecuteUpdate(
+ {}, "DELETE FROM intTable WHERE keyName = 'new_value'"));
+
+ ASSERT_OK_AND_EQ(4, ExecuteCountQuery("SELECT COUNT(*) FROM intTable"));
+}
+
+TEST_F(TestFlightSqlServer, TestCommandPreparedStatementUpdate) {
+ ASSERT_OK_AND_ASSIGN(
+ auto prepared_statement,
+ sql_client->Prepare(
+ {}, "INSERT INTO INTTABLE (keyName, value) VALUES ('new_value', 999)"));
+
+ ASSERT_OK_AND_EQ(4, ExecuteCountQuery("SELECT COUNT(*) FROM intTable"));
+
+ ASSERT_OK_AND_EQ(1, prepared_statement->ExecuteUpdate());
+
+ ASSERT_OK_AND_EQ(5, ExecuteCountQuery("SELECT COUNT(*) FROM intTable"));
+
+ ASSERT_OK_AND_EQ(1, sql_client->ExecuteUpdate(
+ {}, "DELETE FROM intTable WHERE keyName = 'new_value'"));
+
+ ASSERT_OK_AND_EQ(4, ExecuteCountQuery("SELECT COUNT(*) FROM intTable"));
+}
+
+TEST_F(TestFlightSqlServer, TestCommandGetPrimaryKeys) {
+ FlightCallOptions options = {};
+ TableRef table_ref = {util::nullopt, util::nullopt, "int%"};
+ ASSERT_OK_AND_ASSIGN(auto flight_info, sql_client->GetPrimaryKeys(options, table_ref));
+
+ ASSERT_OK_AND_ASSIGN(auto stream,
+ sql_client->DoGet({}, flight_info->endpoints()[0].ticket));
+
+ std::shared_ptr<Table> table;
+ ASSERT_OK(stream->ReadAll(&table));
+
+ const auto catalog_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto schema_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto key_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto table_name = ArrayFromJSON(utf8(), R"(["intTable"])");
+ const auto column_name = ArrayFromJSON(utf8(), R"(["id"])");
+ const auto key_sequence = ArrayFromJSON(int64(), R"([1])");
+
+ const std::shared_ptr<Table>& expected_table = Table::Make(
+ SqlSchema::GetPrimaryKeysSchema(),
+ {catalog_name, schema_name, table_name, column_name, key_sequence, key_name});
+
+ AssertTablesEqual(*expected_table, *table);
+}
+
+TEST_F(TestFlightSqlServer, TestCommandGetImportedKeys) {
+ FlightCallOptions options = {};
+ TableRef table_ref = {util::nullopt, util::nullopt, "intTable"};
+ ASSERT_OK_AND_ASSIGN(auto flight_info, sql_client->GetImportedKeys(options, table_ref));
+
+ ASSERT_OK_AND_ASSIGN(auto stream,
+ sql_client->DoGet({}, flight_info->endpoints()[0].ticket));
+
+ std::shared_ptr<Table> table;
+ ASSERT_OK(stream->ReadAll(&table));
+
+ const auto pk_catalog_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto pk_schema_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto pk_table_name = ArrayFromJSON(utf8(), R"(["foreignTable"])");
+ const auto pk_column_name = ArrayFromJSON(utf8(), R"(["id"])");
+ const auto fk_catalog_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto fk_schema_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto fk_table_name = ArrayFromJSON(utf8(), R"(["intTable"])");
+ const auto fk_column_name = ArrayFromJSON(utf8(), R"(["foreignId"])");
+ const auto key_sequence = ArrayFromJSON(int32(), R"([0])");
+ const auto fk_key_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto pk_key_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto update_rule = ArrayFromJSON(uint8(), R"([3])");
+ const auto delete_rule = ArrayFromJSON(uint8(), R"([3])");
+
+ const std::shared_ptr<Table>& expected_table =
+ Table::Make(SqlSchema::GetImportedKeysSchema(),
+ {pk_catalog_name, pk_schema_name, pk_table_name, pk_column_name,
+ fk_catalog_name, fk_schema_name, fk_table_name, fk_column_name,
+ key_sequence, fk_key_name, pk_key_name, update_rule, delete_rule});
+ AssertTablesEqual(*expected_table, *table);
+}
+
+TEST_F(TestFlightSqlServer, TestCommandGetExportedKeys) {
+ FlightCallOptions options = {};
+ TableRef table_ref = {util::nullopt, util::nullopt, "foreignTable"};
+ ASSERT_OK_AND_ASSIGN(auto flight_info, sql_client->GetExportedKeys(options, table_ref));
+
+ ASSERT_OK_AND_ASSIGN(auto stream,
+ sql_client->DoGet({}, flight_info->endpoints()[0].ticket));
+
+ std::shared_ptr<Table> table;
+ ASSERT_OK(stream->ReadAll(&table));
+
+ const auto pk_catalog_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto pk_schema_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto pk_table_name = ArrayFromJSON(utf8(), R"(["foreignTable"])");
+ const auto pk_column_name = ArrayFromJSON(utf8(), R"(["id"])");
+ const auto fk_catalog_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto fk_schema_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto fk_table_name = ArrayFromJSON(utf8(), R"(["intTable"])");
+ const auto fk_column_name = ArrayFromJSON(utf8(), R"(["foreignId"])");
+ const auto key_sequence = ArrayFromJSON(int32(), R"([0])");
+ const auto fk_key_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto pk_key_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto update_rule = ArrayFromJSON(uint8(), R"([3])");
+ const auto delete_rule = ArrayFromJSON(uint8(), R"([3])");
+
+ const std::shared_ptr<Table>& expected_table =
+ Table::Make(SqlSchema::GetExportedKeysSchema(),
+ {pk_catalog_name, pk_schema_name, pk_table_name, pk_column_name,
+ fk_catalog_name, fk_schema_name, fk_table_name, fk_column_name,
+ key_sequence, fk_key_name, pk_key_name, update_rule, delete_rule});
+ AssertTablesEqual(*expected_table, *table);
+}
+
+TEST_F(TestFlightSqlServer, TestCommandGetCrossReference) {
+ FlightCallOptions options = {};
+ TableRef pk_table_ref = {util::nullopt, util::nullopt, "foreignTable"};
+ TableRef fk_table_ref = {util::nullopt, util::nullopt, "intTable"};
+ ASSERT_OK_AND_ASSIGN(auto flight_info, sql_client->GetCrossReference(
+ options, pk_table_ref, fk_table_ref));
+
+ ASSERT_OK_AND_ASSIGN(auto stream,
+ sql_client->DoGet({}, flight_info->endpoints()[0].ticket));
+
+ std::shared_ptr<Table> table;
+ ASSERT_OK(stream->ReadAll(&table));
+
+ const auto pk_catalog_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto pk_schema_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto pk_table_name = ArrayFromJSON(utf8(), R"(["foreignTable"])");
+ const auto pk_column_name = ArrayFromJSON(utf8(), R"(["id"])");
+ const auto fk_catalog_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto fk_schema_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto fk_table_name = ArrayFromJSON(utf8(), R"(["intTable"])");
+ const auto fk_column_name = ArrayFromJSON(utf8(), R"(["foreignId"])");
+ const auto key_sequence = ArrayFromJSON(int32(), R"([0])");
+ const auto fk_key_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto pk_key_name = ArrayFromJSON(utf8(), R"([null])");
+ const auto update_rule = ArrayFromJSON(uint8(), R"([3])");
+ const auto delete_rule = ArrayFromJSON(uint8(), R"([3])");
+
+ const std::shared_ptr<Table>& expected_table =
+ Table::Make(SqlSchema::GetCrossReferenceSchema(),
+ {pk_catalog_name, pk_schema_name, pk_table_name, pk_column_name,
+ fk_catalog_name, fk_schema_name, fk_table_name, fk_column_name,
+ key_sequence, fk_key_name, pk_key_name, update_rule, delete_rule});
+ AssertTablesEqual(*expected_table, *table);
+}
+
+TEST_F(TestFlightSqlServer, TestCommandGetSqlInfo) {
+ const auto& sql_info_expected_results = sql::example::GetSqlInfoResultMap();
+ std::vector<int> sql_info_ids;
+ sql_info_ids.reserve(sql_info_expected_results.size());
+ for (const auto& sql_info_expected_result : sql_info_expected_results) {
+ sql_info_ids.push_back(sql_info_expected_result.first);
+ }
+
+ FlightCallOptions call_options;
+ ASSERT_OK_AND_ASSIGN(auto flight_info,
+ sql_client->GetSqlInfo(call_options, sql_info_ids));
+ ASSERT_OK_AND_ASSIGN(
+ auto reader, sql_client->DoGet(call_options, flight_info->endpoints()[0].ticket));
+ std::shared_ptr<Table> results;
+ ASSERT_OK(reader->ReadAll(&results));
+ ASSERT_EQ(2, results->num_columns());
+ ASSERT_EQ(sql_info_ids.size(), results->num_rows());
+ const auto& col_name = results->column(0);
+ const auto& col_value = results->column(1);
+ for (int32_t i = 0; i < col_name->num_chunks(); i++) {
+ const auto* col_name_chunk_data =
+ col_name->chunk(i)->data()->GetValuesSafe<int32_t>(1);
+ const auto& col_value_chunk = col_value->chunk(i);
+ for (int64_t row = 0; row < col_value->length(); row++) {
+ ASSERT_OK_AND_ASSIGN(const auto& scalar, col_value_chunk->GetScalar(row));
+ const SqlInfoDenseUnionValidator validator(
+ reinterpret_cast<const DenseUnionScalar&>(*scalar));
+ const auto& expected_result =
+ sql_info_expected_results.at(col_name_chunk_data[row]);
+ arrow::util::visit(validator, expected_result);
+ }
+ }
+}
+
+TEST_F(TestFlightSqlServer, TestCommandGetSqlInfoNoInfo) {
+ FlightCallOptions call_options;
+ ASSERT_OK_AND_ASSIGN(auto flight_info, sql_client->GetSqlInfo(call_options, {999999}));
+
+ EXPECT_RAISES_WITH_MESSAGE_THAT(
+ KeyError, ::testing::HasSubstr("No information for SQL info number 999999."),
+ sql_client->DoGet(call_options, flight_info->endpoints()[0].ticket));
+}
+
+} // namespace sql
+} // namespace flight
+} // namespace arrow
diff --git a/cpp/src/arrow/flight/sql/sql_info_internal.cc b/cpp/src/arrow/flight/sql/sql_info_internal.cc
new file mode 100644
index 0000000..74718fb
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/sql_info_internal.cc
@@ -0,0 +1,101 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "arrow/flight/sql/sql_info_internal.h"
+
+#include "arrow/buffer.h"
+#include "arrow/builder.h"
+
+namespace arrow {
+namespace flight {
+namespace sql {
+namespace internal {
+
+Status SqlInfoResultAppender::operator()(const std::string& value) {
+ ARROW_RETURN_NOT_OK(value_builder_->Append(kStringValueIndex));
+ ARROW_RETURN_NOT_OK(string_value_builder_->Append(value));
+ return Status::OK();
+}
+
+Status SqlInfoResultAppender::operator()(const bool value) {
+ ARROW_RETURN_NOT_OK(value_builder_->Append(kBoolValueIndex));
+ ARROW_RETURN_NOT_OK(bool_value_builder_->Append(value));
+ return Status::OK();
+}
+
+Status SqlInfoResultAppender::operator()(const int64_t value) {
+ ARROW_RETURN_NOT_OK(value_builder_->Append(kBigIntValueIndex));
+ ARROW_RETURN_NOT_OK(bigint_value_builder_->Append(value));
+ return Status::OK();
+}
+
+Status SqlInfoResultAppender::operator()(const int32_t value) {
+ ARROW_RETURN_NOT_OK(value_builder_->Append(kInt32BitMaskIndex));
+ ARROW_RETURN_NOT_OK(int32_bitmask_builder_->Append(value));
+ return Status::OK();
+}
+
+Status SqlInfoResultAppender::operator()(const std::vector<std::string>& value) {
+ ARROW_RETURN_NOT_OK(value_builder_->Append(kStringListIndex));
+ ARROW_RETURN_NOT_OK(string_list_builder_->Append());
+ auto* string_list_child =
+ reinterpret_cast<StringBuilder*>(string_list_builder_->value_builder());
+ for (const auto& string : value) {
+ ARROW_RETURN_NOT_OK(string_list_child->Append(string));
+ }
+ return Status::OK();
+}
+
+Status SqlInfoResultAppender::operator()(
+ const std::unordered_map<int32_t, std::vector<int32_t>>& value) {
+ ARROW_RETURN_NOT_OK(value_builder_->Append(kInt32ToInt32ListIndex));
+ ARROW_RETURN_NOT_OK(int32_to_int32_list_builder_->Append());
+ for (const auto& pair : value) {
+ ARROW_RETURN_NOT_OK(
+ reinterpret_cast<Int32Builder*>(int32_to_int32_list_builder_->key_builder())
+ ->Append(pair.first));
+ auto* int32_list_builder =
+ reinterpret_cast<ListBuilder*>(int32_to_int32_list_builder_->item_builder());
+ ARROW_RETURN_NOT_OK(int32_list_builder->Append());
+ auto* int32_list_child =
+ reinterpret_cast<Int32Builder*>(int32_list_builder->value_builder());
+ for (const auto& int32 : pair.second) {
+ ARROW_RETURN_NOT_OK(int32_list_child->Append(int32));
+ }
+ }
+ return Status::OK();
+}
+
+SqlInfoResultAppender::SqlInfoResultAppender(DenseUnionBuilder* value_builder)
+ : value_builder_(value_builder),
+ string_value_builder_(
+ reinterpret_cast<StringBuilder*>(value_builder_->child(kStringValueIndex))),
+ bool_value_builder_(
+ reinterpret_cast<BooleanBuilder*>(value_builder_->child(kBoolValueIndex))),
+ bigint_value_builder_(
+ reinterpret_cast<Int64Builder*>(value_builder_->child(kBigIntValueIndex))),
+ int32_bitmask_builder_(
+ reinterpret_cast<Int32Builder*>(value_builder_->child(kInt32BitMaskIndex))),
+ string_list_builder_(
+ reinterpret_cast<ListBuilder*>(value_builder_->child(kStringListIndex))),
+ int32_to_int32_list_builder_(
+ reinterpret_cast<MapBuilder*>(value_builder_->child(kInt32ToInt32ListIndex))) {}
+
+} // namespace internal
+} // namespace sql
+} // namespace flight
+} // namespace arrow
diff --git a/cpp/src/arrow/flight/sql/sql_info_internal.h b/cpp/src/arrow/flight/sql/sql_info_internal.h
new file mode 100644
index 0000000..b18789c
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/sql_info_internal.h
@@ -0,0 +1,87 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include "arrow/flight/sql/types.h"
+
+namespace arrow {
+namespace flight {
+namespace sql {
+namespace internal {
+
+/// \brief Auxiliary class used to populate GetSqlInfo's DenseUnionArray with different
+/// data types.
+class SqlInfoResultAppender {
+ public:
+ /// \brief Append a string to the DenseUnionBuilder.
+ /// \param[in] value Value to be appended.
+ Status operator()(const std::string& value);
+
+ /// \brief Append a bool to the DenseUnionBuilder.
+ /// \param[in] value Value to be appended.
+ Status operator()(bool value);
+
+ /// \brief Append a int64_t to the DenseUnionBuilder.
+ /// \param[in] value Value to be appended.
+ Status operator()(int64_t value);
+
+ /// \brief Append a int32_t to the DenseUnionBuilder.
+ /// \param[in] value Value to be appended.
+ Status operator()(int32_t value);
+
+ /// \brief Append a string list to the DenseUnionBuilder.
+ /// \param[in] value Value to be appended.
+ Status operator()(const std::vector<std::string>& value);
+
+ /// \brief Append a int32 to int32 list map to the DenseUnionBuilder.
+ /// \param[in] value Value to be appended.
+ Status operator()(const std::unordered_map<int32_t, std::vector<int32_t>>& value);
+
+ /// \brief Create a Variant visitor that appends data to given
+ /// DenseUnionBuilder. \param[in] value_builder DenseUnionBuilder to append data to.
+ explicit SqlInfoResultAppender(DenseUnionBuilder* value_builder);
+
+ SqlInfoResultAppender(const SqlInfoResultAppender&) = delete;
+ SqlInfoResultAppender(SqlInfoResultAppender&&) = delete;
+ SqlInfoResultAppender& operator=(const SqlInfoResultAppender&) = delete;
+
+ private:
+ DenseUnionBuilder* value_builder_;
+
+ // Builders for each child on dense union
+ StringBuilder* string_value_builder_;
+ BooleanBuilder* bool_value_builder_;
+ Int64Builder* bigint_value_builder_;
+ Int32Builder* int32_bitmask_builder_;
+ ListBuilder* string_list_builder_;
+ MapBuilder* int32_to_int32_list_builder_;
+
+ enum : int8_t {
+ kStringValueIndex = 0,
+ kBoolValueIndex = 1,
+ kBigIntValueIndex = 2,
+ kInt32BitMaskIndex = 3,
+ kStringListIndex = 4,
+ kInt32ToInt32ListIndex = 5
+ };
+};
+
+} // namespace internal
+} // namespace sql
+} // namespace flight
+} // namespace arrow
diff --git a/cpp/src/arrow/flight/sql/test_app_cli.cc b/cpp/src/arrow/flight/sql/test_app_cli.cc
new file mode 100644
index 0000000..43c37be
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/test_app_cli.cc
@@ -0,0 +1,197 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <gflags/gflags.h>
+
+#include <boost/algorithm/string.hpp>
+#include <iostream>
+#include <memory>
+
+#include "arrow/array/builder_binary.h"
+#include "arrow/array/builder_primitive.h"
+#include "arrow/flight/api.h"
+#include "arrow/flight/sql/api.h"
+#include "arrow/io/memory.h"
+#include "arrow/pretty_print.h"
+#include "arrow/status.h"
+#include "arrow/table.h"
+#include "arrow/util/optional.h"
+
+using arrow::Result;
+using arrow::Schema;
+using arrow::Status;
+using arrow::flight::ClientAuthHandler;
+using arrow::flight::FlightCallOptions;
+using arrow::flight::FlightClient;
+using arrow::flight::FlightDescriptor;
+using arrow::flight::FlightEndpoint;
+using arrow::flight::FlightInfo;
+using arrow::flight::FlightStreamChunk;
+using arrow::flight::FlightStreamReader;
+using arrow::flight::Location;
+using arrow::flight::Ticket;
+using arrow::flight::sql::FlightSqlClient;
+using arrow::flight::sql::TableRef;
+
+DEFINE_string(host, "localhost", "Host to connect to");
+DEFINE_int32(port, 32010, "Port to connect to");
+DEFINE_string(username, "", "Username");
+DEFINE_string(password, "", "Password");
+
+DEFINE_string(command, "", "Method to run");
+DEFINE_string(query, "", "Query");
+DEFINE_string(catalog, "", "Catalog");
+DEFINE_string(schema, "", "Schema");
+DEFINE_string(table, "", "Table");
+
+Status PrintResultsForEndpoint(FlightSqlClient& client,
+ const FlightCallOptions& call_options,
+ const FlightEndpoint& endpoint) {
+ ARROW_ASSIGN_OR_RAISE(auto stream, client.DoGet(call_options, endpoint.ticket));
+
+ const arrow::Result<std::shared_ptr<Schema>>& schema = stream->GetSchema();
+ ARROW_RETURN_NOT_OK(schema);
+
+ std::cout << "Schema:" << std::endl;
+ std::cout << schema->get()->ToString() << std::endl << std::endl;
+
+ std::cout << "Results:" << std::endl;
+
+ FlightStreamChunk chunk;
+ int64_t num_rows = 0;
+
+ while (true) {
+ ARROW_RETURN_NOT_OK(stream->Next(&chunk));
+ if (chunk.data == nullptr) {
+ break;
+ }
+ std::cout << chunk.data->ToString() << std::endl;
+ num_rows += chunk.data->num_rows();
+ }
+
+ std::cout << "Total: " << num_rows << std::endl;
+
+ return Status::OK();
+}
+
+Status PrintResults(FlightSqlClient& client, const FlightCallOptions& call_options,
+ const std::unique_ptr<FlightInfo>& info) {
+ const std::vector<FlightEndpoint>& endpoints = info->endpoints();
+
+ for (size_t i = 0; i < endpoints.size(); i++) {
+ std::cout << "Results from endpoint " << i + 1 << " of " << endpoints.size()
+ << std::endl;
+ ARROW_RETURN_NOT_OK(PrintResultsForEndpoint(client, call_options, endpoints[i]));
+ }
+
+ return Status::OK();
+}
+
+Status RunMain() {
+ std::unique_ptr<FlightClient> client;
+ Location location;
+ ARROW_RETURN_NOT_OK(Location::ForGrpcTcp(FLAGS_host, FLAGS_port, &location));
+ ARROW_RETURN_NOT_OK(FlightClient::Connect(location, &client));
+
+ FlightCallOptions call_options;
+
+ if (!FLAGS_username.empty() || !FLAGS_password.empty()) {
+ Result<std::pair<std::string, std::string>> bearer_result =
+ client->AuthenticateBasicToken({}, FLAGS_username, FLAGS_password);
+ ARROW_RETURN_NOT_OK(bearer_result);
+
+ call_options.headers.push_back(bearer_result.ValueOrDie());
+ }
+
+ FlightSqlClient sql_client(std::move(client));
+
+ if (FLAGS_command == "ExecuteUpdate") {
+ ARROW_ASSIGN_OR_RAISE(auto rows, sql_client.ExecuteUpdate(call_options, FLAGS_query));
+
+ std::cout << "Result: " << rows << std::endl;
+
+ return Status::OK();
+ }
+
+ std::unique_ptr<FlightInfo> info;
+
+ if (FLAGS_command == "Execute") {
+ ARROW_ASSIGN_OR_RAISE(info, sql_client.Execute(call_options, FLAGS_query));
+ } else if (FLAGS_command == "GetCatalogs") {
+ ARROW_ASSIGN_OR_RAISE(info, sql_client.GetCatalogs(call_options));
+ } else if (FLAGS_command == "PreparedStatementExecute") {
+ ARROW_ASSIGN_OR_RAISE(auto prepared_statement,
+ sql_client.Prepare(call_options, FLAGS_query));
+ ARROW_ASSIGN_OR_RAISE(info, prepared_statement->Execute());
+ } else if (FLAGS_command == "PreparedStatementExecuteParameterBinding") {
+ ARROW_ASSIGN_OR_RAISE(auto prepared_statement, sql_client.Prepare({}, FLAGS_query));
+ auto parameter_schema = prepared_statement->parameter_schema();
+ auto result_set_schema = prepared_statement->dataset_schema();
+
+ std::cout << result_set_schema->ToString(false) << std::endl;
+ arrow::Int64Builder int_builder;
+ ARROW_RETURN_NOT_OK(int_builder.Append(1));
+ std::shared_ptr<arrow::Array> int_array;
+ ARROW_RETURN_NOT_OK(int_builder.Finish(&int_array));
+ std::shared_ptr<arrow::RecordBatch> result;
+ result = arrow::RecordBatch::Make(parameter_schema, 1, {int_array});
+
+ ARROW_RETURN_NOT_OK(prepared_statement->SetParameters(result));
+ ARROW_ASSIGN_OR_RAISE(info, prepared_statement->Execute());
+ } else if (FLAGS_command == "GetDbSchemas") {
+ ARROW_ASSIGN_OR_RAISE(
+ info, sql_client.GetDbSchemas(call_options, &FLAGS_catalog, &FLAGS_schema));
+ } else if (FLAGS_command == "GetTableTypes") {
+ ARROW_ASSIGN_OR_RAISE(info, sql_client.GetTableTypes(call_options));
+ } else if (FLAGS_command == "GetTables") {
+ ARROW_ASSIGN_OR_RAISE(
+ info, sql_client.GetTables(call_options, &FLAGS_catalog, &FLAGS_schema,
+ &FLAGS_table, false, nullptr));
+ } else if (FLAGS_command == "GetExportedKeys") {
+ TableRef table_ref = {arrow::util::make_optional(FLAGS_catalog),
+ arrow::util::make_optional(FLAGS_schema), FLAGS_table};
+ ARROW_ASSIGN_OR_RAISE(info, sql_client.GetExportedKeys(call_options, table_ref));
+ } else if (FLAGS_command == "GetImportedKeys") {
+ TableRef table_ref = {arrow::util::make_optional(FLAGS_catalog),
+ arrow::util::make_optional(FLAGS_schema), FLAGS_table};
+ ARROW_ASSIGN_OR_RAISE(info, sql_client.GetImportedKeys(call_options, table_ref));
+ } else if (FLAGS_command == "GetPrimaryKeys") {
+ TableRef table_ref = {arrow::util::make_optional(FLAGS_catalog),
+ arrow::util::make_optional(FLAGS_schema), FLAGS_table};
+ ARROW_ASSIGN_OR_RAISE(info, sql_client.GetPrimaryKeys(call_options, table_ref));
+ } else if (FLAGS_command == "GetSqlInfo") {
+ ARROW_ASSIGN_OR_RAISE(info, sql_client.GetSqlInfo(call_options, {}));
+ }
+
+ if (info != NULLPTR &&
+ !boost::istarts_with(FLAGS_command, "PreparedStatementExecute")) {
+ return PrintResults(sql_client, call_options, info);
+ }
+
+ return Status::OK();
+}
+
+int main(int argc, char** argv) {
+ gflags::ParseCommandLineFlags(&argc, &argv, true);
+
+ Status st = RunMain();
+ if (!st.ok()) {
+ std::cerr << st << std::endl;
+ return 1;
+ }
+ return 0;
+}
diff --git a/cpp/src/arrow/flight/sql/test_server_cli.cc b/cpp/src/arrow/flight/sql/test_server_cli.cc
new file mode 100644
index 0000000..8074ab5
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/test_server_cli.cc
@@ -0,0 +1,63 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <gflags/gflags.h>
+
+#include <iostream>
+#include <memory>
+#include <string>
+
+#include "arrow/flight/server.h"
+#include "arrow/flight/sql/example/sqlite_server.h"
+#include "arrow/flight/test_integration.h"
+#include "arrow/flight/test_util.h"
+#include "arrow/io/test_common.h"
+#include "arrow/testing/json_integration.h"
+#include "arrow/util/logging.h"
+
+DEFINE_int32(port, 31337, "Server port to listen on");
+
+arrow::Status RunMain() {
+ arrow::flight::Location location;
+ ARROW_CHECK_OK(arrow::flight::Location::ForGrpcTcp("0.0.0.0", FLAGS_port, &location));
+ arrow::flight::FlightServerOptions options(location);
+
+ std::shared_ptr<arrow::flight::sql::example::SQLiteFlightSqlServer> server;
+ ARROW_ASSIGN_OR_RAISE(server,
+ arrow::flight::sql::example::SQLiteFlightSqlServer::Create())
+
+ ARROW_CHECK_OK(server->Init(options));
+ // Exit with a clean error code (0) on SIGTERM
+ ARROW_CHECK_OK(server->SetShutdownOnSignals({SIGTERM}));
+
+ std::cout << "Server listening on localhost:" << server->port() << std::endl;
+ ARROW_CHECK_OK(server->Serve());
+
+ return arrow::Status::OK();
+}
+
+int main(int argc, char** argv) {
+ gflags::SetUsageMessage("Integration testing server for Flight SQL.");
+ gflags::ParseCommandLineFlags(&argc, &argv, true);
+
+ arrow::Status st = RunMain();
+ if (!st.ok()) {
+ std::cerr << st << std::endl;
+ return 1;
+ }
+ return 0;
+}
diff --git a/cpp/src/arrow/flight/sql/types.h b/cpp/src/arrow/flight/sql/types.h
new file mode 100644
index 0000000..44b8bca
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/types.h
@@ -0,0 +1,890 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <cstdint>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "arrow/type_fwd.h"
+#include "arrow/util/optional.h"
+#include "arrow/util/variant.h"
+
+namespace arrow {
+namespace flight {
+namespace sql {
+
+/// \brief Variant supporting all possible types on SQL info.
+using SqlInfoResult =
+ arrow::util::Variant<std::string, bool, int64_t, int32_t, std::vector<std::string>,
+ std::unordered_map<int32_t, std::vector<int32_t>>>;
+
+/// \brief Map SQL info identifier to its value.
+using SqlInfoResultMap = std::unordered_map<int32_t, SqlInfoResult>;
+
+/// \brief Options to be set in the SqlInfo.
+struct SqlInfoOptions {
+ enum SqlInfo {
+ // Server Information [0-500): Provides basic information about the Flight SQL Server.
+
+ // Retrieves a UTF-8 string with the name of the Flight SQL Server.
+ FLIGHT_SQL_SERVER_NAME = 0,
+
+ // Retrieves a UTF-8 string with the native version of the Flight SQL Server.
+ FLIGHT_SQL_SERVER_VERSION = 1,
+
+ // Retrieves a UTF-8 string with the Arrow format version of the Flight SQL Server.
+ FLIGHT_SQL_SERVER_ARROW_VERSION = 2,
+
+ /*
+ * Retrieves a boolean value indicating whether the Flight SQL Server is read only.
+ *
+ * Returns:
+ * - false: if read-write
+ * - true: if read only
+ */
+ FLIGHT_SQL_SERVER_READ_ONLY = 3,
+
+ // SQL Syntax Information [500-1000): provides information about SQL syntax supported
+ // by the Flight SQL Server.
+
+ /*
+ * Retrieves a boolean value indicating whether the Flight SQL Server supports CREATE
+ * and DROP of catalogs.
+ *
+ * Returns:
+ * - false: if it doesn't support CREATE and DROP of catalogs.
+ * - true: if it supports CREATE and DROP of catalogs.
+ */
+ SQL_DDL_CATALOG = 500,
+
+ /*
+ * Retrieves a boolean value indicating whether the Flight SQL Server supports CREATE
+ * and DROP of schemas.
+ *
+ * Returns:
+ * - false: if it doesn't support CREATE and DROP of schemas.
+ * - true: if it supports CREATE and DROP of schemas.
+ */
+ SQL_DDL_SCHEMA = 501,
+
+ /*
+ * Indicates whether the Flight SQL Server supports CREATE and DROP of tables.
+ *
+ * Returns:
+ * - false: if it doesn't support CREATE and DROP of tables.
+ * - true: if it supports CREATE and DROP of tables.
+ */
+ SQL_DDL_TABLE = 502,
+
+ /*
+ * Retrieves a uint32 value representing the enu uint32 ordinal for the case
+ * sensitivity of catalog, table and schema names.
+ *
+ * The possible values are listed in
+ * `arrow.flight.protocol.sql.SqlSupportedCaseSensitivity`.
+ */
+ SQL_IDENTIFIER_CASE = 503,
+
+ // Retrieves a UTF-8 string with the supported character(s) used to surround a
+ // delimited identifier.
+ SQL_IDENTIFIER_QUOTE_CHAR = 504,
+
+ /*
+ * Retrieves a uint32 value representing the enu uint32 ordinal for the case
+ * sensitivity of quoted identifiers.
+ *
+ * The possible values are listed in
+ * `arrow.flight.protocol.sql.SqlSupportedCaseSensitivity`.
+ */
+ SQL_QUOTED_IDENTIFIER_CASE = 505,
+
+ /*
+ * Retrieves a boolean value indicating whether all tables are selectable.
+ *
+ * Returns:
+ * - false: if not all tables are selectable or if none are;
+ * - true: if all tables are selectable.
+ */
+ SQL_ALL_TABLES_ARE_SELECTABLE = 506,
+
+ /*
+ * Retrieves the null ordering.
+ *
+ * Returns a uint32 ordinal for the null ordering being used, as described in
+ * `arrow.flight.protocol.sql.SqlNullOrdering`.
+ */
+ SQL_NULL_ORDERING = 507,
+
+ // Retrieves a UTF-8 string list with values of the supported keywords.
+ SQL_KEYWORDS = 508,
+
+ // Retrieves a UTF-8 string list with values of the supported numeric functions.
+ SQL_NUMERIC_FUNCTIONS = 509,
+
+ // Retrieves a UTF-8 string list with values of the supported string functions.
+ SQL_STRING_FUNCTIONS = 510,
+
+ // Retrieves a UTF-8 string list with values of the supported system functions.
+ SQL_SYSTEM_FUNCTIONS = 511,
+
+ // Retrieves a UTF-8 string list with values of the supported datetime functions.
+ SQL_DATETIME_FUNCTIONS = 512,
+
+ /*
+ * Retrieves the UTF-8 string that can be used to escape wildcard characters.
+ * This is the string that can be used to escape '_' or '%' in the catalog search
+ * parameters that are a pattern (and therefore use one of the wildcard characters).
+ * The '_' character represents any single character; the '%' character represents any
+ * sequence of zero or more characters.
+ */
+ SQL_SEARCH_STRING_ESCAPE = 513,
+
+ /*
+ * Retrieves a UTF-8 string with all the "extra" characters that can be used in
+ * unquoted identifier names (those beyond a-z, A-Z, 0-9 and _).
+ */
+ SQL_EXTRA_NAME_CHARACTERS = 514,
+
+ /*
+ * Retrieves a boolean value indicating whether column aliasing is supported.
+ * If so, the SQL AS clause can be used to provide names for computed columns or to
+ * provide alias names for columns as required.
+ *
+ * Returns:
+ * - false: if column aliasing is unsupported;
+ * - true: if column aliasing is supported.
+ */
+ SQL_SUPPORTS_COLUMN_ALIASING = 515,
+
+ /*
+ * Retrieves a boolean value indicating whether concatenations between null and
+ * non-null values being null are supported.
+ *
+ * - Returns:
+ * - false: if concatenations between null and non-null values being null are
+ * unsupported;
+ * - true: if concatenations between null and non-null values being null are
+ * supported.
+ */
+ SQL_NULL_PLUS_NULL_IS_NULL = 516,
+
+ /*
+ * Retrieves a map where the key is the type to convert from and the value is a list
+ * with the types to convert to, indicating the supported conversions. Each key and
+ * each item on the list value is a value to a predefined type on SqlSupportsConvert
+ * enum. The returned map will be: map<int32, list<int32>>
+ */
+ SQL_SUPPORTS_CONVERT = 517,
+
+ /*
+ * Retrieves a boolean value indicating whether, when table correlation names are
+ * supported, they are restricted to being different from the names of the tables.
+ *
+ * Returns:
+ * - false: if table correlation names are unsupported;
+ * - true: if table correlation names are supported.
+ */
+ SQL_SUPPORTS_TABLE_CORRELATION_NAMES = 518,
+
+ /*
+ * Retrieves a boolean value indicating whether, when table correlation names are
+ * supported, they are restricted to being different from the names of the tables.
+ *
+ * Returns:
+ * - false: if different table correlation names are unsupported;
+ * - true: if different table correlation names are supported
+ */
+ SQL_SUPPORTS_DIFFERENT_TABLE_CORRELATION_NAMES = 519,
+
+ /*
+ * Retrieves a boolean value indicating whether expressions in ORDER BY lists are
+ * supported.
+ *
+ * Returns:
+ * - false: if expressions in ORDER BY are unsupported;
+ * - true: if expressions in ORDER BY are supported;
+ */
+ SQL_SUPPORTS_EXPRESSIONS_IN_ORDER_BY = 520,
+
+ /*
+ * Retrieves a boolean value indicating whether using a column that is not in the
+ * SELECT statement in a GROUP BY clause is supported.
+ *
+ * Returns:
+ * - false: if using a column that is not in the SELECT statement in a GROUP BY clause
+ * is unsupported;
+ * - true: if using a column that is not in the SELECT statement in a GROUP BY clause
+ * is supported.
+ */
+ SQL_SUPPORTS_ORDER_BY_UNRELATED = 521,
+
+ /*
+ * Retrieves the supported GROUP BY commands;
+ *
+ * Returns an int32 bitmask value representing the supported commands.
+ * The returned bitmask should be parsed in order to retrieve the supported commands.
+ *
+ * For instance:
+ * - return 0 (\b0) => [] (GROUP BY is unsupported);
+ * - return 1 (\b1) => [SQL_GROUP_BY_UNRELATED];
+ * - return 2 (\b10) => [SQL_GROUP_BY_BEYOND_SELECT];
+ * - return 3 (\b11) => [SQL_GROUP_BY_UNRELATED, SQL_GROUP_BY_BEYOND_SELECT].
+ * Valid GROUP BY types are described under
+ * `arrow.flight.protocol.sql.SqlSupportedGroupBy`.
+ */
+ SQL_SUPPORTED_GROUP_BY = 522,
+
+ /*
+ * Retrieves a boolean value indicating whether specifying a LIKE escape clause is
+ * supported.
+ *
+ * Returns:
+ * - false: if specifying a LIKE escape clause is unsupported;
+ * - true: if specifying a LIKE escape clause is supported.
+ */
+ SQL_SUPPORTS_LIKE_ESCAPE_CLAUSE = 523,
+
+ /*
+ * Retrieves a boolean value indicating whether columns may be defined as
+ * non-nullable.
+ *
+ * Returns:
+ * - false: if columns cannot be defined as non-nullable;
+ * - true: if columns may be defined as non-nullable.
+ */
+ SQL_SUPPORTS_NON_NULLABLE_COLUMNS = 524,
+
+ /*
+ * Retrieves the supported SQL grammar level as per the ODBC specification.
+ *
+ * Returns an int32 bitmask value representing the supported SQL grammar level.
+ * The returned bitmask should be parsed in order to retrieve the supported grammar
+ * levels.
+ *
+ * For instance:
+ * - return 0 (\b0) => [] (SQL grammar is unsupported);
+ * - return 1 (\b1) => [SQL_MINIMUM_GRAMMAR];
+ * - return 2 (\b10) => [SQL_CORE_GRAMMAR];
+ * - return 3 (\b11) => [SQL_MINIMUM_GRAMMAR, SQL_CORE_GRAMMAR];
+ * - return 4 (\b100) => [SQL_EXTENDED_GRAMMAR];
+ * - return 5 (\b101) => [SQL_MINIMUM_GRAMMAR, SQL_EXTENDED_GRAMMAR];
+ * - return 6 (\b110) => [SQL_CORE_GRAMMAR, SQL_EXTENDED_GRAMMAR];
+ * - return 7 (\b111) => [SQL_MINIMUM_GRAMMAR, SQL_CORE_GRAMMAR,
+ * SQL_EXTENDED_GRAMMAR]. Valid SQL grammar levels are described under
+ * `arrow.flight.protocol.sql.SupportedSqlGrammar`.
+ */
+ SQL_SUPPORTED_GRAMMAR = 525,
+
+ /*
+ * Retrieves the supported ANSI92 SQL grammar level.
+ *
+ * Returns an int32 bitmask value representing the supported ANSI92 SQL grammar level.
+ * The returned bitmask should be parsed in order to retrieve the supported commands.
+ *
+ * For instance:
+ * - return 0 (\b0) => [] (ANSI92 SQL grammar is unsupported);
+ * - return 1 (\b1) => [ANSI92_ENTRY_SQL];
+ * - return 2 (\b10) => [ANSI92_INTERMEDIATE_SQL];
+ * - return 3 (\b11) => [ANSI92_ENTRY_SQL, ANSI92_INTERMEDIATE_SQL];
+ * - return 4 (\b100) => [ANSI92_FULL_SQL];
+ * - return 5 (\b101) => [ANSI92_ENTRY_SQL, ANSI92_FULL_SQL];
+ * - return 6 (\b110) => [ANSI92_INTERMEDIATE_SQL, ANSI92_FULL_SQL];
+ * - return 7 (\b111) => [ANSI92_ENTRY_SQL, ANSI92_INTERMEDIATE_SQL, ANSI92_FULL_SQL].
+ * Valid ANSI92 SQL grammar levels are described under
+ * `arrow.flight.protocol.sql.SupportedAnsi92SqlGrammarLevel`.
+ */
+ SQL_ANSI92_SUPPORTED_LEVEL = 526,
+
+ /*
+ * Retrieves a boolean value indicating whether the SQL Integrity Enhancement Facility
+ * is supported.
+ *
+ * Returns:
+ * - false: if the SQL Integrity Enhancement Facility is supported;
+ * - true: if the SQL Integrity Enhancement Facility is supported.
+ */
+ SQL_SUPPORTS_INTEGRITY_ENHANCEMENT_FACILITY = 527,
+
+ /*
+ * Retrieves the support level for SQL OUTER JOINs.
+ *
+ * Returns a uint3 uint32 ordinal for the SQL ordering being used, as described in
+ * `arrow.flight.protocol.sql.SqlOuterJoinsSupportLevel`.
+ */
+ SQL_OUTER_JOINS_SUPPORT_LEVEL = 528,
+
+ // Retrieves a UTF-8 string with the preferred term for "schema".
+ SQL_SCHEMA_TERM = 529,
+
+ // Retrieves a UTF-8 string with the preferred term for "procedure".
+ SQL_PROCEDURE_TERM = 530,
+
+ // Retrieves a UTF-8 string with the preferred term for "catalog".
+ SQL_CATALOG_TERM = 531,
+
+ /*
+ * Retrieves a boolean value indicating whether a catalog appears at the start of a
+ * fully qualified table name.
+ *
+ * - false: if a catalog does not appear at the start of a fully qualified table name;
+ * - true: if a catalog appears at the start of a fully qualified table name.
+ */
+ SQL_CATALOG_AT_START = 532,
+
+ /*
+ * Retrieves the supported actions for a SQL schema.
+ *
+ * Returns an int32 bitmask value representing the supported actions for a SQL schema.
+ * The returned bitmask should be parsed in order to retrieve the supported actions
+ * for a SQL schema.
+ *
+ * For instance:
+ * - return 0 (\b0) => [] (no supported actions for SQL schema);
+ * - return 1 (\b1) => [SQL_ELEMENT_IN_PROCEDURE_CALLS];
+ * - return 2 (\b10) => [SQL_ELEMENT_IN_INDEX_DEFINITIONS];
+ * - return 3 (\b11) => [SQL_ELEMENT_IN_PROCEDURE_CALLS,
+ * SQL_ELEMENT_IN_INDEX_DEFINITIONS];
+ * - return 4 (\b100) => [SQL_ELEMENT_IN_PRIVILEGE_DEFINITIONS];
+ * - return 5 (\b101) => [SQL_ELEMENT_IN_PROCEDURE_CALLS,
+ * SQL_ELEMENT_IN_PRIVILEGE_DEFINITIONS];
+ * - return 6 (\b110) => [SQL_ELEMENT_IN_INDEX_DEFINITIONS,
+ * SQL_ELEMENT_IN_PRIVILEGE_DEFINITIONS];
+ * - return 7 (\b111) => [SQL_ELEMENT_IN_PROCEDURE_CALLS,
+ * SQL_ELEMENT_IN_INDEX_DEFINITIONS, SQL_ELEMENT_IN_PRIVILEGE_DEFINITIONS]. Valid
+ * actions for a SQL schema described under
+ * `arrow.flight.protocol.sql.SqlSupportedElementActions`.
+ */
+ SQL_SCHEMAS_SUPPORTED_ACTIONS = 533,
+
+ /*
+ * Retrieves the supported actions for a SQL schema.
+ *
+ * Returns an int32 bitmask value representing the supported actions for a SQL
+ * catalog. The returned bitmask should be parsed in order to retrieve the supported
+ * actions for a SQL catalog.
+ *
+ * For instance:
+ * - return 0 (\b0) => [] (no supported actions for SQL catalog);
+ * - return 1 (\b1) => [SQL_ELEMENT_IN_PROCEDURE_CALLS];
+ * - return 2 (\b10) => [SQL_ELEMENT_IN_INDEX_DEFINITIONS];
+ * - return 3 (\b11) => [SQL_ELEMENT_IN_PROCEDURE_CALLS,
+ * SQL_ELEMENT_IN_INDEX_DEFINITIONS];
+ * - return 4 (\b100) => [SQL_ELEMENT_IN_PRIVILEGE_DEFINITIONS];
+ * - return 5 (\b101) => [SQL_ELEMENT_IN_PROCEDURE_CALLS,
+ * SQL_ELEMENT_IN_PRIVILEGE_DEFINITIONS];
+ * - return 6 (\b110) => [SQL_ELEMENT_IN_INDEX_DEFINITIONS,
+ * SQL_ELEMENT_IN_PRIVILEGE_DEFINITIONS];
+ * - return 7 (\b111) => [SQL_ELEMENT_IN_PROCEDURE_CALLS,
+ * SQL_ELEMENT_IN_INDEX_DEFINITIONS, SQL_ELEMENT_IN_PRIVILEGE_DEFINITIONS]. Valid
+ * actions for a SQL catalog are described under
+ * `arrow.flight.protocol.sql.SqlSupportedElementActions`.
+ */
+ SQL_CATALOGS_SUPPORTED_ACTIONS = 534,
+
+ /*
+ * Retrieves the supported SQL positioned commands.
+ *
+ * Returns an int32 bitmask value representing the supported SQL positioned commands.
+ * The returned bitmask should be parsed in order to retrieve the supported SQL
+ * positioned commands.
+ *
+ * For instance:
+ * - return 0 (\b0) => [] (no supported SQL positioned commands);
+ * - return 1 (\b1) => [SQL_POSITIONED_DELETE];
+ * - return 2 (\b10) => [SQL_POSITIONED_UPDATE];
+ * - return 3 (\b11) => [SQL_POSITIONED_DELETE, SQL_POSITIONED_UPDATE].
+ * Valid SQL positioned commands are described under
+ * `arrow.flight.protocol.sql.SqlSupportedPositionedCommands`.
+ */
+ SQL_SUPPORTED_POSITIONED_COMMANDS = 535,
+
+ /*
+ * Retrieves a boolean value indicating whether SELECT FOR UPDATE statements are
+ * supported.
+ *
+ * Returns:
+ * - false: if SELECT FOR UPDATE statements are unsupported;
+ * - true: if SELECT FOR UPDATE statements are supported.
+ */
+ SQL_SELECT_FOR_UPDATE_SUPPORTED = 536,
+
+ /*
+ * Retrieves a boolean value indicating whether stored procedure calls that use the
+ * stored procedure escape syntax are supported.
+ *
+ * Returns:
+ * - false: if stored procedure calls that use the stored procedure escape syntax are
+ * unsupported;
+ * - true: if stored procedure calls that use the stored procedure escape syntax are
+ * supported.
+ */
+ SQL_STORED_PROCEDURES_SUPPORTED = 537,
+
+ /*
+ * Retrieves the supported SQL subqueries.
+ *
+ * Returns an int32 bitmask value representing the supported SQL subqueries.
+ * The returned bitmask should be parsed in order to retrieve the supported SQL
+ * subqueries.
+ *
+ * For instance:
+ * - return 0 (\b0) => [] (no supported SQL subqueries);
+ * - return 1 (\b1) => [SQL_SUBQUERIES_IN_COMPARISONS];
+ * - return 2 (\b10) => [SQL_SUBQUERIES_IN_EXISTS];
+ * - return 3 (\b11) => [SQL_SUBQUERIES_IN_COMPARISONS,
+ * SQL_SUBQUERIES_IN_EXISTS];
+ * - return 4 (\b100) => [SQL_SUBQUERIES_IN_INS];
+ * - return 5 (\b101) => [SQL_SUBQUERIES_IN_COMPARISONS, SQL_SUBQUERIES_IN_INS];
+ * - return 6 (\b110) => [SQL_SUBQUERIES_IN_COMPARISONS,
+ * SQL_SUBQUERIES_IN_EXISTS];
+ * - return 7 (\b111) => [SQL_SUBQUERIES_IN_COMPARISONS, SQL_SUBQUERIES_IN_EXISTS,
+ * SQL_SUBQUERIES_IN_INS];
+ * - return 8 (\b1000) => [SQL_SUBQUERIES_IN_QUANTIFIEDS];
+ * - return 9 (\b1001) => [SQL_SUBQUERIES_IN_COMPARISONS,
+ * SQL_SUBQUERIES_IN_QUANTIFIEDS];
+ * - return 10 (\b1010) => [SQL_SUBQUERIES_IN_EXISTS,
+ * SQL_SUBQUERIES_IN_QUANTIFIEDS];
+ * - return 11 (\b1011) => [SQL_SUBQUERIES_IN_COMPARISONS, SQL_SUBQUERIES_IN_EXISTS,
+ * SQL_SUBQUERIES_IN_QUANTIFIEDS];
+ * - return 12 (\b1100) => [SQL_SUBQUERIES_IN_INS, SQL_SUBQUERIES_IN_QUANTIFIEDS];
+ * - return 13 (\b1101) => [SQL_SUBQUERIES_IN_COMPARISONS, SQL_SUBQUERIES_IN_INS,
+ * SQL_SUBQUERIES_IN_QUANTIFIEDS];
+ * - return 14 (\b1110) => [SQL_SUBQUERIES_IN_EXISTS, SQL_SUBQUERIES_IN_INS,
+ * SQL_SUBQUERIES_IN_QUANTIFIEDS];
+ * - return 15 (\b1111) => [SQL_SUBQUERIES_IN_COMPARISONS, SQL_SUBQUERIES_IN_EXISTS,
+ * SQL_SUBQUERIES_IN_INS, SQL_SUBQUERIES_IN_QUANTIFIEDS];
+ * - ...
+ * Valid SQL subqueries are described under
+ * `arrow.flight.protocol.sql.SqlSupportedSubqueries`.
+ */
+ SQL_SUPPORTED_SUBQUERIES = 538,
+
+ /*
+ * Retrieves a boolean value indicating whether correlated subqueries are supported.
+ *
+ * Returns:
+ * - false: if correlated subqueries are unsupported;
+ * - true: if correlated subqueries are supported.
+ */
+ SQL_CORRELATED_SUBQUERIES_SUPPORTED = 539,
+
+ /*
+ * Retrieves the supported SQL UNIONs.
+ *
+ * Returns an int32 bitmask value representing the supported SQL UNIONs.
+ * The returned bitmask should be parsed in order to retrieve the supported SQL
+ * UNIONs.
+ *
+ * For instance:
+ * - return 0 (\b0) => [] (no supported SQL positioned commands);
+ * - return 1 (\b1) => [SQL_UNION];
+ * - return 2 (\b10) => [SQL_UNION_ALL];
+ * - return 3 (\b11) => [SQL_UNION, SQL_UNION_ALL].
+ * Valid SQL positioned commands are described under
+ * `arrow.flight.protocol.sql.SqlSupportedUnions`.
+ */
+ SQL_SUPPORTED_UNIONS = 540,
+
+ // Retrieves a uint32 value representing the maximum number of hex characters allowed
+ // in an inline binary literal.
+ SQL_MAX_BINARY_LITERAL_LENGTH = 541,
+
+ // Retrieves a uint32 value representing the maximum number of characters allowed for
+ // a character literal.
+ SQL_MAX_CHAR_LITERAL_LENGTH = 542,
+
+ // Retrieves a uint32 value representing the maximum number of characters allowed for
+ // a column name.
+ SQL_MAX_COLUMN_NAME_LENGTH = 543,
+
+ // Retrieves a uint32 value representing the the maximum number of columns allowed in
+ // a GROUP BY clause.
+ SQL_MAX_COLUMNS_IN_GROUP_BY = 544,
+
+ // Retrieves a uint32 value representing the maximum number of columns allowed in an
+ // index.
+ SQL_MAX_COLUMNS_IN_INDEX = 545,
+
+ // Retrieves a uint32 value representing the maximum number of columns allowed in an
+ // ORDER BY clause.
+ SQL_MAX_COLUMNS_IN_ORDER_BY = 546,
+
+ // Retrieves a uint32 value representing the maximum number of columns allowed in a
+ // SELECT list.
+ SQL_MAX_COLUMNS_IN_SELECT = 547,
+
+ // Retrieves a uint32 value representing the maximum number of columns allowed in a
+ // table.
+ SQL_MAX_COLUMNS_IN_TABLE = 548,
+
+ // Retrieves a uint32 value representing the maximum number of concurrent connections
+ // possible.
+ SQL_MAX_CONNECTIONS = 549,
+
+ // Retrieves a uint32 value the maximum number of characters allowed in a cursor name.
+ SQL_MAX_CURSOR_NAME_LENGTH = 550,
+
+ /*
+ * Retrieves a uint32 value representing the maximum number of bytes allowed for an
+ * index, including all of the parts of the index.
+ */
+ SQL_MAX_INDEX_LENGTH = 551,
+
+ // Retrieves a uint32 value representing the maximum number of characters allowed in a
+ // procedure name.
+ SQL_SCHEMA_NAME_LENGTH = 552,
+
+ // Retrieves a uint32 value representing the maximum number of bytes allowed in a
+ // single row.
+ SQL_MAX_PROCEDURE_NAME_LENGTH = 553,
+
+ // Retrieves a uint32 value representing the maximum number of characters allowed in a
+ // catalog name.
+ SQL_MAX_CATALOG_NAME_LENGTH = 554,
+
+ // Retrieves a uint32 value representing the maximum number of bytes allowed in a
+ // single row.
+ SQL_MAX_ROW_SIZE = 555,
+
+ /*
+ * Retrieves a boolean indicating whether the return value for the JDBC method
+ * getMaxRowSize includes the SQL data types LONGVARCHAR and LONGVARBINARY.
+ *
+ * Returns:
+ * - false: if return value for the JDBC method getMaxRowSize does
+ * not include the SQL data types LONGVARCHAR and LONGVARBINARY;
+ * - true: if return value for the JDBC method getMaxRowSize includes
+ * the SQL data types LONGVARCHAR and LONGVARBINARY.
+ */
+ SQL_MAX_ROW_SIZE_INCLUDES_BLOBS = 556,
+
+ /*
+ * Retrieves a uint32 value representing the maximum number of characters allowed for
+ * an SQL statement; a result of 0 (zero) means that there is no limit or the limit is
+ * not known.
+ */
+ SQL_MAX_STATEMENT_LENGTH = 557,
+
+ // Retrieves a uint32 value representing the maximum number of active statements that
+ // can be open at the same time.
+ SQL_MAX_STATEMENTS = 558,
+
+ // Retrieves a uint32 value representing the maximum number of characters allowed in a
+ // table name.
+ SQL_MAX_TABLE_NAME_LENGTH = 559,
+
+ // Retrieves a uint32 value representing the maximum number of tables allowed in a
+ // SELECT statement.
+ SQL_MAX_TABLES_IN_SELECT = 560,
+
+ // Retrieves a uint32 value representing the maximum number of characters allowed in a
+ // user name.
+ SQL_MAX_USERNAME_LENGTH = 561,
+
+ /*
+ * Retrieves this database's default transaction isolation level as described in
+ * `arrow.flight.protocol.sql.SqlTransactionIsolationLevel`.
+ *
+ * Returns a uint32 ordinal for the SQL transaction isolation level.
+ */
+ SQL_DEFAULT_TRANSACTION_ISOLATION = 562,
+
+ /*
+ * Retrieves a boolean value indicating whether transactions are supported. If not,
+ * invoking the method commit is a noop, and the isolation level is
+ * `arrow.flight.protocol.sql.SqlTransactionIsolationLevel.TRANSACTION_NONE`.
+ *
+ * Returns:
+ * - false: if transactions are unsupported;
+ * - true: if transactions are supported.
+ */
+ SQL_TRANSACTIONS_SUPPORTED = 563,
+
+ /*
+ * Retrieves the supported transactions isolation levels.
+ *
+ * Returns an int32 bitmask value representing the supported transactions isolation
+ * levels. The returned bitmask should be parsed in order to retrieve the supported
+ * transactions isolation levels.
+ *
+ * For instance:
+ * - return 0 (\b0) => [] (no supported SQL transactions isolation levels);
+ * - return 1 (\b1) => [SQL_TRANSACTION_NONE];
+ * - return 2 (\b10) => [SQL_TRANSACTION_READ_UNCOMMITTED];
+ * - return 3 (\b11) => [SQL_TRANSACTION_NONE, SQL_TRANSACTION_READ_UNCOMMITTED];
+ * - return 4 (\b100) => [SQL_TRANSACTION_REPEATABLE_READ];
+ * - return 5 (\b101) => [SQL_TRANSACTION_NONE, SQL_TRANSACTION_REPEATABLE_READ];
+ * - return 6 (\b110) => [SQL_TRANSACTION_READ_UNCOMMITTED,
+ * SQL_TRANSACTION_REPEATABLE_READ];
+ * - return 7 (\b111) => [SQL_TRANSACTION_NONE, SQL_TRANSACTION_READ_UNCOMMITTED,
+ * SQL_TRANSACTION_REPEATABLE_READ];
+ * - return 8 (\b1000) => [SQL_TRANSACTION_REPEATABLE_READ];
+ * - return 9 (\b1001) => [SQL_TRANSACTION_NONE, SQL_TRANSACTION_REPEATABLE_READ];
+ * - return 10 (\b1010) => [SQL_TRANSACTION_READ_UNCOMMITTED,
+ * SQL_TRANSACTION_REPEATABLE_READ];
+ * - return 11 (\b1011) => [SQL_TRANSACTION_NONE, SQL_TRANSACTION_READ_UNCOMMITTED,
+ * SQL_TRANSACTION_REPEATABLE_READ];
+ * - return 12 (\b1100) => [SQL_TRANSACTION_REPEATABLE_READ,
+ * SQL_TRANSACTION_REPEATABLE_READ];
+ * - return 13 (\b1101) => [SQL_TRANSACTION_NONE, SQL_TRANSACTION_REPEATABLE_READ,
+ * SQL_TRANSACTION_REPEATABLE_READ];
+ * - return 14 (\b1110) => [SQL_TRANSACTION_READ_UNCOMMITTED,
+ * SQL_TRANSACTION_REPEATABLE_READ, SQL_TRANSACTION_REPEATABLE_READ];
+ * - return 15 (\b1111) => [SQL_TRANSACTION_NONE, SQL_TRANSACTION_READ_UNCOMMITTED,
+ * SQL_TRANSACTION_REPEATABLE_READ, SQL_TRANSACTION_REPEATABLE_READ];
+ * - return 16 (\b10000) => [SQL_TRANSACTION_SERIALIZABLE];
+ * - ...
+ * Valid SQL positioned commands are described under
+ * `arrow.flight.protocol.sql.SqlTransactionIsolationLevel`.
+ */
+ SQL_SUPPORTED_TRANSACTIONS_ISOLATION_LEVELS = 564,
+
+ /*
+ * Retrieves a boolean value indicating whether a data definition statement within a
+ * transaction forces the transaction to commit.
+ *
+ * Returns:
+ * - false: if a data definition statement within a transaction does not force the
+ * transaction to commit;
+ * - true: if a data definition statement within a transaction forces the transaction
+ * to commit.
+ */
+ SQL_DATA_DEFINITION_CAUSES_TRANSACTION_COMMIT = 565,
+
+ /*
+ * Retrieves a boolean value indicating whether a data definition statement within a
+ * transaction is ignored.
+ *
+ * Returns:
+ * - false: if a data definition statement within a transaction is taken into account;
+ * - true: a data definition statement within a transaction is ignored.
+ */
+ SQL_DATA_DEFINITIONS_IN_TRANSACTIONS_IGNORED = 566,
+
+ /*
+ * Retrieves an int32 bitmask value representing the supported result set types.
+ * The returned bitmask should be parsed in order to retrieve the supported result set
+ * types.
+ *
+ * For instance:
+ * - return 0 (\b0) => [] (no supported result set types);
+ * - return 1 (\b1) => [SQL_RESULT_SET_TYPE_UNSPECIFIED];
+ * - return 2 (\b10) => [SQL_RESULT_SET_TYPE_FORWARD_ONLY];
+ * - return 3 (\b11) => [SQL_RESULT_SET_TYPE_UNSPECIFIED,
+ * SQL_RESULT_SET_TYPE_FORWARD_ONLY];
+ * - return 4 (\b100) => [SQL_RESULT_SET_TYPE_SCROLL_INSENSITIVE];
+ * - return 5 (\b101) => [SQL_RESULT_SET_TYPE_UNSPECIFIED,
+ * SQL_RESULT_SET_TYPE_SCROLL_INSENSITIVE];
+ * - return 6 (\b110) => [SQL_RESULT_SET_TYPE_FORWARD_ONLY,
+ * SQL_RESULT_SET_TYPE_SCROLL_INSENSITIVE];
+ * - return 7 (\b111) => [SQL_RESULT_SET_TYPE_UNSPECIFIED,
+ * SQL_RESULT_SET_TYPE_FORWARD_ONLY, SQL_RESULT_SET_TYPE_SCROLL_INSENSITIVE];
+ * - return 8 (\b1000) => [SQL_RESULT_SET_TYPE_SCROLL_SENSITIVE];
+ * - ...
+ * Valid result set types are described under
+ * `arrow.flight.protocol.sql.SqlSupportedResultSetType`.
+ */
+ SQL_SUPPORTED_RESULT_SET_TYPES = 567,
+
+ /*
+ * Returns an int32 bitmask value concurrency types supported for
+ * `arrow.flight.protocol.sql.SqlSupportedResultSetType.SQL_RESULT_SET_TYPE_UNSPECIFIED`.
+ *
+ * For instance:
+ * - return 0 (\b0) => [] (no supported concurrency types for this result set type)
+ * - return 1 (\b1) => [SQL_RESULT_SET_CONCURRENCY_UNSPECIFIED]
+ * - return 2 (\b10) => [SQL_RESULT_SET_CONCURRENCY_READ_ONLY]
+ * - return 3 (\b11) => [SQL_RESULT_SET_CONCURRENCY_UNSPECIFIED,
+ * SQL_RESULT_SET_CONCURRENCY_READ_ONLY]
+ * - return 4 (\b100) => [SQL_RESULT_SET_CONCURRENCY_UPDATABLE]
+ * - return 5 (\b101) => [SQL_RESULT_SET_CONCURRENCY_UNSPECIFIED,
+ * SQL_RESULT_SET_CONCURRENCY_UPDATABLE]
+ * - return 6 (\b110) => [SQL_RESULT_SET_CONCURRENCY_READ_ONLY,
+ * SQL_RESULT_SET_CONCURRENCY_UPDATABLE]
+ * - return 7 (\b111) => [SQL_RESULT_SET_CONCURRENCY_UNSPECIFIED,
+ * SQL_RESULT_SET_CONCURRENCY_READ_ONLY, SQL_RESULT_SET_CONCURRENCY_UPDATABLE] Valid
+ * result set types are described under
+ * `arrow.flight.protocol.sql.SqlSupportedResultSetConcurrency`.
+ */
+ SQL_SUPPORTED_CONCURRENCIES_FOR_RESULT_SET_UNSPECIFIED = 568,
+
+ /*
+ * Returns an int32 bitmask value concurrency types supported for
+ * `arrow.flight.protocol.sql.SqlSupportedResultSetType.SQL_RESULT_SET_TYPE_FORWARD_ONLY`.
+ *
+ * For instance:
+ * - return 0 (\b0) => [] (no supported concurrency types for this result set type)
+ * - return 1 (\b1) => [SQL_RESULT_SET_CONCURRENCY_UNSPECIFIED]
+ * - return 2 (\b10) => [SQL_RESULT_SET_CONCURRENCY_READ_ONLY]
+ * - return 3 (\b11) => [SQL_RESULT_SET_CONCURRENCY_UNSPECIFIED,
+ * SQL_RESULT_SET_CONCURRENCY_READ_ONLY]
+ * - return 4 (\b100) => [SQL_RESULT_SET_CONCURRENCY_UPDATABLE]
+ * - return 5 (\b101) => [SQL_RESULT_SET_CONCURRENCY_UNSPECIFIED,
+ * SQL_RESULT_SET_CONCURRENCY_UPDATABLE]
+ * - return 6 (\b110) => [SQL_RESULT_SET_CONCURRENCY_READ_ONLY,
+ * SQL_RESULT_SET_CONCURRENCY_UPDATABLE]
+ * - return 7 (\b111) => [SQL_RESULT_SET_CONCURRENCY_UNSPECIFIED,
+ * SQL_RESULT_SET_CONCURRENCY_READ_ONLY, SQL_RESULT_SET_CONCURRENCY_UPDATABLE] Valid
+ * result set types are described under
+ * `arrow.flight.protocol.sql.SqlSupportedResultSetConcurrency`.
+ */
+ SQL_SUPPORTED_CONCURRENCIES_FOR_RESULT_SET_FORWARD_ONLY = 569,
+
+ /*
+ * Returns an int32 bitmask value concurrency types supported for
+ * `arrow.flight.protocol.sql.SqlSupportedResultSetType.SQL_RESULT_SET_TYPE_SCROLL_SENSITIVE`.
+ *
+ * For instance:
+ * - return 0 (\b0) => [] (no supported concurrency types for this result set type)
+ * - return 1 (\b1) => [SQL_RESULT_SET_CONCURRENCY_UNSPECIFIED]
+ * - return 2 (\b10) => [SQL_RESULT_SET_CONCURRENCY_READ_ONLY]
+ * - return 3 (\b11) => [SQL_RESULT_SET_CONCURRENCY_UNSPECIFIED,
+ * SQL_RESULT_SET_CONCURRENCY_READ_ONLY]
+ * - return 4 (\b100) => [SQL_RESULT_SET_CONCURRENCY_UPDATABLE]
+ * - return 5 (\b101) => [SQL_RESULT_SET_CONCURRENCY_UNSPECIFIED,
+ * SQL_RESULT_SET_CONCURRENCY_UPDATABLE]
+ * - return 6 (\b110) => [SQL_RESULT_SET_CONCURRENCY_READ_ONLY,
+ * SQL_RESULT_SET_CONCURRENCY_UPDATABLE]
+ * - return 7 (\b111) => [SQL_RESULT_SET_CONCURRENCY_UNSPECIFIED,
+ * SQL_RESULT_SET_CONCURRENCY_READ_ONLY, SQL_RESULT_SET_CONCURRENCY_UPDATABLE] Valid
+ * result set types are described under
+ * `arrow.flight.protocol.sql.SqlSupportedResultSetConcurrency`.
+ */
+ SQL_SUPPORTED_CONCURRENCIES_FOR_RESULT_SET_SCROLL_SENSITIVE = 570,
+
+ /*
+ * Returns an int32 bitmask value concurrency types supported for
+ * `arrow.flight.protocol.sql.SqlSupportedResultSetType.SQL_RESULT_SET_TYPE_SCROLL_INSENSITIVE`.
+ *
+ * For instance:
+ * - return 0 (\b0) => [] (no supported concurrency types for this result set type)
+ * - return 1 (\b1) => [SQL_RESULT_SET_CONCURRENCY_UNSPECIFIED]
+ * - return 2 (\b10) => [SQL_RESULT_SET_CONCURRENCY_READ_ONLY]
+ * - return 3 (\b11) => [SQL_RESULT_SET_CONCURRENCY_UNSPECIFIED,
+ * SQL_RESULT_SET_CONCURRENCY_READ_ONLY]
+ * - return 4 (\b100) => [SQL_RESULT_SET_CONCURRENCY_UPDATABLE]
+ * - return 5 (\b101) => [SQL_RESULT_SET_CONCURRENCY_UNSPECIFIED,
+ * SQL_RESULT_SET_CONCURRENCY_UPDATABLE]
+ * - return 6 (\b110) => [SQL_RESULT_SET_CONCURRENCY_READ_ONLY,
+ * SQL_RESULT_SET_CONCURRENCY_UPDATABLE]
+ * - return 7 (\b111) => [SQL_RESULT_SET_CONCURRENCY_UNSPECIFIED,
+ * SQL_RESULT_SET_CONCURRENCY_READ_ONLY, SQL_RESULT_SET_CONCURRENCY_UPDATABLE] Valid
+ * result set types are described under
+ * `arrow.flight.protocol.sql.SqlSupportedResultSetConcurrency`.
+ */
+ SQL_SUPPORTED_CONCURRENCIES_FOR_RESULT_SET_SCROLL_INSENSITIVE = 571,
+
+ /*
+ * Retrieves a boolean value indicating whether this database supports batch updates.
+ *
+ * - false: if this database does not support batch updates;
+ * - true: if this database supports batch updates.
+ */
+ SQL_BATCH_UPDATES_SUPPORTED = 572,
+
+ /*
+ * Retrieves a boolean value indicating whether this database supports savepoints.
+ *
+ * Returns:
+ * - false: if this database does not support savepoints;
+ * - true: if this database supports savepoints.
+ */
+ SQL_SAVEPOINTS_SUPPORTED = 573,
+
+ /*
+ * Retrieves a boolean value indicating whether named parameters are supported in
+ * callable statements.
+ *
+ * Returns:
+ * - false: if named parameters in callable statements are unsupported;
+ * - true: if named parameters in callable statements are supported.
+ */
+ SQL_NAMED_PARAMETERS_SUPPORTED = 574,
+
+ /*
+ * Retrieves a boolean value indicating whether updates made to a LOB are made on a
+ * copy or directly to the LOB.
+ *
+ * Returns:
+ * - false: if updates made to a LOB are made directly to the LOB;
+ * - true: if updates made to a LOB are made on a copy.
+ */
+ SQL_LOCATORS_UPDATE_COPY = 575,
+
+ /*
+ * Retrieves a boolean value indicating whether invoking user-defined or vendor
+ * functions using the stored procedure escape syntax is supported.
+ *
+ * Returns:
+ * - false: if invoking user-defined or vendor functions using the stored procedure
+ * escape syntax is unsupported;
+ * - true: if invoking user-defined or vendor functions using the stored procedure
+ * escape syntax is supported.
+ */
+ SQL_STORED_FUNCTIONS_USING_CALL_SYNTAX_SUPPORTED = 576,
+ };
+
+ enum SqlSupportedCaseSensitivity {
+ SQL_CASE_SENSITIVITY_UNKNOWN = 0,
+ SQL_CASE_SENSITIVITY_CASE_INSENSITIVE = 1,
+ SQL_CASE_SENSITIVITY_UPPERCASE = 2,
+ };
+
+ enum SqlNullOrdering {
+ SQL_NULLS_SORTED_HIGH = 0,
+ SQL_NULLS_SORTED_LOW = 1,
+ SQL_NULLS_SORTED_AT_START = 2,
+ SQL_NULLS_SORTED_AT_END = 3,
+ };
+
+ enum SqlSupportsConvert {
+ SQL_CONVERT_BIGINT = 0,
+ SQL_CONVERT_BINARY = 1,
+ SQL_CONVERT_BIT = 2,
+ SQL_CONVERT_CHAR = 3,
+ SQL_CONVERT_DATE = 4,
+ SQL_CONVERT_DECIMAL = 5,
+ SQL_CONVERT_FLOAT = 6,
+ SQL_CONVERT_INTEGER = 7,
+ SQL_CONVERT_INTERVAL_DAY_TIME = 8,
+ SQL_CONVERT_INTERVAL_YEAR_MONTH = 9,
+ SQL_CONVERT_LONGVARBINARY = 10,
+ SQL_CONVERT_LONGVARCHAR = 11,
+ SQL_CONVERT_NUMERIC = 12,
+ SQL_CONVERT_REAL = 13,
+ SQL_CONVERT_SMALLINT = 14,
+ SQL_CONVERT_TIME = 15,
+ SQL_CONVERT_TIMESTAMP = 16,
+ SQL_CONVERT_TINYINT = 17,
+ SQL_CONVERT_VARBINARY = 18,
+ SQL_CONVERT_VARCHAR = 19,
+ };
+};
+
+/// \brief Table reference, optionally containing table's catalog and db_schema.
+struct TableRef {
+ util::optional<std::string> catalog;
+ util::optional<std::string> db_schema;
+ std::string table;
+};
+
+} // namespace sql
+} // namespace flight
+} // namespace arrow
diff --git a/cpp/vcpkg.json b/cpp/vcpkg.json
index 64ece20..5566438 100644
--- a/cpp/vcpkg.json
+++ b/cpp/vcpkg.json
@@ -44,6 +44,7 @@
"rapidjson",
"re2",
"snappy",
+ "sqlite3",
"thrift",
"utf8proc",
"zlib",
diff --git a/docker-compose.yml b/docker-compose.yml
index 834304d..91f4cbf 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -269,6 +269,7 @@ services:
ARROW_CXXFLAGS: "-Og" # Shrink test runtime by enabling minimal optimizations
ARROW_ENABLE_TIMING_TESTS: # inherit
ARROW_FLIGHT: "OFF"
+ ARROW_FLIGHT_SQL: "OFF"
ARROW_GANDIVA: "OFF"
ARROW_JEMALLOC: "OFF"
ARROW_RUNTIME_SIMD_LEVEL: "AVX2" # AVX512 not supported by Valgrind (ARROW-9851)
@@ -1022,6 +1023,7 @@ services:
environment:
<<: *ccache
ARROW_FLIGHT: "OFF"
+ ARROW_FLIGHT_SQL: "OFF"
ARROW_GANDIVA: "OFF"
volumes: *conda-volumes
command:
@@ -1617,6 +1619,7 @@ services:
environment:
<<: *ccache
ARROW_FLIGHT: "OFF"
+ ARROW_FLIGHT_SQL: "OFF"
ARROW_GANDIVA: "OFF"
ARROW_PLASMA: "OFF"
ARROW_HIVESERVER2: "ON"