/** * midgard_transaction_commit: * @self: #MidgardTransaction instance * * In case of error, #MidgardConnection error is set to MGD_ERR_INTERNAL. * * Returns: %TRUE on success, %FALSE otherwise * * Since: 9.09 */ gboolean midgard_transaction_commit (MidgardTransaction *self) { _ASSERT_T_MGD(self); gboolean rv = FALSE; GdaConnection *cnc = _T_CNC(self); MidgardConnection *mgd = self->priv->mgd; GError *error = NULL; g_debug("Commit named transaction '%s'", self->priv->name); rv = gda_connection_commit_transaction(cnc, self->priv->name, &error); if (!error && rv) return TRUE; midgard_set_error(mgd, MGD_GENERIC_ERROR, MGD_ERR_INTERNAL, error && error->message ? error->message : " Unknown error."); if (error) g_error_free(error); return FALSE; }
void midgard_cr_core_transaction_commit (MidgardCRCoreTransaction *self, GError **error) { _ASSERT_T_MGD (self); gboolean rv = FALSE; GdaConnection *cnc = _T_CNC (self); MidgardCRSQLStorageManager *manager = self->priv->manager; GError *err = NULL; rv = gda_connection_commit_transaction (cnc, self->priv->name, &err); if (err) g_propagate_error (error, err); if (!rv && !err) g_warning ("Failed to commit underlying database transaction and no error has been set"); return; }
/** * gda_xa_transaction_commit: * @xa_trans: a #GdaXaTransaction object * @cnc_to_recover: (allow-none) (element-type Gda.Connection) (out callee-allocates): a place to store the list of connections for which the commit phase failed, or %NULL * @error: a place to store errors, or %NULL * * Commits a distributed transaction (managed by @xa_trans). The commit is composed of two phases: * <itemizedlist> * <listitem><para>a PREPARE phase where all the connections are required to store their transaction data to a * permanent place (to be able to complete the commit should a problem occur afterwards)</para></listitem> * <listitem><para>a COMMIT phase where the transaction data is actually written to the database</para></listitem> * </itemizedlist> * * If the PREPARE phase fails for any of the connection registered with @xa_trans, then the distributed commit * fails and FALSE is returned. During the COMMIT phase, some commit may actually fail but the transaction can * still be completed because the PREPARE phase succeeded (through the recover method). * * Returns: TRUE if no error occurred (there may be some connections to recover, though) */ gboolean gda_xa_transaction_commit (GdaXaTransaction *xa_trans, GSList **cnc_to_recover, GError **error) { GList *list; if (cnc_to_recover) *cnc_to_recover = NULL; g_return_val_if_fail (GDA_IS_XA_TRANSACTION (xa_trans), FALSE); /* * PREPARE phase */ for (list = xa_trans->priv->cnc_list; list; list = list->next) { GdaConnection *cnc = NULL; GdaServerProvider *prov; const GdaBinary *branch; if (cnc == xa_trans->priv->non_xa_cnc) continue; cnc = GDA_CONNECTION (list->data); prov = gda_connection_get_provider (cnc); branch = g_hash_table_lookup (xa_trans->priv->cnc_hash, cnc); memcpy (xa_trans->priv->xid.data + xa_trans->priv->xid.gtrid_length, /* Flawfinder: ignore */ branch->data, branch->binary_length); if (PROV_CLASS (prov)->xa_funcs->xa_end && !PROV_CLASS (prov)->xa_funcs->xa_end (prov, cnc, &(xa_trans->priv->xid), error)) break; if (!PROV_CLASS (prov)->xa_funcs->xa_prepare) { g_warning (_("Provider error: %s method not implemented for provider %s"), "xa_prepare()", gda_server_provider_get_name (prov)); break; } if (!PROV_CLASS (prov)->xa_funcs->xa_commit) { g_warning (_("Provider error: %s method not implemented for provider %s"), "xa_commit()", gda_server_provider_get_name (prov)); break; } if (!PROV_CLASS (prov)->xa_funcs->xa_prepare (prov, cnc, &(xa_trans->priv->xid), error)) break; } if (list) { /* something went wrong during the PREPARE phase => rollback everything */ for (; list; list = list->prev) { GdaConnection *cnc = NULL; GdaServerProvider *prov; if (cnc == xa_trans->priv->non_xa_cnc) gda_connection_rollback_transaction (cnc, NULL, NULL); else { const GdaBinary *branch; cnc = GDA_CONNECTION (list->data); prov = gda_connection_get_provider (cnc); branch = g_hash_table_lookup (xa_trans->priv->cnc_hash, cnc); memcpy (xa_trans->priv->xid.data + xa_trans->priv->xid.gtrid_length, /* Flawfinder: ignore */ branch->data, branch->binary_length); if (PROV_CLASS (prov)->xa_funcs->xa_rollback) PROV_CLASS (prov)->xa_funcs->xa_rollback (prov, cnc, &(xa_trans->priv->xid), NULL); else g_warning (_("Provider error: %s method not implemented for provider %s"), "xa_rollback()", gda_server_provider_get_name (prov)); } } return FALSE; } /* * COMMIT phase */ if (xa_trans->priv->non_xa_cnc && ! gda_connection_commit_transaction (xa_trans->priv->non_xa_cnc, NULL, error)) { /* something went wrong => rollback everything */ for (list = xa_trans->priv->cnc_list; list; list = list->next) { GdaConnection *cnc = NULL; GdaServerProvider *prov; if (cnc == xa_trans->priv->non_xa_cnc) gda_connection_rollback_transaction (cnc, NULL, NULL); else { const GdaBinary *branch; cnc = GDA_CONNECTION (list->data); prov = gda_connection_get_provider (cnc); branch = g_hash_table_lookup (xa_trans->priv->cnc_hash, cnc); memcpy (xa_trans->priv->xid.data + xa_trans->priv->xid.gtrid_length, /* Flawfinder: ignore */ branch->data, branch->binary_length); if (PROV_CLASS (prov)->xa_funcs->xa_rollback) PROV_CLASS (prov)->xa_funcs->xa_rollback (prov, cnc, &(xa_trans->priv->xid), NULL); else g_warning (_("Provider error: %s method not implemented for provider %s"), "xa_rollback()", gda_server_provider_get_name (prov)); } } return FALSE; } for (list = xa_trans->priv->cnc_list; list; list = list->next) { GdaConnection *cnc = NULL; GdaServerProvider *prov; const GdaBinary *branch; if (cnc == xa_trans->priv->non_xa_cnc) continue; cnc = GDA_CONNECTION (list->data); prov = gda_connection_get_provider (cnc); branch = g_hash_table_lookup (xa_trans->priv->cnc_hash, cnc); memcpy (xa_trans->priv->xid.data + xa_trans->priv->xid.gtrid_length, /* Flawfinder: ignore */ branch->data, branch->binary_length); if (!PROV_CLASS (prov)->xa_funcs->xa_commit (prov, cnc, &(xa_trans->priv->xid), error) && cnc_to_recover) *cnc_to_recover = g_slist_prepend (*cnc_to_recover, cnc); } return TRUE; }
/** * gda_xa_transaction_commit: * @xa_trans: a #GdaXaTransaction object * @cnc_to_recover: (nullable) (element-type Gda.Connection) (out callee-allocates): a place to store the list of connections for which the commit phase failed, or %NULL * @error: a place to store errors, or %NULL * * Commits a distributed transaction (managed by @xa_trans). The commit is composed of two phases: * <itemizedlist> * <listitem><para>a PREPARE phase where all the connections are required to store their transaction data to a * permanent place (to be able to complete the commit should a problem occur afterwards)</para></listitem> * <listitem><para>a COMMIT phase where the transaction data is actually written to the database</para></listitem> * </itemizedlist> * * If the PREPARE phase fails for any of the connection registered with @xa_trans, then the distributed commit * fails and FALSE is returned. During the COMMIT phase, some commit may actually fail but the transaction can * still be completed because the PREPARE phase succeeded (through the recover method). * * Returns: TRUE if no error occurred (there may be some connections to recover, though) */ gboolean gda_xa_transaction_commit (GdaXaTransaction *xa_trans, GSList **cnc_to_recover, GError **error) { GList *list; if (cnc_to_recover) *cnc_to_recover = NULL; g_return_val_if_fail (GDA_IS_XA_TRANSACTION (xa_trans), FALSE); GdaXaTransactionPrivate *priv = gda_xa_transaction_get_instance_private (xa_trans); /* * PREPARE phase */ for (list = priv->cnc_list; list; list = list->next) { GdaConnection *cnc = NULL; GdaServerProvider *prov; GdaBinary *branch; if (cnc == priv->non_xa_cnc) continue; cnc = GDA_CONNECTION (list->data); prov = gda_connection_get_provider (cnc); branch = g_hash_table_lookup (priv->cnc_hash, cnc); memcpy (priv->xid.data + priv->xid.gtrid_length, /* Flawfinder: ignore */ gda_binary_get_data (branch), gda_binary_get_size (branch)); if (!_gda_server_provider_xa_end (prov, cnc, &(priv->xid), error)) break; if (!_gda_server_provider_xa_prepare (prov, cnc, &(priv->xid), error)) break; } if (list) { /* something went wrong during the PREPARE phase => rollback everything */ for (; list; list = list->prev) { GdaConnection *cnc = NULL; GdaServerProvider *prov; if (cnc == priv->non_xa_cnc) gda_connection_rollback_transaction (cnc, NULL, NULL); else { GdaBinary *branch; cnc = GDA_CONNECTION (list->data); prov = gda_connection_get_provider (cnc); branch = g_hash_table_lookup (priv->cnc_hash, cnc); memcpy (priv->xid.data + priv->xid.gtrid_length, /* Flawfinder: ignore */ gda_binary_get_data (branch), gda_binary_get_size (branch)); _gda_server_provider_xa_rollback (prov, cnc, &(priv->xid), NULL); } } return FALSE; } /* * COMMIT phase */ if (priv->non_xa_cnc && ! gda_connection_commit_transaction (priv->non_xa_cnc, NULL, error)) { /* something went wrong => rollback everything */ for (list = priv->cnc_list; list; list = list->next) { GdaConnection *cnc = NULL; GdaServerProvider *prov; if (cnc == priv->non_xa_cnc) gda_connection_rollback_transaction (cnc, NULL, NULL); else { GdaBinary *branch; cnc = GDA_CONNECTION (list->data); prov = gda_connection_get_provider (cnc); branch = g_hash_table_lookup (priv->cnc_hash, cnc); memcpy (priv->xid.data + priv->xid.gtrid_length, /* Flawfinder: ignore */ gda_binary_get_data (branch), gda_binary_get_size (branch)); _gda_server_provider_xa_rollback (prov, cnc, &(priv->xid), NULL); } } return FALSE; } for (list = priv->cnc_list; list; list = list->next) { GdaConnection *cnc = NULL; GdaServerProvider *prov; GdaBinary *branch; if (cnc == priv->non_xa_cnc) continue; cnc = GDA_CONNECTION (list->data); prov = gda_connection_get_provider (cnc); branch = g_hash_table_lookup (priv->cnc_hash, cnc); memcpy (priv->xid.data + priv->xid.gtrid_length, /* Flawfinder: ignore */ gda_binary_get_data (branch), gda_binary_get_size (branch)); if (! _gda_server_provider_xa_commit (prov, cnc, &(priv->xid), error) && cnc_to_recover) *cnc_to_recover = g_slist_prepend (*cnc_to_recover, cnc); } return TRUE; }
int main (int argc, char **argv) { GError *error = NULL; GOptionContext *context; GdaConnection *cnc; gchar *auth_string = NULL; gchar *blob_data; /* command line parsing */ context = g_option_context_new ("Tests opening a connection"); g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_warning ("Can't parse arguments: %s", error->message); exit (1); } g_option_context_free (context); if (direct && dsn) { g_print ("DSN and connection string are exclusive\n"); exit (1); } if (!direct && !dsn) { g_print ("You must specify a connection to open either as a DSN or a connection string\n"); exit (1); } if (direct && !prov) { g_print ("You must specify a provider when using a connection string\n"); exit (1); } gda_init (); /* open connection */ if (user) { if (pass) auth_string = g_strdup_printf ("USERNAME=%s;PASSWORD=%s", user, pass); else auth_string = g_strdup_printf ("USERNAME=%s", user); } if (dsn) { GdaDsnInfo *info = NULL; info = gda_config_get_dsn_info (dsn); if (!info) g_error (_("DSN '%s' is not declared"), dsn); else { cnc = gda_connection_open_from_dsn (info->name, auth_string ? auth_string : info->auth_string, 0, &error); if (!cnc) { g_warning (_("Can't open connection to DSN %s: %s\n"), info->name, error && error->message ? error->message : "???"); exit (1); } prov = info->provider; } } else { cnc = gda_connection_open_from_string (prov, direct, auth_string, 0, &error); if (!cnc) { g_warning (_("Can't open specified connection: %s\n"), error && error->message ? error->message : "???"); exit (1); } } g_free (auth_string); g_print (_("Connection successfully opened!\n")); parser = gda_connection_create_parser (cnc); gda_connection_begin_transaction (cnc, NULL, GDA_TRANSACTION_ISOLATION_UNKNOWN, NULL); /* * clear all blobs */ if (!clear_blobs (cnc, &error)) g_error ("Blobs clear error: %s", error && error->message ? error->message : "No detail"); /* insert a blob */ blob_data = "Blob Data 1"; if (!insert_blob (cnc, 1, blob_data, strlen (blob_data), &error)) g_error ("Blob insert error: %s", error && error->message ? error->message : "No detail"); else if (error) { g_print ("Msg: %s\n", error->message); g_error_free (error); error = NULL; } /* insert a blob */ blob_data = "Blob Data 2"; if (!insert_blob (cnc, 2, blob_data, strlen (blob_data), &error)) g_error ("Blob insert error: %s", error && error->message ? error->message : "No detail"); else if (error) { g_print ("Msg: %s\n", error->message); g_error_free (error); error = NULL; } if (!display_blobs (cnc, &error)) g_error ("Blobs display error: %s", error && error->message ? error->message : "No detail"); /* update blob */ blob_data = "New blob 1 contents is now this one..."; if (!update_blob (cnc, 1, blob_data, strlen (blob_data), &error)) g_error ("Blob update error: %s", error && error->message ? error->message : "No detail"); else if (error) { g_print ("Msg: %s\n", error->message); g_error_free (error); error = NULL; } if (!display_blobs (cnc, &error)) g_error ("Blobs display error: %s", error && error->message ? error->message : "No detail"); /* update blob */ blob_data = "After several blobs updated"; if (!update_multiple_blobs (cnc, blob_data, strlen (blob_data), &error)) g_error ("Multiple blob update error: %s", error && error->message ? error->message : "No detail"); else if (error) { g_print ("Msg: %s\n", error->message); g_error_free (error); error = NULL; } if (!display_blobs (cnc, &error)) g_error ("Blobs display error: %s", error && error->message ? error->message : "No detail"); /* SQL Postgres: create table blobs (id serial not null primary key, name varchar (50), data oid); SQL Oracle: CREATE TABLE blobs (id number primary key, name varchar2 (50), data BLOB); */ gda_connection_commit_transaction (cnc, NULL, NULL); if (! gda_connection_close (cnc, &error)) g_error ("Can't close connection: %s", error && error->message ? error->message : "No detail"); return 0; }
/* * Load data from file @file into table @table */ gboolean test_cnc_load_data_from_file (GdaConnection *cnc, const gchar *table, const gchar *full_file, GError **error) { GdaStatement *stmt = NULL; GdaSet *params = NULL; GdaDataModel *import; gint nrows, ncols, i; GdaMetaStruct *mstruct = NULL; GSList *list; gboolean retval = TRUE; /* loading XML file */ import = gda_data_model_import_new_file (full_file, TRUE, NULL); if (gda_data_model_import_get_errors (GDA_DATA_MODEL_IMPORT (import))) { g_set_error (error, TEST_ERROR, TEST_ERROR_GENERIC, "Error loading '%s' file", full_file); return FALSE; } /* retrieving meta data info */ GdaMetaDbObject *table_dbo; GValue *name_value; g_value_set_string ((name_value = gda_value_new (G_TYPE_STRING)), table); mstruct = gda_meta_struct_new (gda_connection_get_meta_store (cnc), GDA_META_STRUCT_FEATURE_NONE); table_dbo = gda_meta_struct_complement (mstruct, GDA_META_DB_TABLE, NULL, NULL, name_value, error); gda_value_free (name_value); if (! table_dbo) { retval = FALSE; goto out; } /* creating INSERT statement */ GdaSqlStatement *st; GdaSqlStatementInsert *ist; GSList *insert_values_list = NULL; ist = g_new0 (GdaSqlStatementInsert, 1); GDA_SQL_ANY_PART (ist)->type = GDA_SQL_ANY_STMT_INSERT; ist->table = gda_sql_table_new (GDA_SQL_ANY_PART (ist)); ist->table->table_name = g_strdup (table); GdaMetaTable *mtable = GDA_META_TABLE (table_dbo); for (list = mtable->columns; list; list = list->next) { GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data); GdaSqlField *field; /* field */ field = gda_sql_field_new (GDA_SQL_ANY_PART (ist)); field->field_name = g_strdup (tcol->column_name); ist->fields_list = g_slist_append (ist->fields_list, field); /* value */ GdaSqlParamSpec *pspec = g_new0 (GdaSqlParamSpec, 1); GdaSqlExpr *expr; pspec->name = g_strdup (tcol->column_name); pspec->g_type = tcol->gtype; pspec->nullok = tcol->nullok; expr = gda_sql_expr_new (GDA_SQL_ANY_PART (ist)); expr->param_spec = pspec; insert_values_list = g_slist_append (insert_values_list, expr); } ist->values_list = g_slist_append (NULL, insert_values_list); st = gda_sql_statement_new (GDA_SQL_STATEMENT_INSERT); st->contents = ist; stmt = g_object_new (GDA_TYPE_STATEMENT, "structure", st, NULL); gda_sql_statement_free (st); g_object_unref (mstruct); if (! gda_statement_get_parameters (stmt, ¶ms, error)) { retval = FALSE; goto out; } /* executing inserts */ nrows = gda_data_model_get_n_rows (import); ncols = gda_data_model_get_n_columns (import); if (!gda_connection_begin_transaction (cnc, NULL, GDA_TRANSACTION_ISOLATION_UNKNOWN, error)) { retval = FALSE; goto out; } for (i = 0; i < nrows; i++) { gint j; GSList *list; for (list = params->holders, j = 0; list && (j < ncols); list = list->next, j++) { const GValue *cvalue = gda_data_model_get_value_at (import, j, i, error); if (!cvalue) { gda_connection_rollback_transaction (cnc, NULL, NULL); retval = FALSE; goto out; } if (! gda_holder_set_value (GDA_HOLDER (list->data), cvalue, error)) { gda_connection_rollback_transaction (cnc, NULL, NULL); retval = FALSE; goto out; } } if (list || (j < ncols)) { g_set_error (error, TEST_ERROR, TEST_ERROR_GENERIC, "%s", "Incoherent number of columns in table and imported data"); gda_connection_rollback_transaction (cnc, NULL, NULL); retval = FALSE; goto out; } if (gda_connection_statement_execute_non_select (cnc, stmt, params, NULL, error) == -1) { gda_connection_rollback_transaction (cnc, NULL, NULL); retval = FALSE; goto out; } } if (! gda_connection_commit_transaction (cnc, NULL, error)) retval = FALSE; out: if (import) g_object_unref (import); if (stmt) g_object_unref (stmt); if (params) g_object_unref (params); return retval; }