glib/adbc-glib/statement.c (197 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/statement.h> #include <adbc-glib/connection-raw.h> #include <adbc-glib/error-raw.h> #include <adbc-glib/statement-raw.h> /** * SECTION: statement * @title: GADBCStatement * @include: adbc-glib/adbc-glib.h * * #GADBCStatement is a class for statement. */ typedef struct { gboolean initialized; struct AdbcStatement adbc_statement; GADBCConnection* connection; } GADBCStatementPrivate; G_DEFINE_TYPE_WITH_PRIVATE(GADBCStatement, gadbc_statement, G_TYPE_OBJECT) static void gadbc_statement_dispose(GObject* object) { GADBCStatementPrivate* priv = gadbc_statement_get_instance_private(GADBC_STATEMENT(object)); if (priv->initialized) { struct AdbcError adbc_error = {}; AdbcStatusCode status_code = AdbcStatementRelease(&(priv->adbc_statement), &adbc_error); gadbc_error_warn(status_code, &adbc_error, "[adbc][statement][finalize]"); priv->initialized = FALSE; } if (priv->connection) { g_object_unref(priv->connection); priv->connection = NULL; } G_OBJECT_CLASS(gadbc_statement_parent_class)->dispose(object); } static void gadbc_statement_init(GADBCStatement* statement) {} static void gadbc_statement_class_init(GADBCStatementClass* klass) { GObjectClass* gobject_class = G_OBJECT_CLASS(klass); gobject_class->dispose = gadbc_statement_dispose; } /** * gadbc_statement_new: * @connection: A #GADBCConnection. * @error: (nullable): Return location for a #GError or %NULL. * * Returns: A newly created #GADBCStatement for @connection on success, * %NULL otherwise. * * Since: 0.1.0 */ GADBCStatement* gadbc_statement_new(GADBCConnection* connection, GError** error) { const gchar* context = "[adbc][statement][new]"; struct AdbcConnection* adbc_connection = gadbc_connection_get_raw(connection, context, error); if (!adbc_connection) { return NULL; } GADBCStatement* statement = g_object_new(GADBC_TYPE_STATEMENT, NULL); GADBCStatementPrivate* priv = gadbc_statement_get_instance_private(statement); struct AdbcError adbc_error = {}; AdbcStatusCode status_code = AdbcStatementNew(adbc_connection, &(priv->adbc_statement), &adbc_error); priv->initialized = gadbc_error_check(error, status_code, &adbc_error, context); if (!priv->initialized) { g_object_unref(statement); return NULL; } priv->connection = connection; g_object_ref(priv->connection); return statement; } /** * gadbc_statement_release: * @statement: A #GADBCStatement. * @error: (nullable): Return location for a #GError or %NULL. * * Release this statement explicitly. Normally, you don't need to call * this explicitly. If this statement is freed by g_object_unref(), * this statement is released automatically. * * You can't use this statement anymore after you call this. * * Returns: %TRUE if this statement is released successfully, %FALSE otherwise. * * Since: 0.1.0 */ gboolean gadbc_statement_release(GADBCStatement* statement, GError** error) { const gchar* context = "[adbc][statement][release]"; struct AdbcStatement* adbc_statement = gadbc_statement_get_raw(statement, context, error); if (!adbc_statement) { return FALSE; } struct AdbcError adbc_error = {}; AdbcStatusCode status_code = AdbcStatementRelease(adbc_statement, &adbc_error); gboolean success = gadbc_error_check(error, status_code, &adbc_error, context); if (success) { GADBCStatementPrivate* priv = gadbc_statement_get_instance_private(statement); priv->initialized = FALSE; } return success; } /** * gadbc_statement_set_sql_query: * @statement: A #GADBCStatement. * @query: A query to execute. * @error: (out) (optional): Return location for a #GError or %NULL. * * Set the SQL query to execute. * * The query can then be executed with gadbc_statement_execute(). For * queries expected to be executed repeatedly, * gadbc_statement_prepare() the statement first. * * Returns: %TRUE if query is set successfully, %FALSE otherwise. * * Since: 0.1.0 */ gboolean gadbc_statement_set_sql_query(GADBCStatement* statement, const gchar* query, GError** error) { const gchar* context = "[adbc][statement][set-sql-query]"; struct AdbcStatement* adbc_statement = gadbc_statement_get_raw(statement, context, error); if (!adbc_statement) { return FALSE; } struct AdbcError adbc_error = {}; AdbcStatusCode status_code = AdbcStatementSetSqlQuery(adbc_statement, query, &adbc_error); return gadbc_error_check(error, status_code, &adbc_error, context); } static gboolean gadbc_statement_set_option_internal(GADBCStatement* statement, const gchar* key, const gchar* value, const gchar* context, GError** error) { struct AdbcStatement* adbc_statement = gadbc_statement_get_raw(statement, context, error); if (!adbc_statement) { return FALSE; } struct AdbcError adbc_error = {}; AdbcStatusCode status_code = AdbcStatementSetOption(adbc_statement, key, value, &adbc_error); return gadbc_error_check(error, status_code, &adbc_error, context); } /** * gadbc_statement_set_option: * @statement: A #GADBCStatement. * @key: A option key. * @value: A option value. * @error: (out) (optional): Return location for a #GError or %NULL. * * Set a string option on a statement. * * Returns: %TRUE if option is set successfully, %FALSE otherwise. * * Since: 0.4.0 */ gboolean gadbc_statement_set_option(GADBCStatement* statement, const gchar* key, const char* value, GError** error) { const gchar* context = "[adbc][statement][set-option]"; return gadbc_statement_set_option_internal(statement, key, value, context, error); } /** * gadbc_statement_set_ingest_target_table: * @statement: A #GADBCStatement. * @table: A table name to be ingested. * @error: (out) (optional): Return location for a #GError or %NULL. * * Set an ingest target table name on a statement. * * Returns: %TRUE if table is set successfully, %FALSE otherwise. * * Since: 0.4.0 */ gboolean gadbc_statement_set_ingest_target_table(GADBCStatement* statement, const gchar* table, GError** error) { const gchar* context = "[adbc][statement][set-ingest-target-table]"; return gadbc_statement_set_option_internal(statement, ADBC_INGEST_OPTION_TARGET_TABLE, table, context, error); } /** * gadbc_statement_set_ingest_mode: * @statement: A #GADBCStatement. * @mode: A #GADBCIngestMode. * @error: (out) (optional): Return location for a #GError or %NULL. * * Set an ingest mode on a statement. * * Returns: %TRUE if mode is set successfully, %FALSE otherwise. * * Since: 0.4.0 */ gboolean gadbc_statement_set_ingest_mode(GADBCStatement* statement, GADBCIngestMode mode, GError** error) { const gchar* context = "[adbc][statement][set-ingest-mode]"; const gchar* mode_value = ADBC_INGEST_OPTION_MODE_CREATE; switch (mode) { case GADBC_INGEST_MODE_APPEND: mode_value = ADBC_INGEST_OPTION_MODE_APPEND; break; default: break; } return gadbc_statement_set_option_internal(statement, ADBC_INGEST_OPTION_MODE, mode_value, context, error); } /** * gadbc_statement_prepare: * @statement: A #GADBCStatement. * @error: (out) (optional): Return location for a #GError or %NULL. * * Turn this statement into a prepared statement to be * executed multiple times. * * This invalidates any prior result sets. * * Returns: %TRUE if preparation is done successfully, %FALSE * otherwise. * * Since: 0.4.0 */ gboolean gadbc_statement_prepare(GADBCStatement* statement, GError** error) { const gchar* context = "[adbc][statement][prepare]"; struct AdbcStatement* adbc_statement = gadbc_statement_get_raw(statement, context, error); if (!adbc_statement) { return FALSE; } struct AdbcError adbc_error = {}; AdbcStatusCode status_code = AdbcStatementPrepare(adbc_statement, &adbc_error); return gadbc_error_check(error, status_code, &adbc_error, context); } /** * gadbc_statement_bind: * @statement: A #GADBCStatement. * @c_abi_array: A `struct ArrowArray *` of a record batch to * bind. The driver will call the release callback itself, although * it may not do this until the statement is released. * @c_abi_schema: A `struct ArrowSchema *` of @c_abi_array. * @error: (out) (optional): Return location for a #GError or %NULL. * * Bind Arrow data. This can be used for bulk inserts or prepared * statements. * * Returns: %TRUE if binding is done successfully, %FALSE * otherwise. * * Since: 0.4.0 */ gboolean gadbc_statement_bind(GADBCStatement* statement, gpointer c_abi_array, gpointer c_abi_schema, GError** error) { const gchar* context = "[adbc][statement][bind]"; struct AdbcStatement* adbc_statement = gadbc_statement_get_raw(statement, context, error); if (!adbc_statement) { return FALSE; } struct AdbcError adbc_error = {}; AdbcStatusCode status_code = AdbcStatementBind(adbc_statement, c_abi_array, c_abi_schema, &adbc_error); return gadbc_error_check(error, status_code, &adbc_error, context); } /** * gadbc_statement_bind_stream: * @statement: A #GADBCStatement. * @c_abi_array_stream: A `struct ArrowArrayStream *` of record batches stream * to bind. The driver will call the release callback itself, although * it may not do this until the statement is released. * @error: (out) (optional): Return location for a #GError or %NULL. * * Bind Arrow data stream. This can be used for bulk inserts or prepared * statements. * * Returns: %TRUE if binding is done successfully, %FALSE * otherwise. * * Since: 0.4.0 */ gboolean gadbc_statement_bind_stream(GADBCStatement* statement, gpointer c_abi_array_stream, GError** error) { const gchar* context = "[adbc][statement][bind-stream]"; struct AdbcStatement* adbc_statement = gadbc_statement_get_raw(statement, context, error); if (!adbc_statement) { return FALSE; } struct AdbcError adbc_error = {}; AdbcStatusCode status_code = AdbcStatementBindStream(adbc_statement, c_abi_array_stream, &adbc_error); return gadbc_error_check(error, status_code, &adbc_error, context); } /** * gadbc_statement_execute: * @statement: A #GADBCStatement. * @need_result: Whether the results are received by @c_abi_arrray_stream or * not. * @c_abi_array_stream: (out) (optional): Return location for the execution as * `struct ArrowArrayStream *`. It should be freed with the * `ArrowArrayStream::release` callback then g_free() when no longer needed. * @n_rows_affected: (out) (optional): Return location for the number of rows * affected if known. * @error: (out) (optional): Return location for a #GError or %NULL. * * Execute a statement and get the results. * * This invalidates any prior result sets. * * Returns: %TRUE if execution is done successfully, %FALSE otherwise. * * Since: 0.1.0 */ gboolean gadbc_statement_execute(GADBCStatement* statement, gboolean need_result, gpointer* c_abi_array_stream, gint64* n_rows_affected, GError** error) { const gchar* context = "[adbc][statement][execute]"; if (c_abi_array_stream) { *c_abi_array_stream = NULL; } struct AdbcStatement* adbc_statement = gadbc_statement_get_raw(statement, context, error); if (!adbc_statement) { return FALSE; } struct ArrowArrayStream* array_stream = NULL; if (need_result && c_abi_array_stream) { array_stream = g_new0(struct ArrowArrayStream, 1); } struct AdbcError adbc_error = {}; AdbcStatusCode status_code = AdbcStatementExecuteQuery(adbc_statement, array_stream, n_rows_affected, &adbc_error); gboolean success = gadbc_error_check(error, status_code, &adbc_error, context); if (array_stream) { if (success) { *c_abi_array_stream = array_stream; } else { g_free(array_stream); } } return success; } /** * gadbc_statement_get_raw: * @statement: A #GADBCStatement. * @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 `AdbcStatement` if this statement * isn't released yet, %NULL otherwise. * * Since: 0.1.0 */ struct AdbcStatement* gadbc_statement_get_raw(GADBCStatement* statement, const gchar* context, GError** error) { GADBCStatementPrivate* priv = gadbc_statement_get_instance_private(statement); if (priv->initialized) { return &(priv->adbc_statement); } else { g_set_error(error, GADBC_ERROR, GADBC_ERROR_INVALID_ARGUMENT, "%s statement is already released", context); return NULL; } }