From c3bfc21d7b6c333a37f03d91dc08bbb1267ecbda Mon Sep 17 00:00:00 2001 From: tokoko Date: Sun, 19 Apr 2026 00:03:41 +0400 Subject: [PATCH 1/3] [Format][FlightSQL][C++] Add dialect-related SqlInfo codes --- cpp/src/arrow/flight/sql/types.h | 61 ++++++++++++++++++++++++++++++++ format/FlightSql.proto | 60 +++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) diff --git a/cpp/src/arrow/flight/sql/types.h b/cpp/src/arrow/flight/sql/types.h index fe90c08ed201..16eb7a6321c9 100644 --- a/cpp/src/arrow/flight/sql/types.h +++ b/cpp/src/arrow/flight/sql/types.h @@ -849,6 +849,36 @@ struct ARROW_FLIGHT_SQL_EXPORT SqlInfoOptions { /// escape syntax is supported. SQL_STORED_FUNCTIONS_USING_CALL_SYNTAX_SUPPORTED = 576, + /// Retrieves an int32 describing the syntax accepted for combined row + /// limiting and offset in SELECT statements. + /// + /// The possible values are listed in + /// `arrow.flight.protocol.sql.SqlLimitOffsetSyntax`. + SQL_LIMIT_OFFSET_SYNTAX = 577, + + /// Retrieves an int32 describing the syntax accepted for explicit null + /// ordering in ORDER BY (e.g. NULLS FIRST / NULLS LAST). Distinct from + /// SQL_NULL_ORDERING (507), which reports the server's default null + /// ordering rather than which explicit syntax parses. + /// + /// The possible values are listed in + /// `arrow.flight.protocol.sql.SqlNullsOrderingSyntax`. + SQL_NULLS_ORDERING_SYNTAX = 578, + + /// Retrieves an int32 describing the accepted literal syntax for boolean + /// values. + /// + /// The possible values are listed in + /// `arrow.flight.protocol.sql.SqlBooleanLiteralSyntax`. + SQL_BOOLEAN_LITERAL_SYNTAX = 579, + + /// Retrieves an int32 describing the accepted literal syntax for date, + /// time, and timestamp values. + /// + /// The possible values are listed in + /// `arrow.flight.protocol.sql.SqlDatetimeLiteralSyntax`. + SQL_DATETIME_LITERAL_SYNTAX = 580, + /// @} }; @@ -900,6 +930,37 @@ struct ARROW_FLIGHT_SQL_EXPORT SqlInfoOptions { SQL_CONVERT_VARBINARY = 18, SQL_CONVERT_VARCHAR = 19, }; + + /// Syntax for combined row limiting and offset. + enum SqlLimitOffsetSyntax { + /// LIMIT n [OFFSET m] (PostgreSQL, MySQL, SQLite, DuckDB, Snowflake, ...) + SQL_LIMIT_OFFSET_SYNTAX_LIMIT_OFFSET = 0, + /// OFFSET m ROWS FETCH NEXT n ROWS ONLY (SQL Server, Oracle, ANSI) + SQL_LIMIT_OFFSET_SYNTAX_OFFSET_FETCH = 1, + }; + + /// Syntax accepted for explicit null ordering in ORDER BY. + enum SqlNullsOrderingSyntax { + SQL_NULLS_ORDERING_SYNTAX_UNSUPPORTED = 0, + /// ORDER BY col [ASC|DESC] NULLS FIRST|LAST + SQL_NULLS_ORDERING_SYNTAX_NULLS_FIRST_LAST = 1, + }; + + /// Accepted literal syntax for boolean values. + enum SqlBooleanLiteralSyntax { + /// TRUE / FALSE keywords. + SQL_BOOLEAN_LITERAL_TRUE_FALSE = 0, + /// Integer 1 / 0. + SQL_BOOLEAN_LITERAL_INT_ONE_ZERO = 1, + }; + + /// Accepted literal syntax for date, time, and timestamp values. + enum SqlDatetimeLiteralSyntax { + /// DATE '2026-01-01', TIME '12:00:00', TIMESTAMP '2026-01-01 12:00:00'. + SQL_DATETIME_LITERAL_ANSI_KEYWORD = 0, + /// Bare quoted string, e.g. '2026-01-01' or '2026-01-01 12:00:00'. + SQL_DATETIME_LITERAL_BARE_STRING = 1, + }; }; /// \brief A SQL %table reference, optionally containing table's catalog and db_schema. diff --git a/format/FlightSql.proto b/format/FlightSql.proto index 90e6e5baeb21..fa7ec04aeed0 100644 --- a/format/FlightSql.proto +++ b/format/FlightSql.proto @@ -833,6 +833,39 @@ enum SqlInfo { * - true: if invoking user-defined or vendor functions using the stored procedure escape syntax is supported. */ SQL_STORED_FUNCTIONS_USING_CALL_SYNTAX_SUPPORTED = 576; + + /* + * Retrieves an int32 describing the syntax accepted for combined row limiting + * and offset in SELECT statements. + * + * The possible values are listed in `arrow.flight.protocol.sql.SqlLimitOffsetSyntax`. + */ + SQL_LIMIT_OFFSET_SYNTAX = 577; + + /* + * Retrieves an int32 describing the syntax accepted for explicit null + * ordering in ORDER BY (e.g. `NULLS FIRST` / `NULLS LAST`). Distinct from + * SQL_NULL_ORDERING (507), which reports the server's default null + * ordering rather than which explicit syntax parses. + * + * The possible values are listed in `arrow.flight.protocol.sql.SqlNullsOrderingSyntax`. + */ + SQL_NULLS_ORDERING_SYNTAX = 578; + + /* + * Retrieves an int32 describing the accepted literal syntax for boolean values. + * + * The possible values are listed in `arrow.flight.protocol.sql.SqlBooleanLiteralSyntax`. + */ + SQL_BOOLEAN_LITERAL_SYNTAX = 579; + + /* + * Retrieves an int32 describing the accepted literal syntax for date, + * time, and timestamp values. + * + * The possible values are listed in `arrow.flight.protocol.sql.SqlDatetimeLiteralSyntax`. + */ + SQL_DATETIME_LITERAL_SYNTAX = 580; } // The level of support for Flight SQL transaction RPCs. @@ -957,6 +990,33 @@ enum SqlSupportsConvert { SQL_CONVERT_VARCHAR = 19; } +enum SqlLimitOffsetSyntax { + // LIMIT n [OFFSET m] (PostgreSQL, MySQL, SQLite, DuckDB, Snowflake, ...) + SQL_LIMIT_OFFSET_SYNTAX_LIMIT_OFFSET = 0; + // OFFSET m ROWS FETCH NEXT n ROWS ONLY (SQL Server, Oracle, ANSI) + SQL_LIMIT_OFFSET_SYNTAX_OFFSET_FETCH = 1; +} + +enum SqlNullsOrderingSyntax { + SQL_NULLS_ORDERING_SYNTAX_UNSUPPORTED = 0; + // ORDER BY col [ASC|DESC] NULLS FIRST|LAST + SQL_NULLS_ORDERING_SYNTAX_NULLS_FIRST_LAST = 1; +} + +enum SqlBooleanLiteralSyntax { + // TRUE / FALSE keywords + SQL_BOOLEAN_LITERAL_TRUE_FALSE = 0; + // Integer 1 / 0 + SQL_BOOLEAN_LITERAL_INT_ONE_ZERO = 1; +} + +enum SqlDatetimeLiteralSyntax { + // DATE '2026-01-01', TIME '12:00:00', TIMESTAMP '2026-01-01 12:00:00' + SQL_DATETIME_LITERAL_ANSI_KEYWORD = 0; + // Bare quoted string, e.g. '2026-01-01' or '2026-01-01 12:00:00' + SQL_DATETIME_LITERAL_BARE_STRING = 1; +} + /** * The JDBC/ODBC-defined type of any object. * All the values here are the same as in the JDBC and ODBC specs. From d253a696d62d987f720215c1e4159360d83b84e2 Mon Sep 17 00:00:00 2001 From: tokoko Date: Sun, 19 Apr 2026 00:44:08 +0400 Subject: [PATCH 2/3] [Format][FlightSQL][C++] Add dialect-related SqlInfo codes --- cpp/src/arrow/flight/sql/types.h | 52 ++++++++++---------- format/FlightSql.proto | 81 +++++++++++++++++++++++--------- 2 files changed, 84 insertions(+), 49 deletions(-) diff --git a/cpp/src/arrow/flight/sql/types.h b/cpp/src/arrow/flight/sql/types.h index 16eb7a6321c9..2c4fad069f03 100644 --- a/cpp/src/arrow/flight/sql/types.h +++ b/cpp/src/arrow/flight/sql/types.h @@ -849,35 +849,27 @@ struct ARROW_FLIGHT_SQL_EXPORT SqlInfoOptions { /// escape syntax is supported. SQL_STORED_FUNCTIONS_USING_CALL_SYNTAX_SUPPORTED = 576, - /// Retrieves an int32 describing the syntax accepted for combined row - /// limiting and offset in SELECT statements. - /// - /// The possible values are listed in + /// Retrieves the supported row-limit and offset grammars as an int32 + /// bitmask. Valid grammars are described under /// `arrow.flight.protocol.sql.SqlLimitOffsetSyntax`. - SQL_LIMIT_OFFSET_SYNTAX = 577, + SQL_SUPPORTED_LIMIT_OFFSET = 577, - /// Retrieves an int32 describing the syntax accepted for explicit null - /// ordering in ORDER BY (e.g. NULLS FIRST / NULLS LAST). Distinct from - /// SQL_NULL_ORDERING (507), which reports the server's default null - /// ordering rather than which explicit syntax parses. - /// - /// The possible values are listed in + /// Retrieves the supported syntaxes for explicit null ordering in + /// ORDER BY as an int32 bitmask. Distinct from SQL_NULL_ORDERING (507), + /// which reports the server's default null ordering rather than which + /// explicit syntax parses. Valid syntaxes are described under /// `arrow.flight.protocol.sql.SqlNullsOrderingSyntax`. - SQL_NULLS_ORDERING_SYNTAX = 578, + SQL_SUPPORTED_NULLS_ORDERING = 578, - /// Retrieves an int32 describing the accepted literal syntax for boolean - /// values. - /// - /// The possible values are listed in + /// Retrieves the supported literal syntaxes for boolean values as an + /// int32 bitmask. Valid syntaxes are described under /// `arrow.flight.protocol.sql.SqlBooleanLiteralSyntax`. - SQL_BOOLEAN_LITERAL_SYNTAX = 579, + SQL_SUPPORTED_BOOLEAN_LITERAL = 579, - /// Retrieves an int32 describing the accepted literal syntax for date, - /// time, and timestamp values. - /// - /// The possible values are listed in - /// `arrow.flight.protocol.sql.SqlDatetimeLiteralSyntax`. - SQL_DATETIME_LITERAL_SYNTAX = 580, + /// Retrieves the supported literal syntaxes for date, time, and + /// timestamp values as an int32 bitmask. Valid syntaxes are described + /// under `arrow.flight.protocol.sql.SqlDatetimeLiteralSyntax`. + SQL_SUPPORTED_DATETIME_LITERAL = 580, /// @} }; @@ -931,19 +923,23 @@ struct ARROW_FLIGHT_SQL_EXPORT SqlInfoOptions { SQL_CONVERT_VARCHAR = 19, }; - /// Syntax for combined row limiting and offset. + /// Grammar for combined row limiting and offset. Variants differ in their + /// offset behavior: LIMIT accepts optional OFFSET, FETCH requires a + /// preceding OFFSET clause, TOP is limit-only. enum SqlLimitOffsetSyntax { /// LIMIT n [OFFSET m] (PostgreSQL, MySQL, SQLite, DuckDB, Snowflake, ...) - SQL_LIMIT_OFFSET_SYNTAX_LIMIT_OFFSET = 0, + SQL_LIMIT_OFFSET_LIMIT = 0, /// OFFSET m ROWS FETCH NEXT n ROWS ONLY (SQL Server, Oracle, ANSI) - SQL_LIMIT_OFFSET_SYNTAX_OFFSET_FETCH = 1, + SQL_LIMIT_OFFSET_FETCH = 1, + /// SELECT TOP n ... (SQL Server, Sybase, Snowflake). Limit-only; does + /// not compose with offset. + SQL_LIMIT_OFFSET_TOP = 2, }; /// Syntax accepted for explicit null ordering in ORDER BY. enum SqlNullsOrderingSyntax { - SQL_NULLS_ORDERING_SYNTAX_UNSUPPORTED = 0, /// ORDER BY col [ASC|DESC] NULLS FIRST|LAST - SQL_NULLS_ORDERING_SYNTAX_NULLS_FIRST_LAST = 1, + SQL_NULLS_ORDERING_FIRST_LAST = 0, }; /// Accepted literal syntax for boolean values. diff --git a/format/FlightSql.proto b/format/FlightSql.proto index fa7ec04aeed0..7288d2a119e5 100644 --- a/format/FlightSql.proto +++ b/format/FlightSql.proto @@ -835,37 +835,74 @@ enum SqlInfo { SQL_STORED_FUNCTIONS_USING_CALL_SYNTAX_SUPPORTED = 576; /* - * Retrieves an int32 describing the syntax accepted for combined row limiting - * and offset in SELECT statements. + * Retrieves the supported row-limit and offset grammars. Variants differ + * in their offset behavior: SQL_LIMIT_OFFSET_LIMIT accepts an optional + * OFFSET, SQL_LIMIT_OFFSET_FETCH requires a preceding OFFSET clause, and + * SQL_LIMIT_OFFSET_TOP is limit-only and does not compose with offset. * - * The possible values are listed in `arrow.flight.protocol.sql.SqlLimitOffsetSyntax`. + * Returns an int32 bitmask value representing the supported grammars. + * The returned bitmask should be parsed in order to retrieve the supported + * grammars. + * + * For instance: + * - return 0 (\b0) => [] (no row-limit grammar is supported); + * - return 1 (\b1) => [SQL_LIMIT_OFFSET_LIMIT]; + * - return 2 (\b10) => [SQL_LIMIT_OFFSET_FETCH]; + * - return 3 (\b11) => [SQL_LIMIT_OFFSET_LIMIT, SQL_LIMIT_OFFSET_FETCH]; + * - return 4 (\b100) => [SQL_LIMIT_OFFSET_TOP]; + * - return 6 (\b110) => [SQL_LIMIT_OFFSET_FETCH, SQL_LIMIT_OFFSET_TOP]. + * Valid grammars are described under `arrow.flight.protocol.sql.SqlLimitOffsetSyntax`. */ - SQL_LIMIT_OFFSET_SYNTAX = 577; + SQL_SUPPORTED_LIMIT_OFFSET = 577; /* - * Retrieves an int32 describing the syntax accepted for explicit null - * ordering in ORDER BY (e.g. `NULLS FIRST` / `NULLS LAST`). Distinct from - * SQL_NULL_ORDERING (507), which reports the server's default null - * ordering rather than which explicit syntax parses. + * Retrieves the supported syntaxes for explicit null ordering in ORDER BY. + * Distinct from SQL_NULL_ORDERING (507), which reports the server's default + * null ordering rather than which explicit syntax parses. * - * The possible values are listed in `arrow.flight.protocol.sql.SqlNullsOrderingSyntax`. + * Returns an int32 bitmask value representing the supported syntaxes. + * The returned bitmask should be parsed in order to retrieve the supported + * syntaxes. + * + * For instance: + * - return 0 (\b0) => [] (no explicit null-ordering syntax is supported); + * - return 1 (\b1) => [SQL_NULLS_ORDERING_FIRST_LAST]. + * Valid syntaxes are described under `arrow.flight.protocol.sql.SqlNullsOrderingSyntax`. */ - SQL_NULLS_ORDERING_SYNTAX = 578; + SQL_SUPPORTED_NULLS_ORDERING = 578; /* - * Retrieves an int32 describing the accepted literal syntax for boolean values. + * Retrieves the supported literal syntaxes for boolean values. * - * The possible values are listed in `arrow.flight.protocol.sql.SqlBooleanLiteralSyntax`. + * Returns an int32 bitmask value representing the supported syntaxes. + * The returned bitmask should be parsed in order to retrieve the supported + * syntaxes. + * + * For instance: + * - return 0 (\b0) => [] (no boolean literal syntax is supported); + * - return 1 (\b1) => [SQL_BOOLEAN_LITERAL_TRUE_FALSE]; + * - return 2 (\b10) => [SQL_BOOLEAN_LITERAL_INT_ONE_ZERO]; + * - return 3 (\b11) => [SQL_BOOLEAN_LITERAL_TRUE_FALSE, SQL_BOOLEAN_LITERAL_INT_ONE_ZERO]. + * Valid syntaxes are described under `arrow.flight.protocol.sql.SqlBooleanLiteralSyntax`. */ - SQL_BOOLEAN_LITERAL_SYNTAX = 579; + SQL_SUPPORTED_BOOLEAN_LITERAL = 579; /* - * Retrieves an int32 describing the accepted literal syntax for date, - * time, and timestamp values. + * Retrieves the supported literal syntaxes for date, time, and timestamp + * values. * - * The possible values are listed in `arrow.flight.protocol.sql.SqlDatetimeLiteralSyntax`. + * Returns an int32 bitmask value representing the supported syntaxes. + * The returned bitmask should be parsed in order to retrieve the supported + * syntaxes. + * + * For instance: + * - return 0 (\b0) => [] (no datetime literal syntax is supported); + * - return 1 (\b1) => [SQL_DATETIME_LITERAL_ANSI_KEYWORD]; + * - return 2 (\b10) => [SQL_DATETIME_LITERAL_BARE_STRING]; + * - return 3 (\b11) => [SQL_DATETIME_LITERAL_ANSI_KEYWORD, SQL_DATETIME_LITERAL_BARE_STRING]. + * Valid syntaxes are described under `arrow.flight.protocol.sql.SqlDatetimeLiteralSyntax`. */ - SQL_DATETIME_LITERAL_SYNTAX = 580; + SQL_SUPPORTED_DATETIME_LITERAL = 580; } // The level of support for Flight SQL transaction RPCs. @@ -992,15 +1029,17 @@ enum SqlSupportsConvert { enum SqlLimitOffsetSyntax { // LIMIT n [OFFSET m] (PostgreSQL, MySQL, SQLite, DuckDB, Snowflake, ...) - SQL_LIMIT_OFFSET_SYNTAX_LIMIT_OFFSET = 0; + SQL_LIMIT_OFFSET_LIMIT = 0; // OFFSET m ROWS FETCH NEXT n ROWS ONLY (SQL Server, Oracle, ANSI) - SQL_LIMIT_OFFSET_SYNTAX_OFFSET_FETCH = 1; + SQL_LIMIT_OFFSET_FETCH = 1; + // SELECT TOP n ... (SQL Server, Sybase, Snowflake). Limit-only; does not + // compose with offset. + SQL_LIMIT_OFFSET_TOP = 2; } enum SqlNullsOrderingSyntax { - SQL_NULLS_ORDERING_SYNTAX_UNSUPPORTED = 0; // ORDER BY col [ASC|DESC] NULLS FIRST|LAST - SQL_NULLS_ORDERING_SYNTAX_NULLS_FIRST_LAST = 1; + SQL_NULLS_ORDERING_FIRST_LAST = 0; } enum SqlBooleanLiteralSyntax { From 18eb1855d04c5cc7f343b53862a8e100601b2c24 Mon Sep 17 00:00:00 2001 From: tokoko Date: Sun, 11 Oct 2026 12:01:22 +0400 Subject: [PATCH 3/3] feat: switch from building literals to bind parameters --- cpp/src/arrow/flight/sql/types.h | 85 +++++++++++++-------- format/FlightSql.proto | 123 +++++++++++++++++++++---------- 2 files changed, 139 insertions(+), 69 deletions(-) diff --git a/cpp/src/arrow/flight/sql/types.h b/cpp/src/arrow/flight/sql/types.h index 2c4fad069f03..57f8c1c7b823 100644 --- a/cpp/src/arrow/flight/sql/types.h +++ b/cpp/src/arrow/flight/sql/types.h @@ -850,7 +850,9 @@ struct ARROW_FLIGHT_SQL_EXPORT SqlInfoOptions { SQL_STORED_FUNCTIONS_USING_CALL_SYNTAX_SUPPORTED = 576, /// Retrieves the supported row-limit and offset grammars as an int32 - /// bitmask. Valid grammars are described under + /// bitmask. Limiting and offsetting are reported separately, and + /// SQL_LIMIT_OFFSET_FETCH_WITHOUT_ORDER_BY tells whether the FETCH + /// grammars need an ORDER BY clause. Valid grammars are described under /// `arrow.flight.protocol.sql.SqlLimitOffsetSyntax`. SQL_SUPPORTED_LIMIT_OFFSET = 577, @@ -861,15 +863,23 @@ struct ARROW_FLIGHT_SQL_EXPORT SqlInfoOptions { /// `arrow.flight.protocol.sql.SqlNullsOrderingSyntax`. SQL_SUPPORTED_NULLS_ORDERING = 578, - /// Retrieves the supported literal syntaxes for boolean values as an - /// int32 bitmask. Valid syntaxes are described under - /// `arrow.flight.protocol.sql.SqlBooleanLiteralSyntax`. - SQL_SUPPORTED_BOOLEAN_LITERAL = 579, - - /// Retrieves the supported literal syntaxes for date, time, and - /// timestamp values as an int32 bitmask. Valid syntaxes are described - /// under `arrow.flight.protocol.sql.SqlDatetimeLiteralSyntax`. - SQL_SUPPORTED_DATETIME_LITERAL = 580, + /// Retrieves the supported ways of escaping the wildcard characters '%' + /// and '_' in a LIKE pattern as an int32 bitmask. Supersedes + /// SQL_SUPPORTS_LIKE_ESCAPE_CLAUSE (523), which cannot describe a server + /// that escapes without an ESCAPE clause. Valid syntaxes are described + /// under `arrow.flight.protocol.sql.SqlLikeEscapeSyntax`. + SQL_SUPPORTED_LIKE_ESCAPE = 579, + + /// Retrieves the supported spellings of a parameter marker in a prepared + /// statement as an int32 bitmask. Clients that generate SQL are + /// encouraged to send values as bound parameters instead of writing them + /// as literals, whose spelling differs between servers for nearly every + /// type. A syntax must only be reported if a marker is accepted wherever + /// a value is compared with a column. Parameters are bound by position; + /// for the numbered syntaxes a client should number the markers from 1 in + /// the order they appear and use each number once. Valid syntaxes are + /// described under `arrow.flight.protocol.sql.SqlParameterMarkerSyntax`. + SQL_SUPPORTED_PARAMETER_MARKER = 580, /// @} }; @@ -923,17 +933,28 @@ struct ARROW_FLIGHT_SQL_EXPORT SqlInfoOptions { SQL_CONVERT_VARCHAR = 19, }; - /// Grammar for combined row limiting and offset. Variants differ in their - /// offset behavior: LIMIT accepts optional OFFSET, FETCH requires a - /// preceding OFFSET clause, TOP is limit-only. + /// Grammars for row limiting and offset. Limiting and offsetting are + /// separate values because servers often accept a grammar for limiting that + /// they do not accept together with an offset. enum SqlLimitOffsetSyntax { - /// LIMIT n [OFFSET m] (PostgreSQL, MySQL, SQLite, DuckDB, Snowflake, ...) + /// LIMIT n (PostgreSQL, MySQL, SQLite, DuckDB, Trino, ...) SQL_LIMIT_OFFSET_LIMIT = 0, - /// OFFSET m ROWS FETCH NEXT n ROWS ONLY (SQL Server, Oracle, ANSI) - SQL_LIMIT_OFFSET_FETCH = 1, + /// LIMIT n OFFSET m (PostgreSQL, MySQL, SQLite, DuckDB, ...). Not implied + /// by SQL_LIMIT_OFFSET_LIMIT: Trino and Presto accept LIMIT n but not this. + SQL_LIMIT_OFFSET_LIMIT_OFFSET = 1, + /// FETCH FIRST n ROWS ONLY, with no OFFSET clause (ANSI, Oracle, + /// PostgreSQL, Trino) + SQL_LIMIT_OFFSET_FETCH_FIRST = 2, + /// OFFSET m ROWS FETCH NEXT n ROWS ONLY (ANSI, SQL Server, Oracle, + /// PostgreSQL) + SQL_LIMIT_OFFSET_OFFSET_FETCH = 3, /// SELECT TOP n ... (SQL Server, Sybase, Snowflake). Limit-only; does /// not compose with offset. - SQL_LIMIT_OFFSET_TOP = 2, + SQL_LIMIT_OFFSET_TOP = 4, + /// The FETCH grammars above are accepted in a query with no ORDER BY + /// clause (Oracle, PostgreSQL, Trino). Not set by SQL Server, which + /// requires one. + SQL_LIMIT_OFFSET_FETCH_WITHOUT_ORDER_BY = 5, }; /// Syntax accepted for explicit null ordering in ORDER BY. @@ -942,20 +963,26 @@ struct ARROW_FLIGHT_SQL_EXPORT SqlInfoOptions { SQL_NULLS_ORDERING_FIRST_LAST = 0, }; - /// Accepted literal syntax for boolean values. - enum SqlBooleanLiteralSyntax { - /// TRUE / FALSE keywords. - SQL_BOOLEAN_LITERAL_TRUE_FALSE = 0, - /// Integer 1 / 0. - SQL_BOOLEAN_LITERAL_INT_ONE_ZERO = 1, + /// Ways of escaping the wildcard characters '%' and '_' in a LIKE pattern. + enum SqlLikeEscapeSyntax { + /// col LIKE 'a!%b' ESCAPE '!', with an escape character of the client's + /// choice (ANSI, PostgreSQL, MySQL, SQL Server, Oracle, Trino) + SQL_LIKE_ESCAPE_CLAUSE = 0, + /// col LIKE 'a\\%b': a backslash escapes with no ESCAPE clause + /// (PostgreSQL, MySQL, ClickHouse, DataFusion) + SQL_LIKE_ESCAPE_IMPLICIT_BACKSLASH = 1, }; - /// Accepted literal syntax for date, time, and timestamp values. - enum SqlDatetimeLiteralSyntax { - /// DATE '2026-01-01', TIME '12:00:00', TIMESTAMP '2026-01-01 12:00:00'. - SQL_DATETIME_LITERAL_ANSI_KEYWORD = 0, - /// Bare quoted string, e.g. '2026-01-01' or '2026-01-01 12:00:00'. - SQL_DATETIME_LITERAL_BARE_STRING = 1, + /// Spellings of a parameter marker in a prepared statement. + enum SqlParameterMarkerSyntax { + /// col = ? (MySQL, SQLite, DuckDB, Trino, ...) + SQL_PARAMETER_MARKER_QUESTION_MARK = 0, + /// col = $1 (PostgreSQL, SQLite, DuckDB, DataFusion) + SQL_PARAMETER_MARKER_DOLLAR_NUMBERED = 1, + /// col = :1 (Oracle, SQLite, DataFusion) + SQL_PARAMETER_MARKER_COLON_NUMBERED = 2, + /// col = @p1 (SQL Server) + SQL_PARAMETER_MARKER_AT_P_NUMBERED = 3, }; }; diff --git a/format/FlightSql.proto b/format/FlightSql.proto index 7288d2a119e5..a6de55283506 100644 --- a/format/FlightSql.proto +++ b/format/FlightSql.proto @@ -835,22 +835,29 @@ enum SqlInfo { SQL_STORED_FUNCTIONS_USING_CALL_SYNTAX_SUPPORTED = 576; /* - * Retrieves the supported row-limit and offset grammars. Variants differ - * in their offset behavior: SQL_LIMIT_OFFSET_LIMIT accepts an optional - * OFFSET, SQL_LIMIT_OFFSET_FETCH requires a preceding OFFSET clause, and - * SQL_LIMIT_OFFSET_TOP is limit-only and does not compose with offset. + * Retrieves the supported row-limit and offset grammars. Limiting and + * offsetting are reported separately because servers often accept a grammar + * for limiting that they do not accept together with an offset: + * SQL_LIMIT_OFFSET_LIMIT and SQL_LIMIT_OFFSET_FETCH_FIRST only limit, + * SQL_LIMIT_OFFSET_LIMIT_OFFSET and SQL_LIMIT_OFFSET_OFFSET_FETCH limit and + * offset, and SQL_LIMIT_OFFSET_TOP only limits and does not compose with an + * offset. + * + * SQL_LIMIT_OFFSET_FETCH_WITHOUT_ORDER_BY qualifies the two FETCH grammars: + * unless it is set, they are only accepted in a query that has an ORDER BY + * clause. * * Returns an int32 bitmask value representing the supported grammars. * The returned bitmask should be parsed in order to retrieve the supported * grammars. * * For instance: - * - return 0 (\b0) => [] (no row-limit grammar is supported); - * - return 1 (\b1) => [SQL_LIMIT_OFFSET_LIMIT]; - * - return 2 (\b10) => [SQL_LIMIT_OFFSET_FETCH]; - * - return 3 (\b11) => [SQL_LIMIT_OFFSET_LIMIT, SQL_LIMIT_OFFSET_FETCH]; - * - return 4 (\b100) => [SQL_LIMIT_OFFSET_TOP]; - * - return 6 (\b110) => [SQL_LIMIT_OFFSET_FETCH, SQL_LIMIT_OFFSET_TOP]. + * - return 0 (\b0) => [] (no row-limit grammar is supported); + * - return 1 (\b1) => [SQL_LIMIT_OFFSET_LIMIT]; + * - return 3 (\b11) => [SQL_LIMIT_OFFSET_LIMIT, SQL_LIMIT_OFFSET_LIMIT_OFFSET]; + * - return 24 (\b11000) => [SQL_LIMIT_OFFSET_OFFSET_FETCH, SQL_LIMIT_OFFSET_TOP]; + * - return 44 (\b101100) => [SQL_LIMIT_OFFSET_FETCH_FIRST, SQL_LIMIT_OFFSET_OFFSET_FETCH, + * SQL_LIMIT_OFFSET_FETCH_WITHOUT_ORDER_BY]. * Valid grammars are described under `arrow.flight.protocol.sql.SqlLimitOffsetSyntax`. */ SQL_SUPPORTED_LIMIT_OFFSET = 577; @@ -872,37 +879,59 @@ enum SqlInfo { SQL_SUPPORTED_NULLS_ORDERING = 578; /* - * Retrieves the supported literal syntaxes for boolean values. + * Retrieves the supported ways of escaping the wildcard characters '%' and + * '_' in a LIKE pattern. Supersedes SQL_SUPPORTS_LIKE_ESCAPE_CLAUSE (523), + * which cannot describe a server that escapes without an ESCAPE clause. * * Returns an int32 bitmask value representing the supported syntaxes. * The returned bitmask should be parsed in order to retrieve the supported * syntaxes. * * For instance: - * - return 0 (\b0) => [] (no boolean literal syntax is supported); - * - return 1 (\b1) => [SQL_BOOLEAN_LITERAL_TRUE_FALSE]; - * - return 2 (\b10) => [SQL_BOOLEAN_LITERAL_INT_ONE_ZERO]; - * - return 3 (\b11) => [SQL_BOOLEAN_LITERAL_TRUE_FALSE, SQL_BOOLEAN_LITERAL_INT_ONE_ZERO]. - * Valid syntaxes are described under `arrow.flight.protocol.sql.SqlBooleanLiteralSyntax`. + * - return 0 (\b0) => [] (a literal wildcard cannot be matched); + * - return 1 (\b1) => [SQL_LIKE_ESCAPE_CLAUSE]; + * - return 2 (\b10) => [SQL_LIKE_ESCAPE_IMPLICIT_BACKSLASH]; + * - return 3 (\b11) => [SQL_LIKE_ESCAPE_CLAUSE, SQL_LIKE_ESCAPE_IMPLICIT_BACKSLASH]. + * Valid syntaxes are described under `arrow.flight.protocol.sql.SqlLikeEscapeSyntax`. */ - SQL_SUPPORTED_BOOLEAN_LITERAL = 579; + SQL_SUPPORTED_LIKE_ESCAPE = 579; /* - * Retrieves the supported literal syntaxes for date, time, and timestamp - * values. + * Retrieves the supported spellings of a parameter marker in a prepared + * statement. + * + * Clients that generate SQL are encouraged to send values as bound + * parameters instead of writing them as literals. How a value is spelled as + * a literal differs between servers for nearly every type (booleans, dates + * and timestamps, strings containing a backslash or characters outside + * ASCII, binary values, floating point values), while a bound value is + * transferred as Arrow data and needs no spelling. The spelling of the + * marker itself is then the one thing a client has to know. + * + * A syntax must only be reported if a statement using it can be prepared + * and executed with parameters bound as described for + * CommandPreparedStatementQuery, and if a marker is accepted wherever a + * value is compared with a column, including each element of an IN list. + * + * Parameters are bound by position. For the numbered syntaxes a client + * should number the markers from 1 in the order they appear and use each + * number once: servers differ in whether a numbered marker takes the + * parameter with that number or the one at its position in the statement, + * and the two only coincide for a statement written that way. * * Returns an int32 bitmask value representing the supported syntaxes. * The returned bitmask should be parsed in order to retrieve the supported * syntaxes. * * For instance: - * - return 0 (\b0) => [] (no datetime literal syntax is supported); - * - return 1 (\b1) => [SQL_DATETIME_LITERAL_ANSI_KEYWORD]; - * - return 2 (\b10) => [SQL_DATETIME_LITERAL_BARE_STRING]; - * - return 3 (\b11) => [SQL_DATETIME_LITERAL_ANSI_KEYWORD, SQL_DATETIME_LITERAL_BARE_STRING]. - * Valid syntaxes are described under `arrow.flight.protocol.sql.SqlDatetimeLiteralSyntax`. - */ - SQL_SUPPORTED_DATETIME_LITERAL = 580; + * - return 0 (\b0) => [] (no marker listed here is supported); + * - return 1 (\b1) => [SQL_PARAMETER_MARKER_QUESTION_MARK]; + * - return 2 (\b10) => [SQL_PARAMETER_MARKER_DOLLAR_NUMBERED]; + * - return 3 (\b11) => [SQL_PARAMETER_MARKER_QUESTION_MARK, SQL_PARAMETER_MARKER_DOLLAR_NUMBERED]; + * - return 8 (\b1000) => [SQL_PARAMETER_MARKER_AT_P_NUMBERED]. + * Valid syntaxes are described under `arrow.flight.protocol.sql.SqlParameterMarkerSyntax`. + */ + SQL_SUPPORTED_PARAMETER_MARKER = 580; } // The level of support for Flight SQL transaction RPCs. @@ -1028,13 +1057,21 @@ enum SqlSupportsConvert { } enum SqlLimitOffsetSyntax { - // LIMIT n [OFFSET m] (PostgreSQL, MySQL, SQLite, DuckDB, Snowflake, ...) + // LIMIT n (PostgreSQL, MySQL, SQLite, DuckDB, Trino, ...) SQL_LIMIT_OFFSET_LIMIT = 0; - // OFFSET m ROWS FETCH NEXT n ROWS ONLY (SQL Server, Oracle, ANSI) - SQL_LIMIT_OFFSET_FETCH = 1; + // LIMIT n OFFSET m (PostgreSQL, MySQL, SQLite, DuckDB, ...). Not implied by + // SQL_LIMIT_OFFSET_LIMIT: Trino and Presto accept LIMIT n but not this. + SQL_LIMIT_OFFSET_LIMIT_OFFSET = 1; + // FETCH FIRST n ROWS ONLY, with no OFFSET clause (ANSI, Oracle, PostgreSQL, Trino) + SQL_LIMIT_OFFSET_FETCH_FIRST = 2; + // OFFSET m ROWS FETCH NEXT n ROWS ONLY (ANSI, SQL Server, Oracle, PostgreSQL) + SQL_LIMIT_OFFSET_OFFSET_FETCH = 3; // SELECT TOP n ... (SQL Server, Sybase, Snowflake). Limit-only; does not // compose with offset. - SQL_LIMIT_OFFSET_TOP = 2; + SQL_LIMIT_OFFSET_TOP = 4; + // The FETCH grammars above are accepted in a query with no ORDER BY clause + // (Oracle, PostgreSQL, Trino). Not set by SQL Server, which requires one. + SQL_LIMIT_OFFSET_FETCH_WITHOUT_ORDER_BY = 5; } enum SqlNullsOrderingSyntax { @@ -1042,18 +1079,24 @@ enum SqlNullsOrderingSyntax { SQL_NULLS_ORDERING_FIRST_LAST = 0; } -enum SqlBooleanLiteralSyntax { - // TRUE / FALSE keywords - SQL_BOOLEAN_LITERAL_TRUE_FALSE = 0; - // Integer 1 / 0 - SQL_BOOLEAN_LITERAL_INT_ONE_ZERO = 1; +enum SqlLikeEscapeSyntax { + // col LIKE 'a!%b' ESCAPE '!', with an escape character of the client's choice + // (ANSI, PostgreSQL, MySQL, SQL Server, Oracle, Trino) + SQL_LIKE_ESCAPE_CLAUSE = 0; + // col LIKE 'a\%b': a backslash escapes with no ESCAPE clause + // (PostgreSQL, MySQL, ClickHouse, DataFusion) + SQL_LIKE_ESCAPE_IMPLICIT_BACKSLASH = 1; } -enum SqlDatetimeLiteralSyntax { - // DATE '2026-01-01', TIME '12:00:00', TIMESTAMP '2026-01-01 12:00:00' - SQL_DATETIME_LITERAL_ANSI_KEYWORD = 0; - // Bare quoted string, e.g. '2026-01-01' or '2026-01-01 12:00:00' - SQL_DATETIME_LITERAL_BARE_STRING = 1; +enum SqlParameterMarkerSyntax { + // col = ? (MySQL, SQLite, DuckDB, Trino, ...) + SQL_PARAMETER_MARKER_QUESTION_MARK = 0; + // col = $1 (PostgreSQL, SQLite, DuckDB, DataFusion) + SQL_PARAMETER_MARKER_DOLLAR_NUMBERED = 1; + // col = :1 (Oracle, SQLite, DataFusion) + SQL_PARAMETER_MARKER_COLON_NUMBERED = 2; + // col = @p1 (SQL Server) + SQL_PARAMETER_MARKER_AT_P_NUMBERED = 3; } /**