Exemple #1
0
/**
 * 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;
}
Exemple #3
0
/**
 * 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;
}
Exemple #4
0
/**
 * 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;
}
Exemple #5
0
/*
 * 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;
}
Exemple #6
0
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;
}
Exemple #7
0
/*
 * 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;
}
Exemple #11
0
/**
 * 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;	
}
Exemple #12
0
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;
}
Exemple #13
0
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;
}
Exemple #14
0
/*
 * 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);
}
Exemple #15
0
/**
 * 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;
}
Exemple #16
0
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);
}
Exemple #17
0
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;
}