diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8353583ce3..ab8b4b29b8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -43,12 +43,12 @@ repos: - id: cmake-format args: [--in-place] - repo: https://github.com/cpplint/cpplint - rev: 1.6.0 + rev: 1.6.1 hooks: - id: cpplint args: # From Arrow's config - - "--filter=-whitespace/comments,-readability/casting,-readability/todo,-readability/alt_tokens,-build/header_guard,-build/c++11,-build/include_order,-build/include_subdir" + - "--filter=-whitespace/comments,-whitespace/indent,-readability/braces,-readability/casting,-readability/todo,-readability/alt_tokens,-build/header_guard,-build/c++11,-build/include_order,-build/include_subdir" - "--linelength=90" - "--verbose=2" - repo: https://github.com/golangci/golangci-lint diff --git a/adbc.h b/adbc.h index 154e881255..756288dae8 100644 --- a/adbc.h +++ b/adbc.h @@ -279,6 +279,14 @@ struct ADBC_EXPORT AdbcError { /// point to an AdbcDriver. #define ADBC_VERSION_1_0_0 1000000 +/// \brief ADBC revision 1.1.0. +/// +/// When passed to an AdbcDriverInitFunc(), the driver parameter must +/// point to an AdbcDriver. +/// +/// \addtogroup adbc-1.1.0 +#define ADBC_VERSION_1_1_0 1001000 + /// \brief Canonical option value for enabling an option. /// /// For use as the value in SetOption calls. @@ -288,6 +296,37 @@ struct ADBC_EXPORT AdbcError { /// For use as the value in SetOption calls. #define ADBC_OPTION_VALUE_DISABLED "false" +/// \brief Canonical option name for URIs. +/// +/// Should be used as the expected option name to specify a URI for +/// any ADBC driver. +/// +/// The type is char*. +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +#define ADBC_OPTION_URI "uri" +/// \brief Canonical option name for usernames. +/// +/// Should be used as the expected option name to specify a username +/// to a driver for authentication. +/// +/// The type is char*. +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +#define ADBC_OPTION_USERNAME "username" +/// \brief Canonical option name for passwords. +/// +/// Should be used as the expected option name to specify a password +/// for authentication to a driver. +/// +/// The type is char*. +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +#define ADBC_OPTION_PASSWORD "password" + /// \brief The database vendor/product name (e.g. the server name). /// (type: utf8). /// @@ -315,6 +354,16 @@ struct ADBC_EXPORT AdbcError { /// /// \see AdbcConnectionGetInfo #define ADBC_INFO_DRIVER_ARROW_VERSION 102 +/// \brief The driver ADBC API version (type: int64). +/// +/// The value should be one of the ADBC_VERSION constants. +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +/// \see AdbcConnectionGetInfo +/// \see ADBC_VERSION_1_0_0 +/// \see ADBC_VERSION_1_1_0 +#define ADBC_INFO_DRIVER_ADBC_VERSION 103 /// \brief Return metadata on catalogs, schemas, tables, and columns. /// @@ -340,15 +389,68 @@ struct ADBC_EXPORT AdbcError { /// \brief The name of the canonical option for whether autocommit is /// enabled. /// +/// The type is char*. +/// /// \see AdbcConnectionSetOption #define ADBC_CONNECTION_OPTION_AUTOCOMMIT "adbc.connection.autocommit" /// \brief The name of the canonical option for whether the current /// connection should be restricted to being read-only. /// +/// The type is char*. +/// /// \see AdbcConnectionSetOption #define ADBC_CONNECTION_OPTION_READ_ONLY "adbc.connection.readonly" +/// \brief The name of the canonical option for the current catalog. +/// +/// The type is char*. +/// +/// \see AdbcConnectionGetOption +/// \see AdbcConnectionSetOption +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +#define ADBC_CONNECTION_OPTION_CURRENT_CATALOG "adbc.connection.catalog" + +/// \brief The name of the canonical option for the current schema. +/// +/// The type is char*. +/// +/// \see AdbcConnectionGetOption +/// \see AdbcConnectionSetOption +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +#define ADBC_CONNECTION_OPTION_CURRENT_DB_SCHEMA "adbc.connection.db_schema" + +/// \brief The name of the canonical option for making query execution +/// nonblocking. +/// +/// When enabled, AdbcStatementExecutePartitions will return +/// partitions as soon as they are available, instead of returning +/// them all at the end. When there are no more to return, it will +/// return an empty set of partitions. AdbcStatementExecuteQuery and +/// AdbcStatementExecuteSchema are not affected. +/// +/// The default is ADBC_OPTION_VALUE_DISABLED. +/// +/// The type is char*. +/// +/// \see AdbcStatementSetOption +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +#define ADBC_STATEMENT_OPTION_INCREMENTAL "adbc.statement.exec.incremental" + +/// \brief The name of the option for getting the progress of a query. +/// +/// Progress is a value in [0.0, 1.0]. +/// +/// The type is double. +/// +/// \see AdbcStatementGetOptionDouble +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +#define ADBC_STATEMENT_OPTION_PROGRESS "adbc.statement.exec.progress" + /// \brief The name of the canonical option for setting the isolation /// level of a transaction. /// @@ -357,6 +459,8 @@ struct ADBC_EXPORT AdbcError { /// isolation level is not supported by a driver, it should return an /// appropriate error. /// +/// The type is char*. +/// /// \see AdbcConnectionSetOption #define ADBC_CONNECTION_OPTION_ISOLATION_LEVEL \ "adbc.connection.transaction.isolation_level" @@ -449,8 +553,12 @@ struct ADBC_EXPORT AdbcError { /// exist. If the table exists but has a different schema, /// ADBC_STATUS_ALREADY_EXISTS should be raised. Else, data should be /// appended to the target table. +/// +/// The type is char*. #define ADBC_INGEST_OPTION_TARGET_TABLE "adbc.ingest.target_table" /// \brief Whether to create (the default) or append. +/// +/// The type is char*. #define ADBC_INGEST_OPTION_MODE "adbc.ingest.mode" /// \brief Create the table and insert data; error if the table exists. #define ADBC_INGEST_OPTION_MODE_CREATE "adbc.ingest.mode.create" @@ -458,6 +566,17 @@ struct ADBC_EXPORT AdbcError { /// table does not exist (ADBC_STATUS_NOT_FOUND) or does not match /// the schema of the data to append (ADBC_STATUS_ALREADY_EXISTS). #define ADBC_INGEST_OPTION_MODE_APPEND "adbc.ingest.mode.append" +/// \brief Create the table and insert data; drop the original table +/// if it already exists. +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +#define ADBC_INGEST_OPTION_MODE_REPLACE "adbc.ingest.mode.replace" +/// \brief Insert data; create the table if it does not exist, or +/// error if the table exists, but the schema does not match the +/// schema of the data to append (ADBC_STATUS_ALREADY_EXISTS). +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +#define ADBC_INGEST_OPTION_MODE_CREATE_APPEND "adbc.ingest.mode.create_append" /// @} @@ -667,8 +786,89 @@ struct ADBC_EXPORT AdbcDriver { struct AdbcError*); AdbcStatusCode (*StatementSetSubstraitPlan)(struct AdbcStatement*, const uint8_t*, size_t, struct AdbcError*); + + /// \defgroup adbc-1.1.0 ADBC API Revision 1.1.0 + /// + /// Functions added in ADBC 1.1.0. For backwards compatibility, + /// these members must not be accessed unless the version passed to + /// the AdbcDriverInitFunc is greater than or equal to + /// ADBC_VERSION_1_1_0. + /// + /// For a 1.0.0 driver being loaded by a 1.1.0 driver manager: the + /// 1.1.0 manager will allocate the new, expanded AdbcDriver struct + /// and attempt to have the driver initialize it with + /// ADBC_VERSION_1_1_0. This must return an error, after which the + /// driver will try again with ADBC_VERSION_1_0_0. The driver must + /// not access the new fields. + /// + /// For a 1.1.0 driver being loaded by a 1.0.0 driver manager: the + /// 1.0.0 manager will allocate the old AdbcDriver struct and + /// attempt to have the driver initialize it with + /// ADBC_VERSION_1_0_0. The driver must not access the new fields, + /// and should initialize the old fields. + /// + /// @{ + + AdbcStatusCode (*DatabaseGetOption)(struct AdbcDatabase*, const char*, const char**, + struct AdbcError*); + AdbcStatusCode (*DatabaseGetOptionInt)(struct AdbcDatabase*, const char*, int64_t*, + struct AdbcError*); + AdbcStatusCode (*DatabaseGetOptionDouble)(struct AdbcDatabase*, const char*, double*, + struct AdbcError*); + AdbcStatusCode (*DatabaseSetOptionInt)(struct AdbcDatabase*, const char*, int64_t, + struct AdbcError*); + AdbcStatusCode (*DatabaseSetOptionDouble)(struct AdbcDatabase*, const char*, double, + struct AdbcError*); + + AdbcStatusCode (*ConnectionGetOption)(struct AdbcConnection*, const char*, const char**, + struct AdbcError*); + AdbcStatusCode (*ConnectionGetOptionInt)(struct AdbcConnection*, const char*, int64_t*, + struct AdbcError*); + AdbcStatusCode (*ConnectionGetOptionDouble)(struct AdbcConnection*, const char*, + double*, struct AdbcError*); + AdbcStatusCode (*ConnectionSetOptionInt)(struct AdbcConnection*, const char*, int64_t, + struct AdbcError*); + AdbcStatusCode (*ConnectionSetOptionDouble)(struct AdbcConnection*, const char*, double, + struct AdbcError*); + + AdbcStatusCode (*StatementCancel)(struct AdbcStatement*, struct AdbcError*); + AdbcStatusCode (*StatementExecuteSchema)(struct AdbcStatement*, struct ArrowSchema*, + struct AdbcError*); + AdbcStatusCode (*StatementGetOption)(struct AdbcStatement*, const char*, const char**, + struct AdbcError*); + AdbcStatusCode (*StatementGetOptionInt)(struct AdbcStatement*, const char*, int64_t*, + struct AdbcError*); + AdbcStatusCode (*StatementGetOptionDouble)(struct AdbcStatement*, const char*, double*, + struct AdbcError*); + AdbcStatusCode (*StatementSetOptionInt)(struct AdbcStatement*, const char*, int64_t, + struct AdbcError*); + AdbcStatusCode (*StatementSetOptionDouble)(struct AdbcStatement*, const char*, double, + struct AdbcError*); + + /// Pad the struct to have 96 pointers. Space reserved for future growth. + void* reserved[50]; + + /// @} }; +/// \brief The size of the AdbcDriver structure in ADBC 1.0.0. +/// Drivers written for ADBC 1.1.0 and later should never touch more +/// than this portion of an AdbcDriver struct when given +/// ADBC_VERSION_1_0_0. +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +#define ADBC_DRIVER_1_0_0_SIZE (offsetof(struct AdbcDriver, DatabaseGetOption)) + +/// \brief The size of the AdbcDriver structure in ADBC 1.1.0. +/// Drivers written for ADBC 1.1.0 and later should never touch more +/// than this portion of an AdbcDriver struct when given +/// ADBC_VERSION_1_1_0. +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +#define ADBC_DRIVER_1_1_0_SIZE (sizeof(struct AdbcDriver)) + /// @} /// \addtogroup adbc-database @@ -684,16 +884,121 @@ struct ADBC_EXPORT AdbcDriver { ADBC_EXPORT AdbcStatusCode AdbcDatabaseNew(struct AdbcDatabase* database, struct AdbcError* error); +/// \brief Get a string option of the database. +/// +/// This must always be thread-safe (other operations are not). +/// +/// The returned option value is only valid until the next call to +/// GetOption or Release. +/// +/// For standard options, drivers must always support getting the +/// option value (if they support getting option values at all) via +/// the type specified in the option. (For example, an option set via +/// SetOptionDouble must be retrievable via GetOptionDouble.) Drivers +/// may also support getting a converted option value via other +/// getters if needed. (For example, getting the string +/// representation of a double option.) +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +/// \param[in] database The database. +/// \param[in] key The option to get. +/// \param[out] value The option value. +/// \param[out] error An optional location to return an error +/// message if necessary. +/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized. +AdbcStatusCode AdbcDatabaseGetOption(struct AdbcDatabase* database, const char* key, + const char** value, struct AdbcError* error); + +/// \brief Get an integer option of the database. +/// +/// This must always be thread-safe (other operations are not). +/// +/// For standard options, drivers must always support getting the +/// option value (if they support getting option values at all) via +/// the type specified in the option. (For example, an option set via +/// SetOptionDouble must be retrievable via GetOptionDouble.) Drivers +/// may also support getting a converted option value via other +/// getters if needed. (For example, getting the integer +/// representation of a double option.) +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +/// \param[in] database The database. +/// \param[in] key The option to get. +/// \param[out] value The option value. +/// \param[out] error An optional location to return an error +/// message if necessary. +/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized. +AdbcStatusCode AdbcDatabaseGetOptionInt(struct AdbcDatabase* database, const char* key, + int64_t* value, struct AdbcError* error); + +/// \brief Get a double option of the database. +/// +/// This must always be thread-safe (other operations are not). +/// +/// For standard options, drivers must always support getting the +/// option value (if they support getting option values at all) via +/// the type specified in the option. (For example, an option set via +/// SetOptionDouble must be retrievable via GetOptionDouble.) Drivers +/// may also support getting a converted option value via other +/// getters if needed. (For example, getting the double +/// representation of an integer option.) +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +/// \param[in] database The database. +/// \param[in] key The option to get. +/// \param[out] value The option value. +/// \param[out] error An optional location to return an error +/// message if necessary. +/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized. +AdbcStatusCode AdbcDatabaseGetOptionDouble(struct AdbcDatabase* database, const char* key, + double* value, struct AdbcError* error); + /// \brief Set a char* option. /// /// Options may be set before AdbcDatabaseInit. Some drivers may /// support setting options after initialization as well. /// +/// \param[in] database The database. +/// \param[in] key The option to set. +/// \param[in] value The option value. +/// \param[out] error An optional location to return an error +/// message if necessary. /// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized ADBC_EXPORT AdbcStatusCode AdbcDatabaseSetOption(struct AdbcDatabase* database, const char* key, const char* value, struct AdbcError* error); +/// \brief Set an integer option on a database. +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +/// \param[in] database The database. +/// \param[in] key The option to set. +/// \param[in] value The option value. +/// \param[out] error An optional location to return an error +/// message if necessary. +/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized +ADBC_EXPORT +AdbcStatusCode AdbcDatabaseSetOptionInt(struct AdbcDatabase* database, const char* key, + int64_t value, struct AdbcError* error); + +/// \brief Set a double option on a database. +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +/// \param[in] database The database. +/// \param[in] key The option to set. +/// \param[in] value The option value. +/// \param[out] error An optional location to return an error +/// message if necessary. +/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized +ADBC_EXPORT +AdbcStatusCode AdbcDatabaseSetOptionDouble(struct AdbcDatabase* database, const char* key, + double value, struct AdbcError* error); + /// \brief Finish setting options and initialize the database. /// /// Some drivers may support setting options after initialization @@ -730,11 +1035,52 @@ AdbcStatusCode AdbcConnectionNew(struct AdbcConnection* connection, /// Options may be set before AdbcConnectionInit. Some drivers may /// support setting options after initialization as well. /// +/// \param[in] connection The database connection. +/// \param[in] key The option to set. +/// \param[in] value The option value. +/// \param[out] error An optional location to return an error +/// message if necessary. /// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized ADBC_EXPORT AdbcStatusCode AdbcConnectionSetOption(struct AdbcConnection* connection, const char* key, const char* value, struct AdbcError* error); +/// \brief Set an integer option. +/// +/// Options may be set before AdbcConnectionInit. Some drivers may +/// support setting options after initialization as well. +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +/// \param[in] connection The database connection. +/// \param[in] key The option to set. +/// \param[in] value The option value. +/// \param[out] error An optional location to return an error +/// message if necessary. +/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized +ADBC_EXPORT +AdbcStatusCode AdbcConnectionSetOptionInt(struct AdbcConnection* connection, + const char* key, int64_t value, + struct AdbcError* error); + +/// \brief Set a double option. +/// +/// Options may be set before AdbcConnectionInit. Some drivers may +/// support setting options after initialization as well. +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +/// \param[in] connection The database connection. +/// \param[in] key The option to set. +/// \param[in] value The option value. +/// \param[out] error An optional location to return an error +/// message if necessary. +/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized +ADBC_EXPORT +AdbcStatusCode AdbcConnectionSetOptionDouble(struct AdbcConnection* connection, + const char* key, double value, + struct AdbcError* error); + /// \brief Finish setting options and initialize the connection. /// /// Some drivers may support setting options after initialization @@ -765,6 +1111,8 @@ AdbcStatusCode AdbcConnectionRelease(struct AdbcConnection* connection, /// concurrent active statements and it must execute a SQL query /// internally in order to implement the metadata function). /// +/// This AdbcConnection must outlive the returned ArrowArrayStream. +/// /// Some functions accept "search pattern" arguments, which are /// strings that can contain the special character "%" to match zero /// or more characters, or "_" to match exactly one character. (See @@ -799,6 +1147,10 @@ AdbcStatusCode AdbcConnectionRelease(struct AdbcConnection* connection, /// for ADBC usage. Drivers/vendors will ignore requests for /// unrecognized codes (the row will be omitted from the result). /// +/// Since ADBC 1.1.0: the range [500, 1_000) is reserved for "XDBC" +/// information, which is the same metadata provided by the same info +/// code range in the Arrow Flight SQL GetSqlInfo RPC. +/// /// \param[in] connection The connection to query. /// \param[in] info_codes A list of metadata codes to fetch, or NULL /// to fetch all. @@ -891,6 +1243,8 @@ AdbcStatusCode AdbcConnectionGetInfo(struct AdbcConnection* connection, /// | fk_table | utf8 not null | /// | fk_column_name | utf8 not null | /// +/// This AdbcConnection must outlive the returned ArrowArrayStream. +/// /// \param[in] connection The database connection. /// \param[in] depth The level of nesting to display. If 0, display /// all levels. If 1, display only catalogs (i.e. catalog_schemas @@ -922,6 +1276,80 @@ AdbcStatusCode AdbcConnectionGetObjects(struct AdbcConnection* connection, int d struct ArrowArrayStream* out, struct AdbcError* error); +/// \brief Get a string option of the connection. +/// +/// This must always be thread-safe (other operations are not). +/// +/// The returned option value is only valid until the next call to +/// GetOption or Release. +/// +/// For standard options, drivers must always support getting the +/// option value (if they support getting option values at all) via +/// the type specified in the option. (For example, an option set via +/// SetOptionDouble must be retrievable via GetOptionDouble.) Drivers +/// may also support getting a converted option value via other +/// getters if needed. (For example, getting the string +/// representation of a double option.) +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +/// \param[in] connection The database connection. +/// \param[in] key The option to get. +/// \param[out] value The option value. +/// \param[out] error An optional location to return an error +/// message if necessary. +/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized. +AdbcStatusCode AdbcConnectionGetOption(struct AdbcConnection* connection, const char* key, + const char** value, struct AdbcError* error); + +/// \brief Get an integer option of the connection. +/// +/// This must always be thread-safe (other operations are not). +/// +/// For standard options, drivers must always support getting the +/// option value (if they support getting option values at all) via +/// the type specified in the option. (For example, an option set via +/// SetOptionDouble must be retrievable via GetOptionDouble.) Drivers +/// may also support getting a converted option value via other +/// getters if needed. (For example, getting the string +/// representation of a double option.) +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +/// \param[in] connection The database connection. +/// \param[in] key The option to get. +/// \param[out] value The option value. +/// \param[out] error An optional location to return an error +/// message if necessary. +/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized. +AdbcStatusCode AdbcConnectionGetOptionInt(struct AdbcConnection* connection, + const char* key, int64_t* value, + struct AdbcError* error); + +/// \brief Get a double option of the connection. +/// +/// This must always be thread-safe (other operations are not). +/// +/// For standard options, drivers must always support getting the +/// option value (if they support getting option values at all) via +/// the type specified in the option. (For example, an option set via +/// SetOptionDouble must be retrievable via GetOptionDouble.) Drivers +/// may also support getting a converted option value via other +/// getters if needed. (For example, getting the string +/// representation of a double option.) +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +/// \param[in] connection The database connection. +/// \param[in] key The option to get. +/// \param[out] value The option value. +/// \param[out] error An optional location to return an error +/// message if necessary. +/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized. +AdbcStatusCode AdbcConnectionGetOptionDouble(struct AdbcConnection* connection, + const char* key, double* value, + struct AdbcError* error); + /// \brief Get the Arrow schema of a table. /// /// \param[in] connection The database connection. @@ -945,6 +1373,8 @@ AdbcStatusCode AdbcConnectionGetTableSchema(struct AdbcConnection* connection, /// ---------------|-------------- /// table_type | utf8 not null /// +/// This AdbcConnection must outlive the returned ArrowArrayStream. +/// /// \param[in] connection The database connection. /// \param[out] out The result set. /// \param[out] error Error details, if an error occurs. @@ -973,6 +1403,8 @@ AdbcStatusCode AdbcConnectionGetTableTypes(struct AdbcConnection* connection, /// /// A partition can be retrieved from AdbcPartitions. /// +/// This AdbcConnection must outlive the returned ArrowArrayStream. +/// /// \param[in] connection The connection to use. This does not have /// to be the same connection that the partition was created on. /// \param[in] serialized_partition The partition descriptor. @@ -1042,7 +1474,11 @@ AdbcStatusCode AdbcStatementRelease(struct AdbcStatement* statement, /// \brief Execute a statement and get the results. /// -/// This invalidates any prior result sets. +/// This invalidates any prior result sets. This AdbcStatement must +/// outlive the returned ArrowArrayStream. +/// +/// Since ADBC 1.1.0: releasing the returned ArrowArrayStream without +/// consuming it fully is equivalent to calling AdbcStatementCancel. /// /// \param[in] statement The statement to execute. /// \param[out] out The results. Pass NULL if the client does not @@ -1056,6 +1492,25 @@ AdbcStatusCode AdbcStatementExecuteQuery(struct AdbcStatement* statement, struct ArrowArrayStream* out, int64_t* rows_affected, struct AdbcError* error); +/// \brief Get the schema of the result set of a query without +/// executing it. +/// +/// This invalidates any prior result sets. +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +/// +/// \param[in] statement The statement to execute. +/// \param[out] out The result schema. +/// \param[out] error An optional location to return an error +/// message if necessary. +/// +/// \return ADBC_STATUS_NOT_IMPLEMENTED if the driver does not support this. +ADBC_EXPORT +AdbcStatusCode AdbcStatementExecuteSchema(struct AdbcStatement* statement, + struct ArrowSchema* schema, + struct AdbcError* error); + /// \brief Turn this statement into a prepared statement to be /// executed multiple times. /// @@ -1138,6 +1593,102 @@ AdbcStatusCode AdbcStatementBindStream(struct AdbcStatement* statement, struct ArrowArrayStream* stream, struct AdbcError* error); +/// \brief Cancel execution of an in-progress query. +/// +/// This can be called during AdbcStatementExecuteQuery (or similar), +/// or while consuming an ArrowArrayStream returned from such. +/// Calling this function should make the other functions return +/// ADBC_STATUS_CANCELLED (from ADBC functions) or ECANCELED (from +/// methods of ArrowArrayStream). +/// +/// This must always be thread-safe (other operations are not). +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +/// +/// \param[in] statement The statement to cancel. +/// \param[out] error An optional location to return an error +/// message if necessary. +/// +/// \return ADBC_STATUS_INVALID_STATE if there is no query to cancel. +/// \return ADBC_STATUS_UNKNOWN if the query could not be cancelled. +ADBC_EXPORT +AdbcStatusCode AdbcStatementCancel(struct AdbcStatement* statement, + struct AdbcError* error); + +/// \brief Get a string option of the statement. +/// +/// This must always be thread-safe (other operations are not). +/// +/// The returned option value is only valid until the next call to +/// GetOption or Release. +/// +/// For standard options, drivers must always support getting the +/// option value (if they support getting option values at all) via +/// the type specified in the option. (For example, an option set via +/// SetOptionDouble must be retrievable via GetOptionDouble.) Drivers +/// may also support getting a converted option value via other +/// getters if needed. (For example, getting the string +/// representation of a double option.) +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +/// \param[in] statement The statement. +/// \param[in] key The option to get. +/// \param[out] value The option value. +/// \param[out] error An optional location to return an error +/// message if necessary. +/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized. +AdbcStatusCode AdbcStatementGetOption(struct AdbcStatement* statement, const char* key, + const char** value, struct AdbcError* error); + +/// \brief Get an integer option of the statement. +/// +/// This must always be thread-safe (other operations are not). +/// +/// For standard options, drivers must always support getting the +/// option value (if they support getting option values at all) via +/// the type specified in the option. (For example, an option set via +/// SetOptionDouble must be retrievable via GetOptionDouble.) Drivers +/// may also support getting a converted option value via other +/// getters if needed. (For example, getting the string +/// representation of a double option.) +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +/// \param[in] statement The statement. +/// \param[in] key The option to get. +/// \param[out] value The option value. +/// \param[out] error An optional location to return an error +/// message if necessary. +/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized. +AdbcStatusCode AdbcStatementGetOptionInt(struct AdbcStatement* statement, const char* key, + int64_t* value, struct AdbcError* error); + +/// \brief Get a double option of the statement. +/// +/// This must always be thread-safe (other operations are not). +/// +/// For standard options, drivers must always support getting the +/// option value (if they support getting option values at all) via +/// the type specified in the option. (For example, an option set via +/// SetOptionDouble must be retrievable via GetOptionDouble.) Drivers +/// may also support getting a converted option value via other +/// getters if needed. (For example, getting the string +/// representation of a double option.) +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +/// \param[in] statement The statement. +/// \param[in] key The option to get. +/// \param[out] value The option value. +/// \param[out] error An optional location to return an error +/// message if necessary. +/// \return ADBC_STATUS_NOT_FOUND if the option is not recognized. +AdbcStatusCode AdbcStatementGetOptionDouble(struct AdbcStatement* statement, + const char* key, double* value, + struct AdbcError* error); + /// \brief Get the schema for bound parameters. /// /// This retrieves an Arrow schema describing the number, names, and @@ -1159,10 +1710,45 @@ AdbcStatusCode AdbcStatementGetParameterSchema(struct AdbcStatement* statement, struct AdbcError* error); /// \brief Set a string option on a statement. +/// \param[in] statement The statement. +/// \param[in] key The option to set. +/// \param[in] value The option value. +/// \param[out] error An optional location to return an error +/// message if necessary. +/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized. ADBC_EXPORT AdbcStatusCode AdbcStatementSetOption(struct AdbcStatement* statement, const char* key, const char* value, struct AdbcError* error); +/// \brief Set an integer option on a statement. +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +/// \param[in] statement The statement. +/// \param[in] key The option to set. +/// \param[in] value The option value. +/// \param[out] error An optional location to return an error +/// message if necessary. +/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized +ADBC_EXPORT +AdbcStatusCode AdbcStatementSetOptionInt(struct AdbcStatement* statement, const char* key, + int64_t value, struct AdbcError* error); + +/// \brief Set a double option on a statement. +/// +/// \since ADBC API revision 1.1.0 +/// \addtogroup adbc-1.1.0 +/// \param[in] statement The statement. +/// \param[in] key The option to set. +/// \param[in] value The option value. +/// \param[out] error An optional location to return an error +/// message if necessary. +/// \return ADBC_STATUS_NOT_IMPLEMENTED if the option is not recognized +ADBC_EXPORT +AdbcStatusCode AdbcStatementSetOptionDouble(struct AdbcStatement* statement, + const char* key, double value, + struct AdbcError* error); + /// \addtogroup adbc-statement-partition /// @{ @@ -1198,7 +1784,15 @@ AdbcStatusCode AdbcStatementExecutePartitions(struct AdbcStatement* statement, /// driver. /// /// Although drivers may choose any name for this function, the -/// recommended name is "AdbcDriverInit". +/// recommended name is "AdbcDriverInit", or a name derived from the +/// name of the driver's shared library as follows: remove the 'lib' +/// prefix (on Unix systems) and all file extensions, then PascalCase +/// the driver name, append Init, and prepend Adbc (if not already +/// there). For example: +/// +/// - libadbc_driver_sqlite.so.2.0.0 -> AdbcDriverSqliteInit +/// - adbc_driver_sqlite.dll -> AdbcDriverSqliteInit +/// - proprietary_driver.dll -> AdbcProprietaryDriverInit /// /// \param[in] version The ADBC revision to attempt to initialize (see /// ADBC_VERSION_1_0_0). diff --git a/c/driver/postgresql/postgresql.cc b/c/driver/postgresql/postgresql.cc index 51f152acc3..e9a2338bfb 100644 --- a/c/driver/postgresql/postgresql.cc +++ b/c/driver/postgresql/postgresql.cc @@ -471,9 +471,10 @@ extern "C" { ADBC_EXPORT AdbcStatusCode AdbcDriverInit(int version, void* raw_driver, struct AdbcError* error) { if (version != ADBC_VERSION_1_0_0) return ADBC_STATUS_NOT_IMPLEMENTED; + if (!raw_driver) return ADBC_STATUS_INVALID_ARGUMENT; auto* driver = reinterpret_cast(raw_driver); - std::memset(driver, 0, sizeof(*driver)); + std::memset(driver, 0, ADBC_DRIVER_1_0_0_SIZE); driver->DatabaseInit = PostgresDatabaseInit; driver->DatabaseNew = PostgresDatabaseNew; driver->DatabaseRelease = PostgresDatabaseRelease; diff --git a/c/driver/sqlite/sqlite.c b/c/driver/sqlite/sqlite.c index d671bc75ee..9d78dfb169 100644 --- a/c/driver/sqlite/sqlite.c +++ b/c/driver/sqlite/sqlite.c @@ -1337,7 +1337,7 @@ AdbcStatusCode SqliteDriverInit(int version, void* raw_driver, struct AdbcError* } struct AdbcDriver* driver = (struct AdbcDriver*)raw_driver; - memset(driver, 0, sizeof(*driver)); + memset(driver, 0, ADBC_DRIVER_1_0_0_SIZE); driver->DatabaseInit = SqliteDatabaseInit; driver->DatabaseNew = SqliteDatabaseNew; driver->DatabaseRelease = SqliteDatabaseRelease; diff --git a/c/driver_manager/adbc_driver_manager.cc b/c/driver_manager/adbc_driver_manager.cc index c63560a40e..888c48a683 100644 --- a/c/driver_manager/adbc_driver_manager.cc +++ b/c/driver_manager/adbc_driver_manager.cc @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -191,6 +192,12 @@ AdbcStatusCode StatementExecutePartitions(struct AdbcStatement* statement, return ADBC_STATUS_NOT_IMPLEMENTED; } +AdbcStatusCode StatementExecuteSchema(struct AdbcStatement* statement, + struct ArrowSchema* schema, + struct AdbcError* error) { + return ADBC_STATUS_NOT_IMPLEMENTED; +} + AdbcStatusCode StatementGetParameterSchema(struct AdbcStatement* statement, struct ArrowSchema* schema, struct AdbcError* error) { @@ -540,6 +547,15 @@ AdbcStatusCode AdbcStatementExecuteQuery(struct AdbcStatement* statement, error); } +AdbcStatusCode AdbcStatementExecuteSchema(struct AdbcStatement* statement, + struct ArrowSchema* schema, + struct AdbcError* error) { + if (!statement->private_driver) { + return ADBC_STATUS_INVALID_STATE; + } + return statement->private_driver->StatementExecuteSchema(statement, schema, error); +} + AdbcStatusCode AdbcStatementGetParameterSchema(struct AdbcStatement* statement, struct ArrowSchema* schema, struct AdbcError* error) { @@ -640,11 +656,19 @@ AdbcStatusCode AdbcLoadDriver(const char* driver_name, const char* entrypoint, AdbcDriverInitFunc init_func; std::string error_message; - if (version != ADBC_VERSION_1_0_0) { - SetError(error, "Only ADBC 1.0.0 is supported"); - return ADBC_STATUS_NOT_IMPLEMENTED; + switch (version) { + case ADBC_VERSION_1_0_0: + case ADBC_VERSION_1_1_0: + break; + default: + SetError(error, "Only ADBC 1.0.0 and 1.1.0 are supported"); + return ADBC_STATUS_NOT_IMPLEMENTED; } + if (!raw_driver) { + SetError(error, "Must provide non-NULL raw_driver"); + return ADBC_STATUS_INVALID_ARGUMENT; + } auto* driver = reinterpret_cast(raw_driver); if (!entrypoint) { @@ -771,6 +795,25 @@ AdbcStatusCode AdbcLoadDriver(const char* driver_name, const char* entrypoint, AdbcStatusCode AdbcLoadDriverFromInitFunc(AdbcDriverInitFunc init_func, int version, void* raw_driver, struct AdbcError* error) { + constexpr std::array kSupportedVersions = { + ADBC_VERSION_1_1_0, + ADBC_VERSION_1_0_0, + }; + + if (!raw_driver) { + SetError(error, "Must provide non-NULL raw_driver"); + return ADBC_STATUS_INVALID_ARGUMENT; + } + + switch (version) { + case ADBC_VERSION_1_0_0: + case ADBC_VERSION_1_1_0: + break; + default: + SetError(error, "Only ADBC 1.0.0 and 1.1.0 are supported"); + return ADBC_STATUS_NOT_IMPLEMENTED; + } + #define FILL_DEFAULT(DRIVER, STUB) \ if (!DRIVER->STUB) { \ DRIVER->STUB = &STUB; \ @@ -781,12 +824,20 @@ AdbcStatusCode AdbcLoadDriverFromInitFunc(AdbcDriverInitFunc init_func, int vers return ADBC_STATUS_INTERNAL; \ } - auto result = init_func(version, raw_driver, error); + // Starting from the passed version, try each (older) version in + // succession with the underlying driver until we find one that's + // accepted. + AdbcStatusCode result = ADBC_STATUS_NOT_IMPLEMENTED; + for (const int try_version : kSupportedVersions) { + if (try_version > version) continue; + result = init_func(try_version, raw_driver, error); + if (result != ADBC_STATUS_NOT_IMPLEMENTED) break; + } if (result != ADBC_STATUS_OK) { return result; } - if (version == ADBC_VERSION_1_0_0) { + if (version >= ADBC_VERSION_1_0_0) { auto* driver = reinterpret_cast(raw_driver); CHECK_REQUIRED(driver, DatabaseNew); CHECK_REQUIRED(driver, DatabaseInit); @@ -816,6 +867,13 @@ AdbcStatusCode AdbcLoadDriverFromInitFunc(AdbcDriverInitFunc init_func, int vers FILL_DEFAULT(driver, StatementSetSqlQuery); FILL_DEFAULT(driver, StatementSetSubstraitPlan); } + if (version >= ADBC_VERSION_1_1_0) { + auto* driver = reinterpret_cast(raw_driver); + FILL_DEFAULT(driver, StatementExecuteSchema); + + // Zero out the padding + std::memset(driver->reserved, 0, sizeof(driver->reserved)); + } return ADBC_STATUS_OK; diff --git a/c/driver_manager/adbc_driver_manager_test.cc b/c/driver_manager/adbc_driver_manager_test.cc index 99fa477bfa..26c8dc6116 100644 --- a/c/driver_manager/adbc_driver_manager_test.cc +++ b/c/driver_manager/adbc_driver_manager_test.cc @@ -34,6 +34,8 @@ namespace adbc { using adbc_validation::IsOkStatus; using adbc_validation::IsStatus; +TEST(Adbc, AdbcDriverSize) { ASSERT_EQ(sizeof(AdbcDriver), 96 * sizeof(void*)); } + class DriverManager : public ::testing::Test { public: void SetUp() override { @@ -157,6 +159,38 @@ TEST_F(DriverManager, MultiDriverTest) { error->release(&error.value); } +class AdbcVersion : public ::testing::Test { + public: + void SetUp() override { + std::memset(&driver, 0, sizeof(driver)); + std::memset(&error, 0, sizeof(error)); + } + + void TearDown() override { + if (error.release) { + error.release(&error); + } + + if (driver.release) { + ASSERT_THAT(driver.release(&driver, &error), IsOkStatus(&error)); + ASSERT_EQ(driver.private_data, nullptr); + ASSERT_EQ(driver.private_manager, nullptr); + } + } + + protected: + struct AdbcDriver driver = {}; + struct AdbcError error = {}; +}; + +// TODO: set up a dummy driver to test behavior more deterministically + +TEST_F(AdbcVersion, ForwardsCompatible) { + ASSERT_THAT( + AdbcLoadDriver("adbc_driver_sqlite", nullptr, ADBC_VERSION_1_1_0, &driver, &error), + IsOkStatus(&error)); +} + class SqliteQuirks : public adbc_validation::DriverQuirks { public: AdbcStatusCode SetupDatabase(struct AdbcDatabase* database, diff --git a/go/adbc/adbc.go b/go/adbc/adbc.go index 2ecd415436..c71ce82a05 100644 --- a/go/adbc/adbc.go +++ b/go/adbc/adbc.go @@ -142,20 +142,35 @@ const ( StatusUnauthorized // Unauthorized ) +const ( + AdbcVersion1_0_0 int64 = 1_000_000 + AdbcVersion1_1_0 int64 = 1_001_000 +) + // Canonical option values const ( - OptionValueEnabled = "true" - OptionValueDisabled = "false" - OptionKeyAutoCommit = "adbc.connection.autocommit" - OptionKeyIngestTargetTable = "adbc.ingest.target_table" - OptionKeyIngestMode = "adbc.ingest.mode" - OptionKeyIsolationLevel = "adbc.connection.transaction.isolation_level" - OptionKeyReadOnly = "adbc.connection.readonly" - OptionValueIngestModeCreate = "adbc.ingest.mode.create" - OptionValueIngestModeAppend = "adbc.ingest.mode.append" - OptionKeyURI = "uri" - OptionKeyUsername = "username" - OptionKeyPassword = "password" + OptionValueEnabled = "true" + OptionValueDisabled = "false" + OptionKeyAutoCommit = "adbc.connection.autocommit" + // The current catalog. + OptionKeyCurrentCatalog = "adbc.connection.catalog" + // The current schema. + OptionKeyCurrentDbSchema = "adbc.connection.db_schema" + // Make ExecutePartitions nonblocking. + OptionKeyIncremental = "adbc.statement.exec.incremental" + // Get the progress + OptionKeyProgress = "adbc.statement.exec.progress" + OptionKeyIngestTargetTable = "adbc.ingest.target_table" + OptionKeyIngestMode = "adbc.ingest.mode" + OptionKeyIsolationLevel = "adbc.connection.transaction.isolation_level" + OptionKeyReadOnly = "adbc.connection.readonly" + OptionValueIngestModeCreate = "adbc.ingest.mode.create" + OptionValueIngestModeAppend = "adbc.ingest.mode.append" + OptionValueIngestModeReplace = "adbc.ingest.mode.replace" + OptionValueIngestModeCreateAppend = "adbc.ingest.mode.create_append" + OptionKeyURI = "uri" + OptionKeyUsername = "username" + OptionKeyPassword = "password" ) type OptionIsolationLevel string @@ -170,6 +185,11 @@ const ( LevelLinearizable OptionIsolationLevel = "adbc.connection.transaction.isolation.linearizable" ) +// Canonical property values +const ( + PropertyProgress = "adbc.statement.exec.progress" +) + // Driver is the entry point for the interface. It is similar to // database/sql.Driver taking a map of keys and values as options // to initialize a Connection to the database. Any common connection @@ -212,6 +232,8 @@ const ( InfoDriverVersion InfoCode = 101 // DriverVersion // The driver Arrow library version (type: utf8) InfoDriverArrowVersion InfoCode = 102 // DriverArrowVersion + // The driver ADBC API version (type: int64) + InfoDriverADBCVersion InfoCode = 103 // DriverADBCVersion ) type ObjectDepth int @@ -275,6 +297,10 @@ type Connection interface { // codes are defined as constants. Codes [0, 10_000) are reserved // for ADBC usage. Drivers/vendors will ignore requests for unrecognized // codes (the row will be omitted from the result). + // + // Since ADBC 1.1.0: the range [500, 1_000) is reserved for "XDBC" + // information, which is the same metadata provided by the same info + // code range in the Arrow Flight SQL GetSqlInfo RPC. GetInfo(ctx context.Context, infoCodes []InfoCode) (array.RecordReader, error) // GetObjects gets a hierarchical view of all catalogs, database schemas, @@ -470,6 +496,9 @@ type Statement interface { // of rows affected if known, otherwise it will be -1. // // This invalidates any prior result sets on this statement. + // + // Since ADBC 1.1.0: releasing the returned RecordReader without + // consuming it fully is equivalent to calling AdbcStatementCancel. ExecuteQuery(context.Context) (array.RecordReader, int64, error) // ExecuteUpdate executes a statement that does not generate a result @@ -534,5 +563,45 @@ type Statement interface { // // If the driver does not support partitioned results, this will return // an error with a StatusNotImplemented code. + // + // When OptionKeyIncremental is set, this should be called + // repeatedly until receiving an empty Partitions. ExecutePartitions(context.Context) (*arrow.Schema, Partitions, int64, error) } + +// StatementCancel is a Statement that also supports Cancel. +// +// Since ADBC API revision 1.1.0. +type StatementCancel interface { + // Cancel stops execution of an in-progress query. + // + // This can be called during ExecuteQuery (or similar), or while + // consuming a RecordReader returned from such. Calling this + // function should make the other functions return an error with a + // StatusCancelled code. + // + // This must always be thread-safe (other operations are not + // necessarily thread-safe). + Cancel() error +} + +// StatementExecuteSchema is a Statement that also supports ExecuteSchema. +// +// Since ADBC API revision 1.1.0. +type StatementExecuteSchema interface { + // ExecuteSchema gets the schema of the result set of a query without executing it. + ExecuteSchema(context.Context) (*arrow.Schema, error) +} + +// GetSetOptions is a PostInitOptions that also supports getting and setting property values of different types. +// +// Since ADBC API revision 1.1.0. +type GetSetOptions interface { + PostInitOptions + + SetOption(key, value string) error + SetOptionInt(key, value int64) error + SetOptionDouble(key, value float64) error + GetOptionInt(key string) (int64, error) + GetOptionDouble(key string) (float64, error) +} diff --git a/go/adbc/infocode_string.go b/go/adbc/infocode_string.go index 73af20c1e1..df0fd74b96 100644 --- a/go/adbc/infocode_string.go +++ b/go/adbc/infocode_string.go @@ -14,23 +14,24 @@ func _() { _ = x[InfoDriverName-100] _ = x[InfoDriverVersion-101] _ = x[InfoDriverArrowVersion-102] + _ = x[InfoDriverADBCVersion-103] } const ( _InfoCode_name_0 = "VendorNameVendorVersionVendorArrowVersion" - _InfoCode_name_1 = "DriverNameDriverVersionDriverArrowVersion" + _InfoCode_name_1 = "DriverNameDriverVersionDriverArrowVersionDriverADBCVersion" ) var ( _InfoCode_index_0 = [...]uint8{0, 10, 23, 41} - _InfoCode_index_1 = [...]uint8{0, 10, 23, 41} + _InfoCode_index_1 = [...]uint8{0, 10, 23, 41, 58} ) func (i InfoCode) String() string { switch { case i <= 2: return _InfoCode_name_0[_InfoCode_index_0[i]:_InfoCode_index_0[i+1]] - case 100 <= i && i <= 102: + case 100 <= i && i <= 103: i -= 100 return _InfoCode_name_1[_InfoCode_index_1[i]:_InfoCode_index_1[i+1]] default: diff --git a/go/adbc/pkg/_tmpl/driver.go.tmpl b/go/adbc/pkg/_tmpl/driver.go.tmpl index fe24bf9e69..706a0fb180 100644 --- a/go/adbc/pkg/_tmpl/driver.go.tmpl +++ b/go/adbc/pkg/_tmpl/driver.go.tmpl @@ -689,7 +689,7 @@ func {{.Prefix}}DriverInit(version C.int, rawDriver *C.void, err *C.struct_AdbcE } driver := (*C.struct_AdbcDriver)(unsafe.Pointer(rawDriver)) - C.memset(unsafe.Pointer(driver), 0, C.sizeof_struct_AdbcDriver) + C.memset(unsafe.Pointer(driver), 0, C.ADBC_DRIVER_1_0_0_SIZE) driver.DatabaseInit = (*[0]byte)(C.{{.Prefix}}DatabaseInit) driver.DatabaseNew = (*[0]byte)(C.{{.Prefix}}DatabaseNew) driver.DatabaseRelease = (*[0]byte)(C.{{.Prefix}}DatabaseRelease) diff --git a/go/adbc/pkg/flightsql/driver.go b/go/adbc/pkg/flightsql/driver.go index a3107e5829..77e39c6f74 100644 --- a/go/adbc/pkg/flightsql/driver.go +++ b/go/adbc/pkg/flightsql/driver.go @@ -692,7 +692,7 @@ func FlightSQLDriverInit(version C.int, rawDriver *C.void, err *C.struct_AdbcErr } driver := (*C.struct_AdbcDriver)(unsafe.Pointer(rawDriver)) - C.memset(unsafe.Pointer(driver), 0, C.sizeof_struct_AdbcDriver) + C.memset(unsafe.Pointer(driver), 0, C.ADBC_DRIVER_1_0_0_SIZE) driver.DatabaseInit = (*[0]byte)(C.FlightSQLDatabaseInit) driver.DatabaseNew = (*[0]byte)(C.FlightSQLDatabaseNew) driver.DatabaseRelease = (*[0]byte)(C.FlightSQLDatabaseRelease) diff --git a/go/adbc/pkg/snowflake/driver.go b/go/adbc/pkg/snowflake/driver.go index 296c6718af..1875107763 100644 --- a/go/adbc/pkg/snowflake/driver.go +++ b/go/adbc/pkg/snowflake/driver.go @@ -692,7 +692,7 @@ func SnowflakeDriverInit(version C.int, rawDriver *C.void, err *C.struct_AdbcErr } driver := (*C.struct_AdbcDriver)(unsafe.Pointer(rawDriver)) - C.memset(unsafe.Pointer(driver), 0, C.sizeof_struct_AdbcDriver) + C.memset(unsafe.Pointer(driver), 0, C.ADBC_DRIVER_1_0_0_SIZE) driver.DatabaseInit = (*[0]byte)(C.SnowflakeDatabaseInit) driver.DatabaseNew = (*[0]byte)(C.SnowflakeDatabaseNew) driver.DatabaseRelease = (*[0]byte)(C.SnowflakeDatabaseRelease) diff --git a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcConnection.java b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcConnection.java index fea705482a..d3c8119186 100644 --- a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcConnection.java +++ b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcConnection.java @@ -27,7 +27,7 @@ *

