glib/adbc-glib/connection.c (237 lines of code) (raw):

/* * 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 is needless. This is just for cpplint. */ #include <adbc-glib/connection.h> #include <adbc-glib/connection-raw.h> #include <adbc-glib/database-raw.h> #include <adbc-glib/error-raw.h> /** * SECTION: connection * @title: GADBCConnection * @include: adbc-glib/adbc-glib.h * * #GADBCConnection is a class for connection. */ #define BOOLEAN_TO_OPTION_VALUE(boolean) \ ((boolean) ? ADBC_OPTION_VALUE_ENABLED : ADBC_OPTION_VALUE_DISABLED) /** * gadbc_isolation_level_to_string: * @level: A #GADBCIsolationLevel. * * Returns: The string representation of @level. * * Since: 0.4.0 */ const gchar* gadbc_isolation_level_to_string(GADBCIsolationLevel level) { switch (level) { case GADBC_ISOLATION_LEVEL_DEFAULT: return ADBC_OPTION_ISOLATION_LEVEL_DEFAULT; case GADBC_ISOLATION_LEVEL_READ_UNCOMMITTED: return ADBC_OPTION_ISOLATION_LEVEL_READ_UNCOMMITTED; case GADBC_ISOLATION_LEVEL_READ_COMMITTED: return ADBC_OPTION_ISOLATION_LEVEL_READ_COMMITTED; case GADBC_ISOLATION_LEVEL_REPEATABLE_READ: return ADBC_OPTION_ISOLATION_LEVEL_REPEATABLE_READ; case GADBC_ISOLATION_LEVEL_SNAPSHOT: return ADBC_OPTION_ISOLATION_LEVEL_SNAPSHOT; case GADBC_ISOLATION_LEVEL_SERIALIZABLE: return ADBC_OPTION_ISOLATION_LEVEL_SERIALIZABLE; case GADBC_ISOLATION_LEVEL_LINEARIZABLE: return ADBC_OPTION_ISOLATION_LEVEL_LINEARIZABLE; default: return "adbc.connection.transaction.isolation.invalid"; } } typedef struct { gboolean initialized; struct AdbcConnection adbc_connection; GADBCDatabase* database; } GADBCConnectionPrivate; #define gadbc_connection_init gadbc_connection_init_ G_DEFINE_TYPE_WITH_PRIVATE(GADBCConnection, gadbc_connection, G_TYPE_OBJECT) #undef gadbc_connection_init static void gadbc_connection_dispose(GObject* object) { GADBCConnectionPrivate* priv = gadbc_connection_get_instance_private(GADBC_CONNECTION(object)); if (priv->initialized) { struct AdbcError adbc_error = {}; AdbcStatusCode status_code = AdbcConnectionRelease(&(priv->adbc_connection), &adbc_error); gadbc_error_warn(status_code, &adbc_error, "[adbc][connection][finalize]"); } if (priv->database) { g_object_unref(priv->database); priv->database = NULL; } G_OBJECT_CLASS(gadbc_connection_parent_class)->dispose(object); } static void gadbc_connection_init_(GADBCConnection* connection) {} static void gadbc_connection_class_init(GADBCConnectionClass* klass) { GObjectClass* gobject_class = G_OBJECT_CLASS(klass); gobject_class->dispose = gadbc_connection_dispose; } /** * gadbc_connection_new: * @error: (nullable): Return location for a #GError or %NULL. * * Returns: A newly created #GADBCConnection. * * Since: 0.1.0 */ GADBCConnection* gadbc_connection_new(GError** error) { GADBCConnection* connection = g_object_new(GADBC_TYPE_CONNECTION, NULL); GADBCConnectionPrivate* priv = gadbc_connection_get_instance_private(connection); struct AdbcError adbc_error = {}; AdbcStatusCode status_code = AdbcConnectionNew(&(priv->adbc_connection), &adbc_error); priv->initialized = gadbc_error_check(error, status_code, &adbc_error, "[adbc][connection][new]"); if (!priv->initialized) { g_object_unref(connection); return NULL; } return connection; } /** * gadbc_connection_release: * @connection: A #GADBCConnection. * @error: (nullable): Return location for a #GError or %NULL. * * Release this connection explicitly. Normally, you don't need to call * this explicitly. If this connection is freed by g_object_unref(), * this connection is released automatically. * * You can't use this connection anymore after you call this. * * Returns: %TRUE if this connection is released successfully, %FALSE otherwise. * * Since: 0.1.0 */ gboolean gadbc_connection_release(GADBCConnection* connection, GError** error) { const gchar* context = "[adbc][connection][release]"; struct AdbcConnection* adbc_connection = gadbc_connection_get_raw(connection, context, error); if (!adbc_connection) { return FALSE; } struct AdbcError adbc_error = {}; AdbcStatusCode status_code = AdbcConnectionRelease(adbc_connection, &adbc_error); gboolean success = gadbc_error_check(error, status_code, &adbc_error, context); if (success) { GADBCConnectionPrivate* priv = gadbc_connection_get_instance_private(connection); priv->initialized = FALSE; } return success; } /** * gadbc_connection_set_option: * @connection: A #GADBCConnection. * @key: An option key. * @value: An option value. * @error: (nullable): Return location for a #GError or %NULL. * * Options may be set before gadbc_connection_init(). Some drivers may * support setting options after initialization as well. * * Returns: %TRUE if option is set successfully, %FALSE otherwise. * * Since: 0.1.0 */ gboolean gadbc_connection_set_option(GADBCConnection* connection, const gchar* key, const gchar* value, GError** error) { const gchar* context = "[adbc][connection][set-option]"; struct AdbcConnection* adbc_connection = gadbc_connection_get_raw(connection, context, error); if (!adbc_connection) { return FALSE; } struct AdbcError adbc_error = {}; AdbcStatusCode status_code = AdbcConnectionSetOption(adbc_connection, key, value, &adbc_error); return gadbc_error_check(error, status_code, &adbc_error, context); } /** * gadbc_connection_set_auto_commit: * @connection: A #GADBCConnection. * @auto_commit: Whether auto commit is enabled or not. * @error: (nullable): Return location for a #GError or %NULL. * * Returns: %TRUE if this is set successfully, %FALSE otherwise. * * Since: 0.4.0 */ gboolean gadbc_connection_set_auto_commit(GADBCConnection* connection, gboolean auto_commit, GError** error) { return gadbc_connection_set_option(connection, ADBC_CONNECTION_OPTION_AUTOCOMMIT, BOOLEAN_TO_OPTION_VALUE(auto_commit), error); } /** * gadbc_connection_set_read_only: * @connection: A #GADBCConnection. * @read_only: Whether read only or not. * @error: (nullable): Return location for a #GError or %NULL. * * Returns: %TRUE if this is set successfully, %FALSE otherwise. * * Since: 0.4.0 */ gboolean gadbc_connection_set_read_only(GADBCConnection* connection, gboolean read_only, GError** error) { return gadbc_connection_set_option(connection, ADBC_CONNECTION_OPTION_READ_ONLY, BOOLEAN_TO_OPTION_VALUE(read_only), error); } /** * gadbc_connection_set_isolation_level: * @connection: A #GADBCConnection. * @level: A #GADBCIsolationLevel to be used. * @error: (nullable): Return location for a #GError or %NULL. * * Returns: %TRUE if this is set successfully, %FALSE otherwise. * * Since: 0.4.0 */ gboolean gadbc_connection_set_isolation_level(GADBCConnection* connection, GADBCIsolationLevel level, GError** error) { return gadbc_connection_set_option(connection, ADBC_CONNECTION_OPTION_ISOLATION_LEVEL, gadbc_isolation_level_to_string(level), error); } /** * gadbc_connection_init: * @connection: A #GADBCConnection. * @database: A #GADBCDatabase. * @error: (nullable): Return location for a #GError or %NULL. * * Finish setting options and initialize the connection. * * Some drivers may support setting options after initialization as * well. * * Returns: %TRUE if initialization is done successfully, %FALSE otherwise. * * Since: 0.1.0 */ gboolean gadbc_connection_init(GADBCConnection* connection, GADBCDatabase* database, GError** error) { const gchar* context = "[adbc][connection][init]"; struct AdbcConnection* adbc_connection = gadbc_connection_get_raw(connection, context, error); if (!adbc_connection) { return FALSE; } struct AdbcDatabase* adbc_database = gadbc_database_get_raw(database, context, error); struct AdbcError adbc_error = {}; AdbcStatusCode status_code = AdbcConnectionInit(adbc_connection, adbc_database, &adbc_error); gboolean success = gadbc_error_check(error, status_code, &adbc_error, context); if (success) { GADBCConnectionPrivate* priv = gadbc_connection_get_instance_private(connection); priv->database = database; g_object_ref(priv->database); } return success; } /** * gadbc_connection_get_info: * @connection: A #GADBCConnection. * @info_codes: (nullable) (array length=n_info_codes): A list of * metadata codes to fetch, or %NULL to fetch all. * @n_info_codes: The length of the info_codes parameter. Ignored if * info_codes is %NULL. * @error: (nullable): Return location for a #GError or %NULL. * * The result is an Arrow dataset with the following schema: * * Field Name | Field Type * ----------------------------|------------------------ * info_name | uint32 not null * info_value | INFO_SCHEMA * * INFO_SCHEMA is a dense union with members: * * Field Name (Type Code) | Field Type * ----------------------------|------------------------ * string_value (0) | utf8 * bool_value (1) | bool * int64_value (2) | int64 * int32_bitmask (3) | int32 * string_list (4) | list<utf8> * int32_to_int32_list_map (5) | map<int32, list<int32>> * * Each metadatum is identified by an integer code. The recognized * 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). * * Returns: The result set as `struct ArrowArrayStream *`. It should * be freed with the `ArrowArrayStream::release` callback then * g_free() when no longer needed. * * Since: 0.4.0 */ gpointer gadbc_connection_get_info(GADBCConnection* connection, guint32* info_codes, gsize n_info_codes, GError** error) { const gchar* context = "[adbc][connection][get-info]"; struct AdbcConnection* adbc_connection = gadbc_connection_get_raw(connection, context, error); if (!adbc_connection) { return NULL; } struct ArrowArrayStream* array_stream = g_new0(struct ArrowArrayStream, 1); struct AdbcError adbc_error = {}; AdbcStatusCode status_code = AdbcConnectionGetInfo( adbc_connection, info_codes, n_info_codes, array_stream, &adbc_error); if (gadbc_error_check(error, status_code, &adbc_error, context)) { return array_stream; } else { g_free(array_stream); return NULL; } } /** * gadbc_connection_get_objects: * @connection: A #GADBCConnection. * @depth: The level of nesting to display. If * @GADBC_OBJECT_DEPTH_ALL, display all levels. If * @GADBC_OBJECT_DEPTH_CATALOGS, display only catalogs * (i.e. `catalog_schemas` will be null). If * @GADBC_OBJECT_DEPTH_DB_SCHEMAS, display only catalogs and schemas * (i.e. `db_schema_tables` will be null). if * @GADBC_OBJECT_DEPTH_TABLES, display only catalogs, schemas and * tables (i.e. `table_columns` and `table_constraints` will be * null). * @catalog: (nullable): Only show tables in the given catalog. If * %NULL, do not filter by catalog. If an empty string, only show * tables without a catalog. May be a search pattern (see section * documentation). * @db_schema: (nullable): Only show tables in the given database * schema. If %NULL, do not filter by database schema. If an empty * string, only show tables without a database schema. May be a * search pattern (see section documentation). * @table_name: (nullable): Only show tables with the given name. If * %NULL, do not filter by name. May be a search pattern (see * section documentation). * @table_types: (nullable) (array zero-terminated=1): Only show * tables matching one of the given table types. If %NULL, show * tables of any type. Valid table types can be fetched from * gadbc_connection_get_table_types(). Terminate the list with a * %NULL entry. * @column_name: (nullable): Only show columns with the given name. If * %NULL, do not filter by name. May be a search pattern (see section * documentation). * @error: (nullable): Return location for a #GError or %NULL. * * Get a hierarchical view of all catalogs, database schemas, tables, * and columns. * * The result is an Arrow dataset with the following schema: * * | Field Name | Field Type | * |--------------------------|-------------------------| * | catalog_name | utf8 | * | catalog_db_schemas | list<DB_SCHEMA_SCHEMA> | * * DB_SCHEMA_SCHEMA is a Struct with fields: * * | Field Name | Field Type | * |--------------------------|-------------------------| * | db_schema_name | utf8 | * | db_schema_tables | list<TABLE_SCHEMA> | * * TABLE_SCHEMA is a Struct with fields: * * | Field Name | Field Type | * |--------------------------|-------------------------| * | table_name | utf8 not null | * | table_type | utf8 not null | * | table_columns | list<COLUMN_SCHEMA> | * | table_constraints | list<CONSTRAINT_SCHEMA> | * * COLUMN_SCHEMA is a Struct with fields: * * | Field Name | Field Type | Comments | * |--------------------------|-------------------------|----------| * | column_name | utf8 not null | | * | ordinal_position | int32 | (1) | * | remarks | utf8 | (2) | * | xdbc_data_type | int16 | (3) | * | xdbc_type_name | utf8 | (3) | * | xdbc_column_size | int32 | (3) | * | xdbc_decimal_digits | int16 | (3) | * | xdbc_num_prec_radix | int16 | (3) | * | xdbc_nullable | int16 | (3) | * | xdbc_column_def | utf8 | (3) | * | xdbc_sql_data_type | int16 | (3) | * | xdbc_datetime_sub | int16 | (3) | * | xdbc_char_octet_length | int32 | (3) | * | xdbc_is_nullable | utf8 | (3) | * | xdbc_scope_catalog | utf8 | (3) | * | xdbc_scope_schema | utf8 | (3) | * | xdbc_scope_table | utf8 | (3) | * | xdbc_is_autoincrement | bool | (3) | * | xdbc_is_generatedcolumn | bool | (3) | * * 1. The column's ordinal position in the table (starting from 1). * 2. Database-specific description of the column. * 3. Optional value. Should be null if not supported by the driver. * xdbc_ values are meant to provide JDBC/ODBC-compatible metadata * in an agnostic manner. * * CONSTRAINT_SCHEMA is a Struct with fields: * * | Field Name | Field Type | Comments | * |--------------------------|-------------------------|----------| * | constraint_name | utf8 | | * | constraint_type | utf8 not null | (1) | * | constraint_column_names | list<utf8> not null | (2) | * | constraint_column_usage | list<USAGE_SCHEMA> | (3) | * * 1. One of 'CHECK', 'FOREIGN KEY', 'PRIMARY KEY', or 'UNIQUE'. * 2. The columns on the current table that are constrained, in * order. * 3. For FOREIGN KEY only, the referenced table and columns. * * USAGE_SCHEMA is a Struct with fields: * * | Field Name | Field Type | * |--------------------------|-------------------------| * | fk_catalog | utf8 | * | fk_db_schema | utf8 | * | fk_table | utf8 not null | * | fk_column_name | utf8 not null | * * Returns: The result set as `struct ArrowArrayStream *`. It should * be freed with the `ArrowArrayStream::release` callback then * g_free() when no longer needed. * * Since: 0.4.0 */ gpointer gadbc_connection_get_objects(GADBCConnection* connection, GADBCObjectDepth depth, const gchar* catalog, const gchar* db_schema, const gchar* table_name, const gchar** table_types, const gchar* column_name, GError** error) { const gchar* context = "[adbc][connection][get-objects]"; struct AdbcConnection* adbc_connection = gadbc_connection_get_raw(connection, context, error); if (!adbc_connection) { return NULL; } struct ArrowArrayStream* array_stream = g_new0(struct ArrowArrayStream, 1); struct AdbcError adbc_error = {}; AdbcStatusCode status_code = AdbcConnectionGetObjects(adbc_connection, depth, catalog, db_schema, table_name, table_types, column_name, array_stream, &adbc_error); if (gadbc_error_check(error, status_code, &adbc_error, context)) { return array_stream; } else { g_free(array_stream); return NULL; } } /** * gadbc_connection_get_table_schema: * @connection: A #GADBCConnection. * @catalog: (nullable): A catalog or %NULL if not applicable. * @db_schema: (nullable): A database schema or %NULL if not applicable. * @table_name: A table name. * @error: (nullable): Return location for a #GError or %NULL. * * Get the Apache Arrow schema of a table. * * Returns: The result set as `struct ArrowSchema *`. It should * be freed with the `ArrowSchema::release` callback then * g_free() when no longer needed. * * Since: 0.4.0 */ gpointer gadbc_connection_get_table_schema(GADBCConnection* connection, const gchar* catalog, const gchar* db_schema, const gchar* table_name, GError** error) { const gchar* context = "[adbc][connection][get-table-schema]"; struct AdbcConnection* adbc_connection = gadbc_connection_get_raw(connection, context, error); if (!adbc_connection) { return NULL; } struct ArrowSchema* array_schema = g_new0(struct ArrowSchema, 1); struct AdbcError adbc_error = {}; AdbcStatusCode status_code = AdbcConnectionGetTableSchema( adbc_connection, catalog, db_schema, table_name, array_schema, &adbc_error); if (gadbc_error_check(error, status_code, &adbc_error, context)) { return array_schema; } else { g_free(array_schema); return NULL; } } /** * gadbc_connection_get_table_types: * @connection: A #GADBCConnection. * @error: (nullable): Return location for a #GError or %NULL. * * Get a list of table types in the database. * * The result is an Arrow dataset with the following schema: * * Field Name | Field Type * ---------------|-------------- * table_type | utf8 not null * * * Returns: The result set as `struct ArrowArrayStream *`. It should * be freed with the `ArrowArrayStream::release` callback then * g_free() when no longer needed. * * Since: 0.4.0 */ gpointer gadbc_connection_get_table_types(GADBCConnection* connection, GError** error) { const gchar* context = "[adbc][connection][get-table-types]"; struct AdbcConnection* adbc_connection = gadbc_connection_get_raw(connection, context, error); if (!adbc_connection) { return NULL; } struct ArrowArrayStream* array_stream = g_new0(struct ArrowArrayStream, 1); struct AdbcError adbc_error = {}; AdbcStatusCode status_code = AdbcConnectionGetTableTypes(adbc_connection, array_stream, &adbc_error); if (gadbc_error_check(error, status_code, &adbc_error, context)) { return array_stream; } else { g_free(array_stream); return NULL; } } /** * gadbc_connection_commit: * @connection: A #GADBCConnection. * @error: (nullable): Return location for a #GError or %NULL. * * Commit any pending transactions. Only used if auto commit is * disabled. * * Behavior is undefined if this is mixed with SQL transaction * statements. * * Returns: %TRUE if the commit is done successfully, %FALSE * otherwise. * * Since: 0.4.0 */ gboolean gadbc_connection_commit(GADBCConnection* connection, GError** error) { const gchar* context = "[adbc][connection][commit]"; struct AdbcConnection* adbc_connection = gadbc_connection_get_raw(connection, context, error); struct AdbcError adbc_error = {}; return gadbc_error_check(error, AdbcConnectionCommit(adbc_connection, &adbc_error), &adbc_error, context); } /** * gadbc_connection_rollback: * @connection: A #GADBCConnection. * @error: (nullable): Return location for a #GError or %NULL. * * Rollback any pending transactions. Only used if auto commit is * disabled. * * Behavior is undefined if this is mixed with SQL transaction * statements. * * Returns: %TRUE if the rollback is done successfully, %FALSE * otherwise. * * Since: 0.4.0 */ gboolean gadbc_connection_rollback(GADBCConnection* connection, GError** error) { const gchar* context = "[adbc][connection][rollback]"; struct AdbcConnection* adbc_connection = gadbc_connection_get_raw(connection, context, error); struct AdbcError adbc_error = {}; return gadbc_error_check(error, AdbcConnectionRollback(adbc_connection, &adbc_error), &adbc_error, context); } /** * gadbc_connection_get_raw: * @connection: A #GADBCConnection. * @context: (nullable): A context where this is called from. This is used in * error message. * @error: (nullable): Return location for a #GError or %NULL. * * Returns: (nullable): The underlying `AdbcConnection` if this connection * isn't released yet, %NULL otherwise. * * Since: 0.1.0 */ struct AdbcConnection* gadbc_connection_get_raw(GADBCConnection* connection, const gchar* context, GError** error) { GADBCConnectionPrivate* priv = gadbc_connection_get_instance_private(connection); if (priv->initialized) { return &(priv->adbc_connection); } else { g_set_error(error, GADBC_ERROR, GADBC_ERROR_INVALID_ARGUMENT, "%s connection is already released", context); return NULL; } }