/** * gda_xa_transaction_begin: * @xa_trans: a #GdaXaTransaction object * @error: (nullable): a place to store errors, or %NULL * * Begins a distributed transaction (managed by @xa_trans). Please note that this phase may fail * for some connections if a (normal) transaction is already started (this depends on the database * provider being used), so it's better to avoid starting any (normal) transaction on any of the * connections registered with @xa_trans. * * Returns: TRUE if no error occurred */ gboolean gda_xa_transaction_begin (GdaXaTransaction *xa_trans, GError **error) { GList *list; g_return_val_if_fail (GDA_IS_XA_TRANSACTION (xa_trans), FALSE); GdaXaTransactionPrivate *priv = gda_xa_transaction_get_instance_private (xa_trans); for (list = priv->cnc_list; list; list = list->next) { GdaConnection *cnc; GdaServerProvider *prov; cnc = GDA_CONNECTION (list->data); prov = gda_connection_get_provider (cnc); if (cnc != priv->non_xa_cnc) { GdaBinary *branch; 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_start (prov, cnc, &(priv->xid), error)) break; } else { /* do a simple BEGIN */ if (! gda_connection_begin_transaction (cnc, NULL, GDA_TRANSACTION_ISOLATION_UNKNOWN, error)) break; } } if (list) { /* something went wrong */ for (; list; list = list->prev) { GdaConnection *cnc; GdaServerProvider *prov; cnc = GDA_CONNECTION (list->data); prov = gda_connection_get_provider (cnc); if (cnc != priv->non_xa_cnc) { GdaBinary *branch; 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); } else { /* do a simple ROLLBACK */ gda_connection_rollback_transaction (cnc, NULL, NULL); } } return FALSE; } return TRUE; }
/** * gda_xa_transaction_rollback: * @xa_trans: a #GdaXaTransaction object * @error: (allow-none): a place to store errors, or %NULL * * Cancels a distributed transaction (managed by @xa_trans). * * Returns: %TRUE if no error occurred */ gboolean gda_xa_transaction_rollback (GdaXaTransaction *xa_trans, GError **error) { GList *list; g_return_val_if_fail (GDA_IS_XA_TRANSACTION (xa_trans), FALSE); for (list = xa_trans->priv->cnc_list; list; list = list->next) { GdaConnection *cnc; GdaServerProvider *prov; cnc = GDA_CONNECTION (list->data); prov = gda_connection_get_provider (cnc); if (cnc == xa_trans->priv->non_xa_cnc) gda_connection_rollback_transaction (cnc, NULL, NULL); else { const GdaBinary *branch; 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) g_warning (_("Provider error: %s method not implemented for provider %s"), "xa_prepare()", gda_server_provider_get_name (prov)); else PROV_CLASS (prov)->xa_funcs->xa_rollback (prov, cnc, &(xa_trans->priv->xid), error); } } return TRUE; }
/** * gda_xa_transaction_rollback: * @xa_trans: a #GdaXaTransaction object * @error: (nullable): a place to store errors, or %NULL * * Cancels a distributed transaction (managed by @xa_trans). * * Returns: %TRUE if no error occurred */ gboolean gda_xa_transaction_rollback (GdaXaTransaction *xa_trans, GError **error) { GList *list; g_return_val_if_fail (GDA_IS_XA_TRANSACTION (xa_trans), FALSE); GdaXaTransactionPrivate *priv = gda_xa_transaction_get_instance_private (xa_trans); for (list = priv->cnc_list; list; list = list->next) { GdaConnection *cnc; GdaServerProvider *prov; cnc = GDA_CONNECTION (list->data); prov = gda_connection_get_provider (cnc); if (cnc == priv->non_xa_cnc) gda_connection_rollback_transaction (cnc, NULL, NULL); else { GdaBinary *branch; 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)); GError *lerror = NULL; _gda_server_provider_xa_rollback (prov, cnc, &(priv->xid), &lerror); if (error && !*error) g_propagate_error (error, lerror); else g_clear_error (&lerror); } } return TRUE; }
/** * gda_xa_transaction_register_connection: * @xa_trans: a #GdaXaTransaction object * @cnc: the connection to add to @xa_trans * @branch: the branch qualifier * @error: (allow-none): a place to store errors, or %NULL * * Registers @cnc to be used by @xa_trans to create a distributed transaction. * * Note: any #GdaConnection object can only be registered with at most one #GdaXaTransaction object; also * some connections may not be registered at all with a #GdaXaTransaction object because the database * provider being used does not support it. * * Returns: %TRUE if no error occurred */ gboolean gda_xa_transaction_register_connection (GdaXaTransaction *xa_trans, GdaConnection *cnc, const gchar *branch, GError **error) { GdaBinary *bin; g_return_val_if_fail (GDA_IS_XA_TRANSACTION (xa_trans), FALSE); g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); g_return_val_if_fail (branch && *branch, FALSE); if (strlen (branch) >= 64) { g_set_error (error, GDA_XA_TRANSACTION_ERROR, GDA_XA_TRANSACTION_CONNECTION_BRANCH_LENGTH_ERROR, "%s", _("Connection branch cannot exceed 63 bytes")); return FALSE; } const GdaBinary *ebranch = g_hash_table_lookup (xa_trans->priv->cnc_hash, cnc); if (ebranch) { bin = g_new0 (GdaBinary, 1); bin->data = (guchar*) g_strdup (branch); bin->binary_length = strlen (branch) + 1; g_hash_table_insert (xa_trans->priv->cnc_hash, cnc, bin); return TRUE; } /* check that @cnc is not already registered with another GdaXaTransaction object */ if (g_object_get_data (G_OBJECT (cnc), "_gda_xa_transaction")) { g_set_error (error, GDA_XA_TRANSACTION_ERROR, GDA_XA_TRANSACTION_ALREADY_REGISTERED_ERROR, "%s", _("Connection already registered with another GdaXaTransaction object")); return FALSE; } /* check that connection supports distributed transaction, only ONE connection in @xa_trans is allowed * to not support them */ GdaServerProvider *prov; prov = gda_connection_get_provider (cnc); if (!gda_server_provider_supports_feature (prov, cnc, GDA_CONNECTION_FEATURE_XA_TRANSACTIONS)) { /* if another connection does not support distributed transaction, then there is an error */ if (xa_trans->priv->non_xa_cnc) { g_set_error (error, GDA_XA_TRANSACTION_ERROR, GDA_XA_TRANSACTION_DTP_NOT_SUPPORTED_ERROR, "%s", _("Connection does not support distributed transaction")); return FALSE; } else xa_trans->priv->non_xa_cnc = cnc; } bin = g_new0 (GdaBinary, 1); bin->data = (guchar*) g_strdup (branch); bin->binary_length = strlen (branch) + 1; xa_trans->priv->cnc_list = g_list_prepend (xa_trans->priv->cnc_list, cnc); g_hash_table_insert (xa_trans->priv->cnc_hash, cnc, bin); g_object_ref (cnc); g_object_set_data (G_OBJECT (cnc), "_gda_xa_transaction", xa_trans); return TRUE; }
/* * Server version request */ static const gchar * gda_ldap_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc) { LdapConnectionData *cdata; g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL); cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data (GDA_VIRTUAL_CONNECTION (cnc)); if (!cdata) return FALSE; if (! cdata->server_version) { /* FIXME: don't know how to get information about the LDAP server! */ } return cdata->server_version; }
gchar * gda_postgres_render_DROP_USER (GdaServerProvider *provider, GdaConnection *cnc, GdaServerOperation *op, G_GNUC_UNUSED GError **error) { GString *string; const GValue *value; gchar *sql = NULL; gchar *tmp; gboolean use_role = TRUE; PostgresConnectionData *cdata = NULL; if (cnc) { g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error); } if (cdata && (cdata->reuseable->version_float < 8.1)) use_role = FALSE; if (use_role) string = g_string_new ("DROP ROLE "); else string = g_string_new ("DROP USER "); value = gda_server_operation_get_value_at (op, "/USER_DESC_P/USER_IFEXISTS"); if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) g_string_append (string, " IF EXISTS"); tmp = gda_server_operation_get_sql_identifier_at (op, cnc, provider, "/USER_DESC_P/USER_NAME", error); if (!tmp) { g_string_free (string, TRUE); return NULL; } g_string_append_c (string, ' '); g_string_append (string, tmp); g_free (tmp); sql = string->str; g_string_free (string, FALSE); return sql; }
/* * Close connection request * * In this function, the following _must_ be done: * - Actually close the connection to the database using @cnc's associated LdapConnectionData structure * - Free the LdapConnectionData structure and its contents * * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR connection event must be added to @cnc) */ static gboolean gda_ldap_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc) { LdapConnectionData *cdata; g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); /* Close the connection using the C API */ cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data (GDA_VIRTUAL_CONNECTION (cnc)); if (!cdata) return FALSE; if (cdata->handle) { ldap_unbind_ext (cdata->handle, NULL, NULL); cdata->handle = NULL; } GdaServerProviderBase *fset; fset = gda_server_provider_get_impl_functions_for_class (parent_class, GDA_SERVER_PROVIDER_FUNCTIONS_BASE); return fset->close_connection (provider, cnc); }
/** * gda_xa_transaction_commit_recovered: * @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 there were data to recover and which failed to be actually committed, or %NULL * @error: (allow-none): a place to store errors, or %NULL * * Tries to commit the data prepared but which failed to commit (see gda_xa_transaction_commit()). This * method allows one to terminate a distributed transaction which succeeded but for which some * connections needed to be recovered. * * Returns: %TRUE if all the data which was still uncommitted has been committed */ gboolean gda_xa_transaction_commit_recovered (GdaXaTransaction *xa_trans, GSList **cnc_to_recover, GError **error) { GList *list; gboolean retval = TRUE; if (cnc_to_recover) *cnc_to_recover = NULL; g_return_val_if_fail (GDA_IS_XA_TRANSACTION (xa_trans), FALSE); for (list = xa_trans->priv->cnc_list; list; list = list->next) { GdaConnection *cnc; GdaServerProvider *prov; cnc = GDA_CONNECTION (list->data); prov = gda_connection_get_provider (cnc); if (cnc == xa_trans->priv->non_xa_cnc) continue; else { GList *recov_xid_list; if (!PROV_CLASS (prov)->xa_funcs->xa_recover) g_warning (_("Provider error: %s method not implemented for provider %s"), "xa_recover()", gda_server_provider_get_name (prov)); else { const GdaBinary *branch; GList *xlist; gboolean commit_needed = FALSE; recov_xid_list = PROV_CLASS (prov)->xa_funcs->xa_recover (prov, cnc, error); if (!recov_xid_list) continue; 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); for (xlist = recov_xid_list; xlist; xlist = xlist->next) { GdaXaTransactionId *xid = (GdaXaTransactionId*) xlist->data; if (!xid) /* ignore unknown XID format */ continue; if (!commit_needed && (xid->format == xa_trans->priv->xid.format) && (xid->gtrid_length == xa_trans->priv->xid.gtrid_length) && (xid->bqual_length == xa_trans->priv->xid.bqual_length) && ! memcmp (xa_trans->priv->xid.data, xid->data, xid->bqual_length + xid->bqual_length)) /* found a transaction to commit */ commit_needed = TRUE; g_free (xid); } g_list_free (recov_xid_list); if (commit_needed) { 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)); retval = FALSE; } else { retval = PROV_CLASS (prov)->xa_funcs->xa_commit (prov, cnc, &(xa_trans->priv->xid), error); if (!retval) if (cnc_to_recover) *cnc_to_recover = g_slist_prepend (*cnc_to_recover, cnc); } } } } } return retval; }
/** * 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_begin: * @xa_trans: a #GdaXaTransaction object * @error: (allow-none): a place to store errors, or %NULL * * Begins a distributed transaction (managed by @xa_trans). Please note that this phase may fail * for some connections if a (normal) transaction is already started (this depends on the database * provider being used), so it's better to avoid starting any (normal) transaction on any of the * connections registered with @xa_trans. * * Returns: TRUE if no error occurred */ gboolean gda_xa_transaction_begin (GdaXaTransaction *xa_trans, GError **error) { GList *list; g_return_val_if_fail (GDA_IS_XA_TRANSACTION (xa_trans), FALSE); for (list = xa_trans->priv->cnc_list; list; list = list->next) { GdaConnection *cnc; GdaServerProvider *prov; cnc = GDA_CONNECTION (list->data); prov = gda_connection_get_provider (cnc); if (cnc != xa_trans->priv->non_xa_cnc) { if (!PROV_CLASS (prov)->xa_funcs->xa_start) { g_warning (_("Provider error: %s method not implemented for provider %s"), "xa_start()", gda_server_provider_get_name (prov)); break; } else { const GdaBinary *branch; 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_start (prov, cnc, &(xa_trans->priv->xid), error)) break; } } else { /* do a simple BEGIN */ if (! gda_connection_begin_transaction (cnc, NULL, GDA_TRANSACTION_ISOLATION_UNKNOWN, error)) break; } } if (list) { /* something went wrong */ for (; list; list = list->prev) { GdaConnection *cnc; GdaServerProvider *prov; cnc = GDA_CONNECTION (list->data); prov = gda_connection_get_provider (cnc); if (cnc != xa_trans->priv->non_xa_cnc) { if (!PROV_CLASS (prov)->xa_funcs->xa_rollback) g_warning (_("Provider error: %s method not implemented for provider %s"), "xa_rollback()", gda_server_provider_get_name (prov)); else { const GdaBinary *branch; 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); PROV_CLASS (prov)->xa_funcs->xa_rollback (prov, cnc, &(xa_trans->priv->xid), NULL); } } else { /* do a simple ROLLBACK */ gda_connection_rollback_transaction (cnc, NULL, NULL); } } return FALSE; } return TRUE; }
/** * gda_xa_transaction_commit_recovered: * @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 there were data to recover and which failed to be actually committed, or %NULL * @error: (nullable): a place to store errors, or %NULL * * Tries to commit the data prepared but which failed to commit (see gda_xa_transaction_commit()). This * method allows one to terminate a distributed transaction which succeeded but for which some * connections needed to be recovered. * * Returns: %TRUE if all the data which was still uncommitted has been committed */ gboolean gda_xa_transaction_commit_recovered (GdaXaTransaction *xa_trans, GSList **cnc_to_recover, GError **error) { GList *list; gboolean retval = TRUE; 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); for (list = priv->cnc_list; list; list = list->next) { GdaConnection *cnc; GdaServerProvider *prov; cnc = GDA_CONNECTION (list->data); prov = gda_connection_get_provider (cnc); if (cnc == priv->non_xa_cnc) continue; else { GList *recov_xid_list; GdaBinary *branch; GList *xlist; gboolean commit_needed = FALSE; recov_xid_list = _gda_server_provider_xa_recover (prov, cnc, error); if (!recov_xid_list) continue; 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)); for (xlist = recov_xid_list; xlist; xlist = xlist->next) { GdaXaTransactionId *xid = (GdaXaTransactionId*) xlist->data; if (!xid) /* ignore unknown XID format */ continue; if (!commit_needed && (xid->format == priv->xid.format) && (xid->gtrid_length == priv->xid.gtrid_length) && (xid->bqual_length == priv->xid.bqual_length) && ! memcmp (priv->xid.data, xid->data, xid->bqual_length + xid->bqual_length)) /* found a transaction to commit */ commit_needed = TRUE; g_free (xid); } g_list_free (recov_xid_list); if (commit_needed) { retval = _gda_server_provider_xa_commit (prov, cnc, &(priv->xid), error); if (!retval) if (cnc_to_recover) *cnc_to_recover = g_slist_prepend (*cnc_to_recover, cnc); } } } return retval; }
static gboolean report_provider_status (GdaServerProvider *prov, GdaConnection *cnc) { gchar *header_str; HtmlFile *file = config->index; gboolean is_virt; typedef void (*AFunc) (void); typedef struct { const gchar *name; gboolean should_be; void (*func) (void); } ProvFunc; GdaServerProviderClass *pclass; if (prov && cnc && (prov != gda_connection_get_provider (cnc))) /* ignoring connection as it has a different provider */ return TRUE; g_assert (prov || cnc); /* section */ if (cnc) header_str = g_strdup_printf ("Report for connection '%s'", gda_connection_get_cnc_string (cnc)); else header_str = g_strdup_printf ("Report for '%s' provider", gda_server_provider_get_name (prov)); /* provider info */ if (!prov) prov = gda_connection_get_provider (cnc); is_virt = GDA_IS_VIRTUAL_PROVIDER (prov); pclass = (GdaServerProviderClass*) G_OBJECT_GET_CLASS (prov); ProvFunc fa[] = { {"get_name", TRUE, (AFunc) pclass->get_name}, {"get_version", TRUE, (AFunc) pclass->get_version}, {"get_server_version", TRUE, (AFunc) pclass->get_server_version}, {"supports_feature", TRUE, (AFunc) pclass->supports_feature}, {"get_data_handler", TRUE, (AFunc) pclass->get_data_handler}, {"get_def_dbms_type", TRUE, (AFunc) pclass->get_def_dbms_type}, {"escape_string", TRUE, (AFunc) pclass->escape_string}, {"unescape_string", TRUE, (AFunc) pclass->unescape_string}, {"open_connection", TRUE, (AFunc) pclass->open_connection}, {"close_connection", TRUE, (AFunc) pclass->close_connection}, {"supports_operation", is_virt ? FALSE : TRUE, (AFunc) pclass->supports_operation}, {"create_operation", FALSE, (AFunc) pclass->create_operation}, {"render_operation", FALSE, (AFunc) pclass->render_operation}, {"perform_operation", FALSE, (AFunc) pclass->perform_operation}, {"begin_transaction", FALSE, (AFunc) pclass->begin_transaction}, {"commit_transaction", FALSE, (AFunc) pclass->commit_transaction}, {"rollback_transaction", FALSE, (AFunc) pclass->rollback_transaction}, {"add_savepoint", FALSE, (AFunc) pclass->add_savepoint}, {"rollback_savepoint", FALSE, (AFunc) pclass->rollback_savepoint}, {"delete_savepoint", FALSE, (AFunc) pclass->delete_savepoint}, {"create_parser", FALSE, (AFunc) pclass->create_parser}, {"statement_to_sql", TRUE, (AFunc) pclass->statement_to_sql}, {"statement_prepare", TRUE, (AFunc) pclass->statement_prepare}, {"statement_execute", TRUE, (AFunc) pclass->statement_execute}, {"identifier_quote", TRUE, (AFunc) pclass->identifier_quote} }; ProvFunc md[] = { {"_info", TRUE, (AFunc) pclass->meta_funcs._info}, {"_btypes", TRUE, (AFunc) pclass->meta_funcs._btypes}, {"_udt", TRUE, (AFunc) pclass->meta_funcs._udt}, {"udt", TRUE, (AFunc) pclass->meta_funcs.udt}, {"_udt_cols", TRUE, (AFunc) pclass->meta_funcs._udt_cols}, {"udt_cols", TRUE, (AFunc) pclass->meta_funcs.udt_cols}, {"_enums", TRUE, (AFunc) pclass->meta_funcs._enums}, {"enums", TRUE, (AFunc) pclass->meta_funcs.enums}, {"_domains", TRUE, (AFunc) pclass->meta_funcs._domains}, {"domains", TRUE, (AFunc) pclass->meta_funcs.domains}, {"_constraints_dom", TRUE, (AFunc) pclass->meta_funcs._constraints_dom}, {"constraints_dom", TRUE, (AFunc) pclass->meta_funcs.constraints_dom}, {"_el_types", TRUE, (AFunc) pclass->meta_funcs._el_types}, {"el_types", TRUE, (AFunc) pclass->meta_funcs.el_types}, {"_collations", TRUE, (AFunc) pclass->meta_funcs._collations}, {"collations", TRUE, (AFunc) pclass->meta_funcs.collations}, {"_character_sets", TRUE, (AFunc) pclass->meta_funcs._character_sets}, {"character_sets", TRUE, (AFunc) pclass->meta_funcs.character_sets}, {"_schemata", TRUE, (AFunc) pclass->meta_funcs._schemata}, {"schemata", TRUE, (AFunc) pclass->meta_funcs.schemata}, {"_tables_views", TRUE, (AFunc) pclass->meta_funcs._tables_views}, {"tables_views", TRUE, (AFunc) pclass->meta_funcs.tables_views}, {"_columns", TRUE, (AFunc) pclass->meta_funcs._columns}, {"columns", TRUE, (AFunc) pclass->meta_funcs.columns}, {"_view_cols", TRUE, (AFunc) pclass->meta_funcs._view_cols}, {"view_cols", TRUE, (AFunc) pclass->meta_funcs.view_cols}, {"_constraints_tab", TRUE, (AFunc) pclass->meta_funcs._constraints_tab}, {"constraints_tab", TRUE, (AFunc) pclass->meta_funcs.constraints_tab}, {"_constraints_ref", TRUE, (AFunc) pclass->meta_funcs._constraints_ref}, {"constraints_ref", TRUE, (AFunc) pclass->meta_funcs.constraints_ref}, {"_key_columns", TRUE, (AFunc) pclass->meta_funcs._key_columns}, {"key_columns", TRUE, (AFunc) pclass->meta_funcs.key_columns}, {"_check_columns", TRUE, (AFunc) pclass->meta_funcs._check_columns}, {"check_columns", TRUE, (AFunc) pclass->meta_funcs.check_columns}, {"_triggers", TRUE, (AFunc) pclass->meta_funcs._triggers}, {"triggers", TRUE, (AFunc) pclass->meta_funcs.triggers}, {"_routines", TRUE, (AFunc) pclass->meta_funcs._routines}, {"routines", TRUE, (AFunc) pclass->meta_funcs.routines}, {"_routine_col", TRUE, (AFunc) pclass->meta_funcs._routine_col}, {"routine_col", TRUE, (AFunc) pclass->meta_funcs.routine_col}, {"_routine_par", TRUE, (AFunc) pclass->meta_funcs._routine_par}, {"routine_par", TRUE, (AFunc) pclass->meta_funcs.routine_par}, }; gboolean has_xa = gda_server_provider_supports_feature (prov, cnc, GDA_CONNECTION_FEATURE_XA_TRANSACTIONS); xmlNodePtr table, tr, td, span; GdaSqlParser *parser; GString *string; gsize i; GdaProviderInfo *pinfo; pinfo = gda_config_get_provider_info (gda_server_provider_get_name (prov)); g_assert (pinfo); table = xmlNewChild (file->body, NULL, BAD_CAST "table", NULL); xmlSetProp (table, BAD_CAST "width", BAD_CAST "100%"); tr = xmlNewChild (table, NULL, BAD_CAST "tr", NULL); td = xmlNewTextChild (tr, NULL, BAD_CAST "th", BAD_CAST header_str); xmlSetProp (td, BAD_CAST "colspan", BAD_CAST "4"); /* line 1 */ tr = xmlNewChild (table, NULL, BAD_CAST "tr", NULL); xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST "Provider's name:"); td = xmlNewTextChild (tr, NULL, BAD_CAST "td", BAD_CAST gda_server_provider_get_name (prov)); xmlSetProp (td, BAD_CAST "width", (xmlChar*) "35%"); xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST "Provider is virtual:"); td = xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST (is_virt ? "Yes (uses the SQLite engine)" : "No")); xmlSetProp (td, BAD_CAST "width", (xmlChar*) "35%"); /* line 2 */ tr = xmlNewChild (table, NULL, BAD_CAST "tr", NULL); xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST "Provider's version:"); xmlNewTextChild (tr, NULL, BAD_CAST "td", BAD_CAST gda_server_provider_get_version (prov)); xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST "Provider's server version:"); xmlNewTextChild (tr, NULL, BAD_CAST "td", BAD_CAST (cnc ? gda_server_provider_get_server_version (prov, cnc) : "(non connected)")); /* line 3 */ tr = xmlNewChild (table, NULL, BAD_CAST "tr", NULL); xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST "Provider's description:"); xmlNewTextChild (tr, NULL, BAD_CAST "td", BAD_CAST pinfo->description); xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST "Filename:"); xmlNewTextChild (tr, NULL, BAD_CAST "td", BAD_CAST pinfo->location); /* line 4 */ parser = gda_server_provider_create_parser (prov, cnc); tr = xmlNewChild (table, NULL, BAD_CAST "tr", NULL); xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST "Creates its own SQL parser:"); xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST (parser ? "Yes" : "No")); if (parser) g_object_unref (parser); xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST "Non implemented base methods:"); span = NULL; td = xmlNewChild (tr, NULL, BAD_CAST "td", NULL); for (i = 0; i < sizeof (fa) / sizeof (ProvFunc); i++) { gchar *str; ProvFunc *pf = &(fa[i]); if (pf->func) continue; if (span) str = g_strdup_printf (", %s()", pf->name); else str = g_strdup_printf ("%s()", pf->name); span = xmlNewTextChild (td, NULL, BAD_CAST "span", BAD_CAST str); g_free (str); if (pf->should_be) xmlSetProp (span, BAD_CAST "class", BAD_CAST "error"); } if (!span) xmlNodeSetContent (td, BAD_CAST "---"); /* line 5 */ tr = xmlNewChild (table, NULL, BAD_CAST "tr", NULL); xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST "Non implemented meta data methods:"); span = NULL; td = xmlNewChild (tr, NULL, BAD_CAST "td", NULL); for (i = 0; i < sizeof (md) / sizeof (ProvFunc); i++) { gchar *str; ProvFunc *pf = &(md[i]); if (pf->func) continue; if (span) str = g_strdup_printf (", %s()", pf->name); else str = g_strdup_printf ("%s()", pf->name); span = xmlNewTextChild (td, NULL, BAD_CAST "span", BAD_CAST str); g_free (str); if (pf->should_be) xmlSetProp (span, BAD_CAST "class", BAD_CAST "error"); } if (!span) xmlNodeSetContent (td, BAD_CAST "---"); xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST "Non implemented XA transactions:"); if (pclass->xa_funcs) { if (!has_xa) { td = xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST "The provider has the 'xa_funcs' part but " "reports that distributed transactions are " "not supported."); xmlSetProp (td, BAD_CAST "class", BAD_CAST "warning"); } else { ProvFunc dt[] = { {"xa_start", TRUE, (AFunc) pclass->xa_funcs->xa_start}, {"xa_end", FALSE, (AFunc) pclass->xa_funcs->xa_end}, {"xa_prepare", TRUE, (AFunc) pclass->xa_funcs->xa_prepare}, {"xa_commit", TRUE, (AFunc) pclass->xa_funcs->xa_commit}, {"xa_rollback", TRUE, (AFunc) pclass->xa_funcs->xa_rollback}, {"xa_recover", TRUE, (AFunc) pclass->xa_funcs->xa_recover}, }; span = NULL; td = xmlNewChild (tr, NULL, BAD_CAST "td", NULL); for (i = 0; i < sizeof (dt) / sizeof (ProvFunc); i++) { gchar *str; ProvFunc *pf = &(dt[i]); if (pf->func) continue; if (span) str = g_strdup_printf (", %s()", pf->name); else str = g_strdup_printf ("%s()", pf->name); span = xmlNewTextChild (td, NULL, BAD_CAST "span", BAD_CAST str); g_free (str); if (pf->should_be) xmlSetProp (span, BAD_CAST "class", BAD_CAST "error"); } if (!span) xmlNodeSetContent (td, BAD_CAST "---"); } } else { if (has_xa) { td = xmlNewTextChild (tr, NULL, BAD_CAST "td", BAD_CAST "The provider does not have the 'xa_funcs' part but " "reports that distributed transactions are " "supported."); xmlSetProp (td, BAD_CAST "class", BAD_CAST "warning"); } else xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST "---"); } /* line 6 */ tr = xmlNewChild (table, NULL, BAD_CAST "tr", NULL); xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST "Connection's parameters:"); if (pinfo->dsn_params && pinfo->dsn_params->holders) { GSList *list; td = xmlNewChild (tr, NULL, BAD_CAST "td", NULL); for (list = pinfo->dsn_params->holders; list; list = list->next) { gchar *str, *descr; GdaHolder *holder = GDA_HOLDER (list->data); g_object_get (G_OBJECT (holder), "description", &descr, NULL); if (descr) str = g_strdup_printf ("%s: %s", gda_holder_get_id (holder), descr); else str = g_strdup (gda_holder_get_id (holder)); g_free (descr); xmlNewTextChild (td, NULL, BAD_CAST "div", BAD_CAST str); g_free (str); } } else { td = xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST "None provided"); xmlSetProp (td, BAD_CAST "class", BAD_CAST "error"); } xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST "Authentication's parameters:"); if (pinfo->auth_params) { GSList *list; if (pinfo->auth_params->holders) { td = xmlNewChild (tr, NULL, BAD_CAST "td", NULL); for (list = pinfo->auth_params->holders; list; list = list->next) { gchar *str, *descr; GdaHolder *holder = GDA_HOLDER (list->data); g_object_get (G_OBJECT (holder), "description", &descr, NULL); if (descr) str = g_strdup_printf ("%s: %s", gda_holder_get_id (holder), descr); else str = g_strdup (gda_holder_get_id (holder)); g_free (descr); xmlNewTextChild (td, NULL, BAD_CAST "div", BAD_CAST str); g_free (str); } } else td = xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST "None required"); } else { td = xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST "None provided"); xmlSetProp (td, BAD_CAST "class", BAD_CAST "error"); } /* line 7 */ GdaConnectionFeature f; string = NULL; tr = xmlNewChild (table, NULL, BAD_CAST "tr", NULL); xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST "Supported features:"); for (f = 0; f < GDA_CONNECTION_FEATURE_LAST; f++) { if (gda_server_provider_supports_feature (prov, cnc, f)) { GEnumValue *ev; ev = g_enum_get_value ((GEnumClass *) g_type_class_ref (GDA_TYPE_CONNECTION_FEATURE), f); if (!string) string = g_string_new (ev->value_name); else g_string_append_printf (string, ", %s", ev->value_name); } } if (string) { xmlNewTextChild (tr, NULL, BAD_CAST "td", BAD_CAST string->str); g_string_free (string, TRUE); } else xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST "---"); string = NULL; xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST "Unsupported features:"); for (f = 0; f < GDA_CONNECTION_FEATURE_LAST; f++) { if (!gda_server_provider_supports_feature (prov, cnc, f)) { GEnumValue *ev; ev = g_enum_get_value ((GEnumClass *) g_type_class_ref (GDA_TYPE_CONNECTION_FEATURE), f); if (!string) string = g_string_new (ev->value_name); else g_string_append_printf (string, ", %s", ev->value_name); } } if (string) { xmlNewTextChild (tr, NULL, BAD_CAST "td", BAD_CAST string->str); g_string_free (string, TRUE); } else xmlNewChild (tr, NULL, BAD_CAST "td", BAD_CAST "---"); g_free (header_str); return TRUE; }
gchar * gda_postgres_render_CREATE_USER (GdaServerProvider *provider, GdaConnection *cnc, GdaServerOperation *op, G_GNUC_UNUSED GError **error) { GString *string; const GValue *value; gchar *sql = NULL; gchar *tmp; gboolean with = FALSE, first, use_role = TRUE; gint nrows, i; PostgresConnectionData *cdata = NULL; if (cnc) { g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE); g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE); cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error); } if (cdata && (cdata->reuseable->version_float < 8.1)) use_role = FALSE; if (use_role) string = g_string_new ("CREATE ROLE "); else string = g_string_new ("CREATE USER "); tmp = gda_server_operation_get_sql_identifier_at (op, cnc, provider, "/USER_DEF_P/USER_NAME", error); if (!tmp) { g_string_free (string, TRUE); return NULL; } g_string_append (string, tmp); g_free (tmp); value = gda_server_operation_get_value_at (op, "/USER_DEF_P/PASSWORD"); if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value) && (*g_value_get_string (value))) { GdaDataHandler *dh; const GValue *value2; g_string_append (string, " WITH"); with = TRUE; value2 = gda_server_operation_get_value_at (op, "/USER_DEF_P/PASSWORD_ENCRYPTED"); if (value2 && G_VALUE_HOLDS (value2, G_TYPE_BOOLEAN) && g_value_get_boolean (value2)) g_string_append (string, " ENCRYPTED"); g_string_append (string, " PASSWORD "); dh = gda_server_provider_get_data_handler_g_type (provider, cnc, G_TYPE_STRING); if (!dh) dh = gda_data_handler_get_default (G_TYPE_STRING); tmp = gda_data_handler_get_sql_from_value (dh, value); g_string_append (string, tmp); g_free (tmp); } value = gda_server_operation_get_value_at (op, "/USER_DEF_P/UID"); if (value && G_VALUE_HOLDS (value, G_TYPE_UINT)) { if (!with) { g_string_append (string, " WITH"); with = TRUE; } g_string_append_printf (string, "SYSID %u", g_value_get_uint (value)); } value = gda_server_operation_get_value_at (op, "/USER_DEF_P/CAP_SUPERUSER"); if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) { if (!with) { g_string_append (string, " WITH"); with = TRUE; } g_string_append (string, " SUPERUSER"); } value = gda_server_operation_get_value_at (op, "/USER_DEF_P/CAP_CREATEDB"); if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) { if (!with) { g_string_append (string, " WITH"); with = TRUE; } g_string_append (string, " CREATEDB"); } value = gda_server_operation_get_value_at (op, "/USER_DEF_P/CAP_CREATEROLE"); if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) { if (!with) { g_string_append (string, " WITH"); with = TRUE; } g_string_append (string, " CREATEROLE"); } value = gda_server_operation_get_value_at (op, "/USER_DEF_P/CAP_CREATEUSER"); if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) { if (!with) { g_string_append (string, " WITH"); with = TRUE; } g_string_append (string, " CREATEUSER"); } value = gda_server_operation_get_value_at (op, "/USER_DEF_P/CAP_INHERIT"); if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) { if (!with) { g_string_append (string, " WITH"); with = TRUE; } g_string_append (string, " INHERIT"); } else { if (!with) { g_string_append (string, " WITH"); with = TRUE; } g_string_append (string, " NOINHERIT"); } value = gda_server_operation_get_value_at (op, "/USER_DEF_P/CAP_LOGIN"); if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) { g_string_append (string, " LOGIN"); value = gda_server_operation_get_value_at (op, "/USER_DEF_P/CNX_LIMIT"); if (value && G_VALUE_HOLDS (value, G_TYPE_INT)) g_string_append_printf (string, " CONNECTION LIMIT %d", g_value_get_int (value)); } nrows = gda_server_operation_get_sequence_size (op, "/GROUPS_S"); for (first = TRUE, i = 0; i < nrows; i++) { gchar *name; if (use_role) name = gda_server_operation_get_sql_identifier_at (op, cnc, provider, "/GROUPS_S/%d/ROLE", error, i); else name = gda_server_operation_get_sql_identifier_at (op, cnc, provider, "/GROUPS_S/%d/USER", error, i); if (name) { if (first) { first = FALSE; if (use_role) g_string_append (string, " IN ROLE "); else g_string_append (string, " IN GROUP "); } else g_string_append (string, ", "); g_string_append (string, name); g_free (name); } else { g_string_free (string, TRUE); return NULL; } } nrows = gda_server_operation_get_sequence_size (op, "/ROLES_S"); for (first = TRUE, i = 0; i < nrows; i++) { gchar *name; name = gda_server_operation_get_sql_identifier_at (op, cnc, provider, "/ROLES_S/%d/ROLE", error, i); if (name) { if (first) { first = FALSE; g_string_append (string, " ROLE "); } else g_string_append (string, ", "); g_string_append (string, name); g_free (name); } else { g_string_free (string, TRUE); return NULL; } } nrows = gda_server_operation_get_sequence_size (op, "/ADMINS_S"); for (first = TRUE, i = 0; i < nrows; i++) { gchar *name; name = gda_server_operation_get_sql_identifier_at (op, cnc, provider, "/ADMINS_S/%d/ROLE", error, i); if (name) { if (first) { first = FALSE; g_string_append (string, " ADMIN "); } else g_string_append (string, ", "); g_string_append (string, name); g_free (name); } else { g_string_free (string, TRUE); return NULL; } } value = gda_server_operation_get_value_at (op, "/USER_DEF_P/VALIDITY"); if (value && G_VALUE_HOLDS (value, GDA_TYPE_TIMESTAMP)) { if (value) { GdaDataHandler *dh; if (!with) { g_string_append (string, " WITH"); with = TRUE; } dh = gda_server_provider_get_data_handler_g_type (provider, cnc, GDA_TYPE_TIMESTAMP); if (!dh) dh = gda_data_handler_get_default (GDA_TYPE_TIMESTAMP); g_string_append (string, " VALID UNTIL "); tmp = gda_data_handler_get_sql_from_value (dh, value); g_string_append (string, tmp); g_free (tmp); } } sql = string->str; g_string_free (string, FALSE); return sql; }
/* * Create a "products" table using a GdaServerOperation object */ void create_table (GdaConnection *cnc) { GError *error = NULL; GdaServerProvider *provider; GdaServerOperation *op; gchar *sql; gint i; /* create a new GdaServerOperation object */ provider = gda_connection_get_provider (cnc); op = gda_server_provider_create_operation (provider, cnc, GDA_SERVER_OPERATION_CREATE_TABLE, NULL, &error); if (!op) { g_print ("CREATE TABLE operation is not supported by the provider: %s\n", error && error->message ? error->message : "No detail"); exit (1); } /* Set parameter's values */ /* table name */ if (!gda_server_operation_set_value_at (op, "products", &error, "/TABLE_DEF_P/TABLE_NAME")) goto on_set_error; /* "id' field */ i = 0; if (!gda_server_operation_set_value_at (op, "id", &error, "/FIELDS_A/@COLUMN_NAME/%d", i)) goto on_set_error; if (!gda_server_operation_set_value_at (op, "integer", &error, "/FIELDS_A/@COLUMN_TYPE/%d", i)) goto on_set_error; if (!gda_server_operation_set_value_at (op, "TRUE", &error, "/FIELDS_A/@COLUMN_AUTOINC/%d", i)) goto on_set_error; if (!gda_server_operation_set_value_at (op, "TRUE", &error, "/FIELDS_A/@COLUMN_PKEY/%d", i)) goto on_set_error; /* 'product_name' field */ i++; if (!gda_server_operation_set_value_at (op, "product_name", &error, "/FIELDS_A/@COLUMN_NAME/%d", i)) goto on_set_error; if (!gda_server_operation_set_value_at (op, "varchar", &error, "/FIELDS_A/@COLUMN_TYPE/%d", i)) goto on_set_error; if (!gda_server_operation_set_value_at (op, "50", &error, "/FIELDS_A/@COLUMN_SIZE/%d", i)) goto on_set_error; if (!gda_server_operation_set_value_at (op, "TRUE", &error, "/FIELDS_A/@COLUMN_NNUL/%d", i)) goto on_set_error; /* Show the SQL to execute * This does not always work since some operations may not be accessible through SQL */ sql = gda_server_provider_render_operation (provider, cnc, op, &error); if (!sql) { g_print ("Error rendering SQL: %s\n", error && error->message ? error->message : "No detail"); exit (1); } g_print ("SQL to execute: %s\n", sql); g_free (sql); /* Actually execute the operation */ if (! gda_server_provider_perform_operation (provider, cnc, op, &error)) { g_print ("Error executing the operation: %s\n", error && error->message ? error->message : "No detail"); exit (1); } g_object_unref (op); return; on_set_error: g_print ("Error setting value in GdaSererOperation: %s\n", error && error->message ? error->message : "No detail"); exit (1); }
/** * 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; }
GdaDataModel * gda_mysql_recordset_new_direct (GdaConnection *cnc, GdaDataModelAccessFlags flags, GType *col_types) { GdaMysqlRecordset *model; MysqlConnectionData *cdata; gint i; GdaDataModelAccessFlags rflags; GSList *columns = NULL; g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL); if (!cdata) return NULL; /* determine access mode: RANDOM or CURSOR FORWARD are the only supported */ if (flags & GDA_DATA_MODEL_ACCESS_RANDOM) rflags = GDA_DATA_MODEL_ACCESS_RANDOM; else rflags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD; /* create data model */ model = g_object_new (GDA_TYPE_MYSQL_RECORDSET, "connection", cnc, "model-usage", rflags, NULL); model->priv->cnc = cnc; g_object_ref (G_OBJECT(cnc)); /* columns & types */ model->priv->ncols = mysql_field_count (cdata->mysql); model->priv->types = g_new0 (GType, model->priv->ncols); /* create columns */ for (i = 0; i < model->priv->ncols; i++) columns = g_slist_prepend (columns, gda_column_new ()); columns = g_slist_reverse (columns); if (col_types) { for (i = 0; ; i++) { if (col_types [i] > 0) { if (col_types [i] == G_TYPE_NONE) break; if (i >= model->priv->ncols) { g_warning (_("Column %d out of range (0-%d), ignoring its specified type"), i, model->priv->ncols - 1); break; } else model->priv->types [i] = col_types [i]; } } } /* fill bind result */ MYSQL_RES *mysql_res = mysql_store_result (cdata->mysql); MYSQL_FIELD *mysql_fields = mysql_fetch_fields (mysql_res); GSList *list; ((GdaDataSelect *) model)->advertized_nrows = mysql_affected_rows (cdata->mysql); for (i=0, list = columns; i < model->priv->ncols; i++, list = list->next) { GdaColumn *column = GDA_COLUMN (list->data); /* use C API to set columns' information using gda_column_set_*() */ MYSQL_FIELD *field = &mysql_fields[i]; GType gtype = model->priv->types [i]; if (gtype == GDA_TYPE_NULL) { gtype = _gda_mysql_type_to_gda (cdata, field->type, field->charsetnr); model->priv->types [i] = gtype; } gda_column_set_g_type (column, gtype); gda_column_set_name (column, field->name); gda_column_set_description (column, field->name); } gda_data_select_set_columns (GDA_DATA_SELECT (model), columns); /* load ALL data */ MYSQL_ROW mysql_row; gint rownum; GdaServerProvider *prov; prov = gda_connection_get_provider (cnc); for (mysql_row = mysql_fetch_row (mysql_res), rownum = 0; mysql_row; mysql_row = mysql_fetch_row (mysql_res), rownum++) { GdaRow *row = gda_row_new (model->priv->ncols); gint col; for (col = 0; col < model->priv->ncols; col++) { gint i = col; GValue *value = gda_row_get_value (row, i); GType type = model->priv->types[i]; char *data = mysql_row[i]; if (!data || (type == GDA_TYPE_NULL)) continue; gda_value_reset_with_type (value, type); if (type == G_TYPE_STRING) g_value_set_string (value, data); else { GdaDataHandler *dh; gboolean valueset = FALSE; dh = gda_server_provider_get_data_handler_g_type (prov, cnc, type); if (dh) { GValue *tmpvalue; tmpvalue = gda_data_handler_get_value_from_str (dh, data, type); if (tmpvalue) { *value = *tmpvalue; g_free (tmpvalue); valueset = TRUE; } } if (!valueset) gda_row_invalidate_value (row, value); } } gda_data_select_take_row ((GdaDataSelect*) model, row, rownum); } mysql_free_result (mysql_res); return GDA_DATA_MODEL (model); }
GdaBlobOp * _gda_sqlite_blob_op_new (GdaConnection *cnc, const gchar *db_name, const gchar *table_name, const gchar *column_name, sqlite3_int64 rowid) { GdaSqliteBlobOp *bop = NULL; int rc; sqlite3_blob *sblob; gchar *db, *table; gboolean free_strings = TRUE; gboolean transaction_started = FALSE; g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); g_return_val_if_fail (table_name, NULL); g_return_val_if_fail (column_name, NULL); g_return_val_if_fail (GDA_IS_SQLITE_PROVIDER (gda_connection_get_provider (cnc)), NULL); GdaSqliteBlobOpPrivate *priv = gda_sqlite_blob_op_get_instance_private (bop); if (db_name) { db = (gchar *) db_name; table = (gchar *) table_name; free_strings = FALSE; } else if (! _split_identifier_string (g_strdup (table_name), &db, &table)) return NULL; SqliteConnectionData *cdata; cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL); if (!cdata || ! _gda_sqlite_check_transaction_started (cnc, &transaction_started, NULL)) return NULL; GdaSqliteProvider *prov = GDA_SQLITE_PROVIDER (gda_connection_get_provider (cnc)); rc = SQLITE3_CALL (prov, sqlite3_blob_open) (cdata->connection, db ? db : "main", table, column_name, rowid, 1, /* Read & Write */ &(sblob)); if (rc != SQLITE_OK) { #ifdef GDA_DEBUG_NO g_print ("ERROR: %s\n", SQLITE3_CALL (prov, sqlite3_errmsg) (cdata->connection)); #endif if (transaction_started) gda_connection_rollback_transaction (cnc, NULL, NULL); goto out; } bop = g_object_new (GDA_TYPE_SQLITE_BLOB_OP, "connection", cnc, NULL); priv->sblob = sblob; g_weak_ref_set (&priv->provider, prov); #ifdef GDA_DEBUG_NO g_print ("OPENED blob %p\n", bop); #endif out: if (free_strings) { g_free (db); g_free (table); } return (GdaBlobOp*) bop; }