Connections are not required to be thread-safe, but they can be used from multiple threads so * long as clients take care to serialize accesses to a connection. */ -public interface AdbcConnection extends AutoCloseable { +public interface AdbcConnection extends AutoCloseable, AdbcOptions { /** Commit the pending transaction. */ default void commit() throws AdbcException { throw AdbcException.notImplemented("Connection does not support transactions"); @@ -285,6 +285,42 @@ default void setAutoCommit(boolean enableAutoCommit) throws AdbcException { throw AdbcException.notImplemented("Connection does not support transactions"); } + /** + * Get the current catalog. + * + * @since ADBC API revision 1.1.0 + */ + default String getCurrentCatalog() throws AdbcException { + throw AdbcException.notImplemented("Connection does not support current catalog"); + } + + /** + * Set the current catalog. + * + * @since ADBC API revision 1.1.0 + */ + default void setCurrentCatalog(String catalog) throws AdbcException { + throw AdbcException.notImplemented("Connection does not support current catalog"); + } + + /** + * Get the current schema. + * + * @since ADBC API revision 1.1.0 + */ + default String getCurrentDbSchema() throws AdbcException { + throw AdbcException.notImplemented("Connection does not support current catalog"); + } + + /** + * Set the current schema. + * + * @since ADBC API revision 1.1.0 + */ + default void setCurrentDbSchema(String catalog) throws AdbcException { + throw AdbcException.notImplemented("Connection does not support current catalog"); + } + /** * Get whether the connection is read-only. * diff --git a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcDatabase.java b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcDatabase.java index e63c598be9..723acfc0da 100644 --- a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcDatabase.java +++ b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcDatabase.java @@ -24,7 +24,7 @@ * remote/networked databases, for in-memory databases, this object provides an explicit point of * ownership. */ -public interface AdbcDatabase extends AutoCloseable { +public interface AdbcDatabase extends AutoCloseable, AdbcOptions { /** Create a new connection to the database. */ AdbcConnection connect() throws AdbcException; } diff --git a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcDriver.java b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcDriver.java index 80abd18560..9386b88089 100644 --- a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcDriver.java +++ b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcDriver.java @@ -21,11 +21,42 @@ /** A handle to an ADBC database driver. */ public interface AdbcDriver { - /** The standard parameter name for a connection URL (type String). */ - String PARAM_URL = "adbc.url"; + /** + * The standard parameter name for a password (type String). + * + * @since ADBC API revision 1.1.0 + */ + AdbcOptionKey PARAM_PASSWORD = new AdbcOptionKey<>("password", String.class); + + /** + * The standard parameter name for a connection URI (type String). + * + * @since ADBC API revision 1.1.0 + */ + AdbcOptionKey PARAM_URI = new AdbcOptionKey<>("uri", String.class); + + /** + * The standard parameter name for a connection URL (type String). + * + * @deprecated Prefer {@link #PARAM_URI} instead. + */ + @Deprecated String PARAM_URL = "adbc.url"; + + /** + * The standard parameter name for a username (type String). + * + * @since ADBC API revision 1.1.0 + */ + AdbcOptionKey PARAM_USERNAME = new AdbcOptionKey<>("username", String.class); + /** The standard parameter name for SQL quirks configuration (type SqlQuirks). */ String PARAM_SQL_QUIRKS = "adbc.sql.quirks"; + /** ADBC API revision 1.0.0. */ + long ADBC_VERSION_1_0_0 = 1_000_000; + /** ADBC API revision 1.1.0. */ + long ADBC_VERSION_1_1_0 = 1_001_000; + /** * Open a database via this driver. * diff --git a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcInfoCode.java b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcInfoCode.java index 52c0956564..8d5c73ba9f 100644 --- a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcInfoCode.java +++ b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcInfoCode.java @@ -16,7 +16,12 @@ */ package org.apache.arrow.adbc.core; -/** Integer IDs used for requesting information about the database/driver. */ +/** + * Integer IDs used for requesting information about the database/driver. + * + *

Since ADBC 1.1.0: the range [500, 1_000) is reserved for "XDBC" information, which is the same + * metadata provided by the same info code range in the Arrow Flight SQL GetSqlInfo RPC. + */ public enum AdbcInfoCode { /** The database vendor/product name (e.g. the server name) (type: utf8). */ VENDOR_NAME(0), @@ -31,6 +36,16 @@ public enum AdbcInfoCode { DRIVER_VERSION(101), /** The driver Arrow library version (type: utf8). */ DRIVER_ARROW_VERSION(102), + /** + * The ADBC API version (type: int64). + * + *

The value should be one of the ADBC_VERSION constants. + * + * @see AdbcDriver#ADBC_VERSION_1_0_0 + * @see AdbcDriver#ADBC_VERSION_1_1_0 + * @since ADBC API revision 1.1.0 + */ + DRIVER_ADBC_VERSION(103), ; private final int value; diff --git a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcOptionKey.java b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcOptionKey.java new file mode 100644 index 0000000000..d594703688 --- /dev/null +++ b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcOptionKey.java @@ -0,0 +1,69 @@ +/* + * 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. + */ + +package org.apache.arrow.adbc.core; + +import java.util.Map; +import java.util.Objects; + +/** + * A typesafe option key. + * + * @since ADBC API revision 1.1.0 + * @param The option value type. + */ +public final class AdbcOptionKey { + private final String key; + private final Class type; + + public AdbcOptionKey(String key, Class type) { + this.key = Objects.requireNonNull(key); + this.type = Objects.requireNonNull(type); + } + + /** + * Set this option in an options map (like for {@link AdbcDriver#open(Map)}. + * + * @param options The options. + * @param value The option value. + */ + public void set(Map options, T value) { + options.put(key, value); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + AdbcOptionKey that = (AdbcOptionKey) o; + return Objects.equals(key, that.key) && Objects.equals(type, that.type); + } + + @Override + public int hashCode() { + return Objects.hash(key, type); + } + + @Override + public String toString() { + return "AdbcOptionKey{" + key + ", " + type + '}'; + } +} diff --git a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcOptions.java b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcOptions.java new file mode 100644 index 0000000000..efd8eab77b --- /dev/null +++ b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcOptions.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.arrow.adbc.core; + +/** An ADBC object that supports getting/setting generic options. */ +public interface AdbcOptions { + /** + * Get a generic option. + * + * @since ADBC API revision 1.1.0 + * @param key The option to retrieve. + * @return The option value. + * @param The option value type. + */ + default T getOption(AdbcOptionKey key) throws AdbcException { + throw AdbcException.notImplemented("Unsupported option " + key); + } + + /** + * Set a generic option. + * + * @since ADBC API revision 1.1.0 + * @param key The option to set. + * @param value The option value. + * @param The option value type. + */ + default void setOption(AdbcOptionKey key, T value) throws AdbcException { + throw AdbcException.notImplemented("Unsupported option " + key); + } +} diff --git a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcStatement.java b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcStatement.java index ef2be487e2..a033726b9a 100644 --- a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcStatement.java +++ b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcStatement.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.nio.ByteBuffer; +import java.util.Iterator; import java.util.List; import org.apache.arrow.vector.VectorSchemaRoot; import org.apache.arrow.vector.ipc.ArrowReader; @@ -40,8 +41,23 @@ *

Statements are not required to be thread-safe, but they can be used from multiple threads so * long as clients take care to serialize accesses to a statement. */ -public interface AdbcStatement extends AutoCloseable { - /** Set a generic query option. */ +public interface AdbcStatement extends AutoCloseable, AdbcOptions { + /** + * Cancel execution of a query. + * + *

This method must be thread-safe (other method are not necessarily thread-safe). + * + * @since ADBC API revision 1.1.0 + */ + default void cancel() throws AdbcException { + throw AdbcException.notImplemented("Statement does not support cancel"); + } + + /** + * Set a generic query option. + * + * @deprecated Prefer {@link #setOption(AdbcOptionKey, Object)}. + */ default void setOption(String key, Object value) throws AdbcException { throw AdbcException.notImplemented("Unsupported option " + key); } @@ -94,6 +110,37 @@ default PartitionResult executePartitioned() throws AdbcException { throw AdbcException.notImplemented("Statement does not support executePartitioned"); } + /** + * Get the schema of the result set without executing the query. + * + * @since ADBC API revision 1.1.0 + */ + default Schema executeSchema() throws AdbcException { + throw AdbcException.notImplemented("Statement does not support executeSchema"); + } + + /** + * Execute a result set-generating query and get a list of partitions of the result set. + * + *

These can be serialized and deserialized for parallel and/or distributed fetching. + * + *

This may invalidate any prior result sets. + * + * @since ADBC API revision 1.1.0 + */ + default Iterator pollPartitioned() throws AdbcException { + throw AdbcException.notImplemented("Statement does not support pollPartitioned"); + } + + /** + * Get the progress of executing a query. + * + * @since ADBC API revision 1.1.0 + */ + default double getProgress() throws AdbcException { + throw AdbcException.notImplemented("Statement does not support getProgress"); + } + /** * Get the schema for bound parameters. * diff --git a/java/core/src/main/java/org/apache/arrow/adbc/core/BulkIngestMode.java b/java/core/src/main/java/org/apache/arrow/adbc/core/BulkIngestMode.java index 2ab16ac428..e23e8de4ac 100644 --- a/java/core/src/main/java/org/apache/arrow/adbc/core/BulkIngestMode.java +++ b/java/core/src/main/java/org/apache/arrow/adbc/core/BulkIngestMode.java @@ -24,7 +24,20 @@ public enum BulkIngestMode { /** * Do not create the table and append data; error if the table does not exist ({@link * AdbcStatusCode#NOT_FOUND}) or does not match the schema of the data to append ({@link - * AdbcStatusCode#ALREADY_EXISTS}). * + * AdbcStatusCode#ALREADY_EXISTS}). */ APPEND, + /** + * Create the table and insert data; drop the original table if it already exists. + * + * @since ADBC API revision 1.1.0 + */ + REPLACE, + /** + * Insert data; create the table if it does not exist, or error ({@link + * AdbcStatusCode#ALREADY_EXISTS}) if the table exists, but the schema does not match the schema + * of the data to append. + */ + CREATE_APPEND, + ; }