/** * 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_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; }
/** * 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[]) { GOptionContext *context; GError *error = NULL; int exit_status = EXIT_SUCCESS; GSList *list, *cnc_list = NULL; context = g_option_context_new ("[DSN|connection string]..."); g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_print ("Can't parse arguments: %s\n", error->message); exit_status = EXIT_FAILURE; goto cleanup; } g_option_context_free (context); gda_init (); ask_pass = !ask_pass; config = g_new0 (HtmlConfig, 1); html_init_config (HTML_CONFIG (config)); config->index = html_file_new (HTML_CONFIG (config), "index.html", "Providers status"); config->dir = g_strdup ("."); /* parse command line arguments for connections */ if (argc > 1) { gint i; for (i = 1; i < argc; i++) { /* open connection */ GdaConnection *cnc; cnc = open_connection (argv[i], &error); if (!cnc) { g_print ("Can't open connection to '%s': %s\n", argv[i], error && error->message ? error->message : "No detail"); exit_status = EXIT_FAILURE; goto cleanup; } cnc_list = g_slist_append (cnc_list, cnc); } } else { if (getenv ("GDA_SQL_CNC")) { GdaConnection *cnc; cnc = open_connection (getenv ("GDA_SQL_CNC"), &error); if (!cnc) { g_print ("Can't open connection defined by GDA_SQL_CNC: %s\n", error && error->message ? error->message : "No detail"); exit_status = EXIT_FAILURE; goto cleanup; } cnc_list = g_slist_append (cnc_list, cnc); } else { /* report status for all providers */ GdaDataModel *providers; gint i, nb; providers = gda_config_list_providers (); nb = gda_data_model_get_n_rows (providers); for (i = 0; i < nb; i++) { GdaServerProvider *prov = NULL; const gchar *pname; const GValue *cvalue; cvalue = gda_data_model_get_value_at (providers, 0, i, &error); if (!cvalue) g_error ("Can't load next provider: %s\n", error && error->message ? error->message : "No detail"); pname = g_value_get_string (cvalue); prov = gda_config_get_provider (pname, &error); if (!prov) g_error ("Can't load the '%s' provider: %s\n", pname, error && error->message ? error->message : "No detail"); if (!report_provider_status (prov, NULL)) { exit_status = EXIT_FAILURE; goto cleanup; } } g_object_unref (providers); } } /* report provider's status for all the connections */ for (list = cnc_list; list; list = list->next) { if (!report_provider_status (NULL, GDA_CONNECTION (list->data))) { exit_status = EXIT_FAILURE; goto cleanup; } } g_slist_foreach (HTML_CONFIG (config)->all_files, (GFunc) html_file_write, config); /* cleanups */ cleanup: g_slist_foreach (cnc_list, (GFunc) g_object_unref, NULL); g_slist_free (cnc_list); return exit_status; }