libgda r3374 - in trunk: . doc/C doc/C/tmpl libgda libgda/thread-wrapper samples samples/AsyncExec tests/multi-threading tools
- From: vivien svn gnome org
- To: svn-commits-list gnome org
- Subject: libgda r3374 - in trunk: . doc/C doc/C/tmpl libgda libgda/thread-wrapper samples samples/AsyncExec tests/multi-threading tools
- Date: Tue, 14 Apr 2009 18:49:11 +0000 (UTC)
Author: vivien
Date: Tue Apr 14 18:49:11 2009
New Revision: 3374
URL: http://svn.gnome.org/viewvc/libgda?rev=3374&view=rev
Log:
2009-04-14 Vivien Malerba <malerba gnome-db org>
* libgda/thread-wrapper/Makefile.am:
* libgda/thread-wrapper/gda-thread-blob-op.[ch]: wrapper for GdaBlobOp
objects
* libgda/thread-wrapper/gda-thread-wrapper.[ch]:
- loosened locking
- allow the wrapped thread to use the GdaThreadWrapper object
- API change in gda_thread_wrapper_fetch_result()
* libgda/thread-wrapper/gda-thread-recordset.c:
- use the new GdaThreadBlobOp object
- adaptations to the API change in gda_thread_wrapper_fetch_result()
* libgda/thread-wrapper/gda-thread-provider.[ch]:
- renamed gda_thread_provider_get_type() to _gda_thread_provider_get_type()
to avoid exporting the symbol
- implemented asynchronous execution
- adaptations to the API change in gda_thread_wrapper_fetch_result()
* tests/multi-threading/check_wrapper.c:
- adaptations to the API change in gda_thread_wrapper_fetch_result()
* libgda/gda-connection.c:
- instanciate the database provider only when really needed
- loosened locking
* tools/test_blob.sh: adapted to version 4.1
* doc/C: doc. updates regarding multi-threading and asynchronous statement
execution
* Makefile.am:
* samples/Makefile:
* samples/README:
* samples/AsyncExec: new example about hos to use the asynchronous statement
execution API
Added:
trunk/libgda/thread-wrapper/gda-thread-blob-op.c
trunk/libgda/thread-wrapper/gda-thread-blob-op.h
trunk/samples/AsyncExec/
trunk/samples/AsyncExec/Makefile
trunk/samples/AsyncExec/README
trunk/samples/AsyncExec/example.c
Modified:
trunk/ChangeLog
trunk/Makefile.am
trunk/doc/C/prov-writing.xml
trunk/doc/C/tmpl/gda-thread-wrapper.sgml
trunk/libgda/gda-connection-internal.h
trunk/libgda/gda-connection.c
trunk/libgda/thread-wrapper/Makefile.am
trunk/libgda/thread-wrapper/gda-thread-provider.c
trunk/libgda/thread-wrapper/gda-thread-provider.h
trunk/libgda/thread-wrapper/gda-thread-recordset.c
trunk/libgda/thread-wrapper/gda-thread-wrapper.c
trunk/libgda/thread-wrapper/gda-thread-wrapper.h
trunk/samples/Makefile
trunk/samples/README
trunk/tests/multi-threading/check_wrapper.c
trunk/tools/test_blob.sh
Modified: trunk/Makefile.am
==============================================================================
--- trunk/Makefile.am (original)
+++ trunk/Makefile.am Tue Apr 14 18:49:11 2009
@@ -71,7 +71,10 @@
samples/Tree/example.c \
samples/SqlBuilder/Makefile \
samples/SqlBuilder/README \
- samples/SqlBuilder/example.c
+ samples/SqlBuilder/example.c \
+ samples/AsyncExec/Makefile \
+ samples/AsyncExec/README \
+ samples/AsyncExec/example.c
EXTRA_DIST = \
COPYING \
Modified: trunk/doc/C/prov-writing.xml
==============================================================================
--- trunk/doc/C/prov-writing.xml (original)
+++ trunk/doc/C/prov-writing.xml Tue Apr 14 18:49:11 2009
@@ -34,13 +34,18 @@
<title>Synchronous / asynchronous mode</title>
<para>
All the provider's commands are executed in a synchronous mode (the caller is blocked until the provider's
- method terminates). However some virtual methods have the <parameter>task_id</parameter>,
- <parameter>async_cb</parameter> and <parameter>cb_data</parameter> which can be set when an asynchronous mode
- is required; asynchronous mode is requested if and only if the <parameter>async_cb</parameter> is not NULL.
+ method terminates). However some virtual methods have the a <parameter>task_id</parameter> parameter,
+ an <parameter>async_cb</parameter> or <parameter>exec_cb</parameter> callback function pointer and
+ a <parameter>cb_data</parameter> parameter which can be set when an asynchronous mode
+ is required; asynchronous mode is requested if and only if the <parameter>async_cb</parameter> or
+ <parameter>exec_cb</parameter> parmeter is not NULL.
</para>
<para>
- When an asynchronous mode is requested, the method should return a temporary result and set a task identifier
- into the <parameter>task_id</parameter> parameter if not NULL.
+ When an asynchronous mode is requested, the method should return TRUE if it returns a boolean or NULL if it returns a
+ pointer and set a task identifier
+ into the <parameter>task_id</parameter> parameter if not NULL. The task identifier is passed again when
+ the <parameter>async_cb</parameter> or <parameter>exec_cb</parameter> callback functions are called by the
+ provider when the execution is finished.
</para>
<para>
When the provider's method terminates, it then should call the function passed as <parameter>async_cb</parameter>
@@ -262,6 +267,31 @@
<link linkend="gda-connection-statement-execute">gda_connection_statement_execute()</link> for more information, note that
this method is also always the one called when any of the gda_connection_statement_execute*() methods are called.
</para>
+ <para>
+ A non NULL <parameter>exec_cb</parameter> parameter specifies that the user requests an asynchronous execution: the
+ function has to return the NULL value immediately (it must not be blocking), and the <parameter>task_id</parameter>
+ parameter must be set to contain a provider specific task ID.
+ The <parameter>exec_cb</parameter> parameter points to a callback function (specified by the
+ <link linkend="GdaConnection">GdaConnection</link>) which the provider has to call once the statement has been
+ executed, using the same task ID which was defined when the statement_execute() function was called, and
+ the <parameter>cb_data</parameter> specified when the statement_execute() function was called.
+ </para>
+ <para>
+ Note that if an asynchronous execution is requested, then the <parameter>stmt</parameter>, <parameter>params</parameter>,
+ <parameter>col_types</parameter>, <parameter>last_inserted_row</parameter>, and <parameter>cb_data</parameter>
+ parameters are supposed to exist and not be altered during the time the statement is executed (the
+ <link linkend="GdaConnection">GdaConnection</link> ensures this) which means it's not necessary to make copies
+ of them during the execution.
+ </para>
+ </sect2>
+ <sect2>
+ <title>handle_async()</title>
+ <para>
+ This method, if implemented, is called to give the database provider a chance to execute some code in case an
+ asynchronous statement's execution has been requested. Often providers will send some data over the network to the
+ database server when the statement_execute() is called, and implement this virtual function as a way to get
+ some data from the database server to see if the execution is terminated.
+ </para>
</sect2>
</sect1>
Modified: trunk/doc/C/tmpl/gda-thread-wrapper.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-thread-wrapper.sgml (original)
+++ trunk/doc/C/tmpl/gda-thread-wrapper.sgml Tue Apr 14 18:49:11 2009
@@ -103,7 +103,7 @@
@wrapper:
@may_lock:
- out_id:
+ exp_id:
@error:
@Returns:
Modified: trunk/libgda/gda-connection-internal.h
==============================================================================
--- trunk/libgda/gda-connection-internal.h (original)
+++ trunk/libgda/gda-connection-internal.h Tue Apr 14 18:49:11 2009
@@ -24,6 +24,7 @@
#define __GDA_CONNECTION_INTERNAL_H_
#include <libgda/gda-decl.h>
+#include <libgda/gda-server-provider.h>
#include <libgda/thread-wrapper/gda-thread-wrapper.h>
G_BEGIN_DECLS
@@ -35,6 +36,12 @@
*/
GdaConnection *_gda_open_internal_sqlite_connection (const gchar *cnc_string);
+typedef struct {
+ guint jid;
+ GdaServerProviderExecCallback async_cb;
+ gpointer cb_data;
+} ThreadConnectionAsyncTask;
+void _ThreadConnectionAsyncTask_free (ThreadConnectionAsyncTask *atd);
/*
* Functions dedicated to implementing a GdaConnection which uses a GdaThreadWrapper around
@@ -45,6 +52,9 @@
GdaServerProvider *cnc_provider;
GdaThreadWrapper *wrapper;
GArray *handlers_ids; /* array of gulong */
+
+ /* current async. tasks */
+ GSList *async_tasks; /* list of ThreadConnectionAsyncTask pointers */
} ThreadConnectionData; /* Per connection private data for */
void _gda_connection_force_transaction_status (GdaConnection *cnc, GdaConnection *wrapped_cnc);
Modified: trunk/libgda/gda-connection.c
==============================================================================
--- trunk/libgda/gda-connection.c (original)
+++ trunk/libgda/gda-connection.c Tue Apr 14 18:49:11 2009
@@ -781,10 +781,11 @@
/* try to find provider */
if (dsn_info->provider != NULL) {
- GdaServerProvider *prov;
+ GdaProviderInfo *pinfo;
+ GdaServerProvider *prov = NULL;
- prov = gda_config_get_provider (dsn_info->provider, error);
- if (prov) {
+ pinfo = gda_config_get_provider_info (dsn_info->provider);
+ if (pinfo) {
if (options & GDA_CONNECTION_OPTIONS_THREAD_SAFE) {
if (!_gda_thread_wrapper_provider)
_gda_thread_wrapper_provider =
@@ -792,6 +793,14 @@
NULL));
prov = _gda_thread_wrapper_provider;
}
+ else
+ prov = gda_config_get_provider (dsn_info->provider, error);
+ }
+ else
+ g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_PROVIDER_NOT_FOUND_ERROR,
+ _("No provider '%s' installed"), dsn_info->provider);
+
+ if (prov) {
if (PROV_CLASS (prov)->create_connection) {
cnc = PROV_CLASS (prov)->create_connection (prov);
if (cnc)
@@ -915,14 +924,14 @@
/* try to find provider */
if (provider_name || real_provider) {
- GdaServerProvider *prov;
+ GdaProviderInfo *pinfo;
+ GdaServerProvider *prov = NULL;
- prov = gda_config_get_provider (provider_name ? provider_name : real_provider, error);
- if (prov) {
+ pinfo = gda_config_get_provider_info (provider_name ? provider_name : real_provider);
+ if (pinfo) {
if (options & GDA_CONNECTION_OPTIONS_THREAD_SAFE) {
gchar *tmp;
- tmp = g_strdup_printf ("%s;PROVIDER_NAME=%s",
- real_cnc, gda_server_provider_get_name (prov));
+ tmp = g_strdup_printf ("%s;PROVIDER_NAME=%s", real_cnc, pinfo->id);
g_free (real_cnc);
real_cnc = tmp;
if (!_gda_thread_wrapper_provider)
@@ -931,7 +940,14 @@
NULL));
prov = _gda_thread_wrapper_provider;
}
+ else
+ prov = gda_config_get_provider (provider_name ? provider_name : real_provider, error);
+ }
+ else
+ g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_PROVIDER_NOT_FOUND_ERROR,
+ _("No provider '%s' installed"), provider_name ? provider_name : real_provider);
+ if (prov) {
if (PROV_CLASS (prov)->create_connection) {
cnc = PROV_CLASS (prov)->create_connection (prov);
if (cnc)
@@ -1386,7 +1402,7 @@
g_return_if_fail (cnc->priv);
g_return_if_fail (GDA_IS_CONNECTION_EVENT (event));
- gda_connection_lock ((GdaLockable*) cnc);
+ gda_mutex_lock (cnc->priv->mutex);
if (debug == -1) {
const gchar *str;
debug = 0;
@@ -1437,7 +1453,7 @@
if (gda_connection_event_get_event_type (event) == GDA_CONNECTION_EVENT_ERROR)
g_signal_emit (G_OBJECT (cnc), gda_connection_signals[ERROR], 0, event);
- gda_connection_unlock ((GdaLockable*) cnc);
+ gda_mutex_unlock (cnc->priv->mutex);
}
/**
@@ -1764,7 +1780,7 @@
gda_connection_lock (GDA_LOCKABLE (cnc));
- i = get_task_index (cnc, task_id, &is_completed, FALSE);
+ i = get_task_index (cnc, task_id, &is_completed, TRUE);
if (i >= 0) {
CncTask *task;
g_assert (!is_completed);
@@ -1799,12 +1815,12 @@
cnc_task_unlock (task);
/* execute next waiting task if there is one */
- while (cnc->priv->waiting_tasks->len >= 1) {
+ if (cnc->priv->waiting_tasks->len >= 1) {
/* execute statement now as there are no other ones to be executed */
GError *lerror = NULL;
task = CNC_TASK (g_array_index (cnc->priv->waiting_tasks, gpointer, 0));
- task->being_processed = TRUE;
cnc_task_lock (task);
+ task->being_processed = TRUE;
PROV_CLASS (cnc->priv->provider_obj)->statement_execute (cnc->priv->provider_obj, cnc,
task->stmt,
task->params,
@@ -1824,9 +1840,11 @@
cnc_task_unlock (task);
}
}
- g_print ("%s() called!!!\n", __FUNCTION__);
+ else
+ g_warning ("Provider called back for the execution of task %u (provider numbering) which does not exist, "
+ "ignored.\n", task_id);
- gda_connection_lock (GDA_LOCKABLE (cnc));
+ gda_connection_unlock (GDA_LOCKABLE (cnc));
}
/**
@@ -1839,14 +1857,14 @@
* @need_last_insert_row: TRUE if the values of the last interted row must be computed
* @error: a place to store errors, or %NULL
*
- * This method is somilar to gda_connection_statement_execute() but is done asynchronously as this method returns
- * immediately a task ID. It's up to the caller to use gda_connection_async_fetch_result() regularly to check
+ * This method is similar to gda_connection_statement_execute() but is asynchronous as it method returns
+ * immediately with a task ID. It's up to the caller to use gda_connection_async_fetch_result() regularly to check
* if the statement's execution is finished.
*
* It is possible to call the method several times to request several statements to be executed asynchronously, the
* statements will be executed in the order in which they were requested.
*
- * The parameters, if present, are copied and can be discaded or modified before the statement is actually executed.
+ * The parameters, if present, are copied and can be discarded or modified before the statement is actually executed.
* The @stmt object is not copied but simply referenced (for performance reasons), and if it is modified before
* it is actually executed, then its execution will not occur. It is however safe to call g_object_unref() on it if
* it's not needed anymore.
@@ -1886,11 +1904,13 @@
if (cnc->priv->waiting_tasks->len == 1) {
/* execute statement now as there are no other ones to be executed */
GError *lerror = NULL;
- task->being_processed = TRUE;
cnc_task_lock (task);
+ task->being_processed = TRUE;
PROV_CLASS (cnc->priv->provider_obj)->statement_execute (cnc->priv->provider_obj, cnc,
- task->stmt, task->params,
- task->model_usage, task->col_types,
+ task->stmt,
+ task->params,
+ task->model_usage,
+ task->col_types,
&(task->last_insert_row),
&(task->prov_task_id),
(GdaServerProviderExecCallback) async_stmt_exec_cb,
@@ -3580,6 +3600,7 @@
ThreadConnectionData *cdata;
UpdateMetaStoreData data;
gpointer res;
+ guint jid;
cdata = (ThreadConnectionData*) gda_connection_internal_get_provider_data (cnc);
if (!cdata)
@@ -3588,9 +3609,9 @@
data.cnc = cdata->sub_connection;
data.context = context;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_update_meta_store, &data, NULL, error);
- res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, error);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_update_meta_store, &data, NULL, error);
+ res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, error);
return GPOINTER_TO_INT (res) ? TRUE : FALSE;
}
@@ -4544,12 +4565,12 @@
static void
statement_weak_notify_cb (GdaConnection *cnc, GdaStatement *stmt)
{
- gda_connection_lock ((GdaLockable*) cnc);
+ gda_mutex_lock (cnc->priv->mutex);
g_assert (cnc->priv->prepared_stmts);
g_hash_table_remove (cnc->priv->prepared_stmts, stmt);
- gda_connection_unlock ((GdaLockable*) cnc);
+ gda_mutex_unlock (cnc->priv->mutex);
}
Modified: trunk/libgda/thread-wrapper/Makefile.am
==============================================================================
--- trunk/libgda/thread-wrapper/Makefile.am (original)
+++ trunk/libgda/thread-wrapper/Makefile.am Tue Apr 14 18:49:11 2009
@@ -13,6 +13,8 @@
libgda_threadwrapper_4_0_la_SOURCES = \
$(libgda_threadwrapper_headers) \
+ gda-thread-blob-op.h \
+ gda-thread-blob-op.c \
gda-thread-provider.h \
gda-thread-provider.c \
gda-thread-recordset.h \
Added: trunk/libgda/thread-wrapper/gda-thread-blob-op.c
==============================================================================
--- (empty file)
+++ trunk/libgda/thread-wrapper/gda-thread-blob-op.c Tue Apr 14 18:49:11 2009
@@ -0,0 +1,245 @@
+/* GDA
+ * Copyright (C) 2009 The GNOME Foundation
+ *
+ * AUTHORS:
+ * Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib/gi18n-lib.h>
+#include <string.h>
+#include "gda-thread-blob-op.h"
+
+struct _GdaThreadBlobOpPrivate {
+ GdaThreadWrapper *wrapper;
+ GdaBlobOp *wrapped_op;
+};
+
+static void gda_thread_blob_op_class_init (GdaThreadBlobOpClass *klass);
+static void gda_thread_blob_op_init (GdaThreadBlobOp *blob,
+ GdaThreadBlobOpClass *klass);
+static void gda_thread_blob_op_dispose (GObject *object);
+
+static glong gda_thread_blob_op_get_length (GdaBlobOp *op);
+static glong gda_thread_blob_op_read (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size);
+static glong gda_thread_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset);
+
+static GObjectClass *parent_class = NULL;
+
+/*
+ * Object init and dispose
+ */
+GType
+_gda_thread_blob_op_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static GStaticMutex registering = G_STATIC_MUTEX_INIT;
+ static const GTypeInfo info = {
+ sizeof (GdaThreadBlobOpClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gda_thread_blob_op_class_init,
+ NULL,
+ NULL,
+ sizeof (GdaThreadBlobOp),
+ 0,
+ (GInstanceInitFunc) gda_thread_blob_op_init
+ };
+ g_static_mutex_lock (®istering);
+ if (type == 0)
+ type = g_type_register_static (GDA_TYPE_BLOB_OP, "GdaThreadBlobOp", &info, 0);
+ g_static_mutex_unlock (®istering);
+ }
+ return type;
+}
+
+static void
+gda_thread_blob_op_init (GdaThreadBlobOp *op,
+ GdaThreadBlobOpClass *klass)
+{
+ g_return_if_fail (GDA_IS_THREAD_BLOB_OP (op));
+
+ op->priv = g_new0 (GdaThreadBlobOpPrivate, 1);
+ op->priv->wrapper = NULL;
+ op->priv->wrapped_op = NULL;
+}
+
+static void
+gda_thread_blob_op_class_init (GdaThreadBlobOpClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdaBlobOpClass *blob_class = GDA_BLOB_OP_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->dispose = gda_thread_blob_op_dispose;
+ blob_class->get_length = gda_thread_blob_op_get_length;
+ blob_class->read = gda_thread_blob_op_read;
+ blob_class->write = gda_thread_blob_op_write;
+}
+
+static void
+gda_thread_blob_op_dispose (GObject * object)
+{
+ GdaThreadBlobOp *thop = (GdaThreadBlobOp *) object;
+
+ g_return_if_fail (GDA_IS_THREAD_BLOB_OP (thop));
+
+ if (thop->priv) {
+ g_object_unref (thop->priv->wrapped_op);
+ g_object_unref (thop->priv->wrapper);
+ g_free (thop->priv);
+ thop->priv = NULL;
+ }
+
+ parent_class->dispose (object);
+}
+
+GdaBlobOp *
+_gda_thread_blob_op_new (GdaThreadWrapper *wrapper, GdaBlobOp *op)
+{
+ GdaThreadBlobOp *thop;
+
+ g_return_val_if_fail (GDA_IS_THREAD_WRAPPER (wrapper), NULL);
+ g_return_val_if_fail (GDA_IS_BLOB_OP (op), NULL);
+
+ thop = g_object_new (GDA_TYPE_THREAD_BLOB_OP, NULL);
+ thop->priv->wrapper = g_object_ref (wrapper);
+ thop->priv->wrapped_op = g_object_ref (op);
+
+ return GDA_BLOB_OP (thop);
+}
+
+
+/*
+ * Virtual functions
+ */
+static glong *
+sub_thread_blob_op_get_length (GdaBlobOp *wrapped_op, GError **error)
+{
+ /* WARNING: function executed in sub thread! */
+ glong *retptr;
+
+ retptr = g_new (glong, 1);
+ *retptr = gda_blob_op_get_length (wrapped_op);
+#ifdef GDA_DEBUG_NO
+ g_print ("/%s() => %ld\n", __FUNCTION__, *retptr);
+#endif
+
+ return retptr;
+}
+
+static glong
+gda_thread_blob_op_get_length (GdaBlobOp *op)
+{
+ GdaThreadBlobOp *thop;
+ glong *ptr, retval;
+ guint jid;
+
+ thop = (GdaThreadBlobOp *) op;
+ jid = gda_thread_wrapper_execute (thop->priv->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_blob_op_get_length,
+ thop->priv->wrapped_op, NULL, NULL);
+ ptr = (glong*) gda_thread_wrapper_fetch_result (thop->priv->wrapper, TRUE, jid, NULL);
+ retval = *ptr;
+ g_free (ptr);
+ return retval;
+}
+
+typedef struct {
+ GdaBlobOp *op;
+ GdaBlob *blob;
+ glong offset;
+ glong size;
+} ThreadData;
+
+static glong *
+sub_thread_blob_op_read (ThreadData *td, GError **error)
+{
+ /* WARNING: function executed in sub thread! */
+ glong *retptr;
+
+ retptr = g_new (glong, 1);
+ *retptr = gda_blob_op_read (td->op, td->blob, td->offset, td->size);
+#ifdef GDA_DEBUG_NO
+ g_print ("/%s() => %ld\n", __FUNCTION__, *retptr);
+#endif
+
+ return retptr;
+}
+
+static glong
+gda_thread_blob_op_read (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size)
+{
+ GdaThreadBlobOp *thop;
+ ThreadData td;
+ glong *ptr, retval;
+ guint jid;
+
+ thop = (GdaThreadBlobOp *) op;
+ td.op = thop->priv->wrapped_op;
+ td.blob = blob;
+ td.offset = offset;
+ td.size = size;
+
+ jid = gda_thread_wrapper_execute (thop->priv->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_blob_op_read,
+ &td, NULL, NULL);
+ ptr = (glong*) gda_thread_wrapper_fetch_result (thop->priv->wrapper, TRUE, jid, NULL);
+ retval = *ptr;
+ g_free (ptr);
+ return retval;
+}
+
+static glong *
+sub_thread_blob_op_write (ThreadData *td, GError **error)
+{
+ /* WARNING: function executed in sub thread! */
+ glong *retptr;
+
+ retptr = g_new (glong, 1);
+ *retptr = gda_blob_op_write (td->op, td->blob, td->offset);
+#ifdef GDA_DEBUG_NO
+ g_print ("/%s() => %ld\n", __FUNCTION__, *retptr);
+#endif
+
+ return retptr;
+}
+
+static glong
+gda_thread_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset)
+{
+ GdaThreadBlobOp *thop;
+ ThreadData td;
+ glong *ptr, retval;
+ guint jid;
+
+ thop = (GdaThreadBlobOp *) op;
+ td.op = thop->priv->wrapped_op;
+ td.blob = blob;
+ td.offset = offset;
+
+ jid = gda_thread_wrapper_execute (thop->priv->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_blob_op_write,
+ &td, NULL, NULL);
+ ptr = (glong*) gda_thread_wrapper_fetch_result (thop->priv->wrapper, TRUE, jid, NULL);
+ retval = *ptr;
+ g_free (ptr);
+ return retval;
+}
Added: trunk/libgda/thread-wrapper/gda-thread-blob-op.h
==============================================================================
--- (empty file)
+++ trunk/libgda/thread-wrapper/gda-thread-blob-op.h Tue Apr 14 18:49:11 2009
@@ -0,0 +1,56 @@
+/* GDA Library
+ * Copyright (C) 2009 The GNOME Foundation.
+ *
+ * AUTHORS:
+ * Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GDA_THREAD_BLOB_OP_H__
+#define __GDA_THREAD_BLOB_OP_H__
+
+#include <libgda/gda-value.h>
+#include <libgda/gda-blob-op.h>
+#include "gda-thread-wrapper.h"
+
+G_BEGIN_DECLS
+
+#define GDA_TYPE_THREAD_BLOB_OP (_gda_thread_blob_op_get_type())
+#define GDA_THREAD_BLOB_OP(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GDA_TYPE_THREAD_BLOB_OP, GdaThreadBlobOp))
+#define GDA_THREAD_BLOB_OP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST (klass, GDA_TYPE_THREAD_BLOB_OP, GdaThreadBlobOpClass))
+#define GDA_IS_THREAD_BLOB_OP(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GDA_TYPE_THREAD_BLOB_OP))
+#define GDA_IS_THREAD_BLOB_OP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDA_TYPE_THREAD_BLOB_OP))
+
+typedef struct _GdaThreadBlobOp GdaThreadBlobOp;
+typedef struct _GdaThreadBlobOpClass GdaThreadBlobOpClass;
+typedef struct _GdaThreadBlobOpPrivate GdaThreadBlobOpPrivate;
+
+struct _GdaThreadBlobOp {
+ GdaBlobOp parent;
+ GdaThreadBlobOpPrivate *priv;
+};
+
+struct _GdaThreadBlobOpClass {
+ GdaBlobOpClass parent_class;
+};
+
+GType _gda_thread_blob_op_get_type (void) G_GNUC_CONST;
+GdaBlobOp *_gda_thread_blob_op_new (GdaThreadWrapper *wrapper, GdaBlobOp *op);
+
+G_END_DECLS
+
+#endif
Modified: trunk/libgda/thread-wrapper/gda-thread-provider.c
==============================================================================
--- trunk/libgda/thread-wrapper/gda-thread-provider.c (original)
+++ trunk/libgda/thread-wrapper/gda-thread-provider.c Tue Apr 14 18:49:11 2009
@@ -1,5 +1,5 @@
/* GDA Thread provider
- * Copyright (C) 2008 The GNOME Foundation.
+ * Copyright (C) 2009 The GNOME Foundation.
*
* AUTHORS:
* Vivien Malerba <malerba gnome-db org>
@@ -116,6 +116,7 @@
GType *col_types, GdaSet **last_inserted_row,
guint *task_id, GdaServerProviderExecCallback async_cb,
gpointer cb_data, GError **error);
+static gboolean gda_thread_provider_handle_async (GdaServerProvider *provider, GdaConnection *cnc, GError **error);
/* distributed transactions */
static gboolean gda_thread_provider_xa_start (GdaServerProvider *provider, GdaConnection *cnc,
@@ -174,6 +175,7 @@
provider_class->statement_to_sql = gda_thread_provider_statement_to_sql;
provider_class->statement_prepare = gda_thread_provider_statement_prepare;
provider_class->statement_execute = gda_thread_provider_statement_execute;
+ provider_class->handle_async = gda_thread_provider_handle_async;
provider_class->is_busy = NULL;
provider_class->cancel = NULL;
@@ -197,7 +199,7 @@
}
GType
-gda_thread_provider_get_type (void)
+_gda_thread_provider_get_type (void)
{
static GType type = 0;
@@ -282,7 +284,9 @@
data->auth_string, data->options, error);
if (cnc)
data->out_cnc_provider = gda_connection_get_provider (cnc);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %p\n", __FUNCTION__, cnc);
+#endif
return cnc;
}
@@ -326,18 +330,20 @@
GdaThreadWrapper *wr;
GdaConnection *sub_cnc;
GError *error = NULL;
+ guint jid;
g_assert (data);
data->auth_string = auth_string;
data->options = options & (~GDA_CONNECTION_OPTIONS_THREAD_SAFE);
wr = gda_thread_wrapper_new ();
- gda_thread_wrapper_execute (wr, (GdaThreadWrapperFunc) sub_thread_open_connection, data, NULL, NULL);
- sub_cnc = gda_thread_wrapper_fetch_result (wr, TRUE, NULL, &error);
+ jid = gda_thread_wrapper_execute (wr, (GdaThreadWrapperFunc) sub_thread_open_connection, data, NULL, NULL);
+ sub_cnc = gda_thread_wrapper_fetch_result (wr, TRUE, jid, &error);
g_free (dsn);
g_free (cnc_string);
g_free (auth_string);
if (!sub_cnc) {
- TO_IMPLEMENT; /* create a GdaConnectionEvent from @error using
- gda_connection_add_event_string () */
+ gda_connection_add_event_string (cnc, "%s", error && error->message ? error->message : _("No detail"));
+ if (error)
+ g_error_free (error);
g_object_unref (wr);
g_free (data);
return FALSE;
@@ -408,7 +414,9 @@
/* WARNING: function executed in sub thread! */
gboolean retval;
retval = PROV_CLASS (data->prov)->close_connection (data->prov, data->cnc);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval ? "TRUE" : "FALSE");
+#endif
return GINT_TO_POINTER (retval ? 1 : 0);
}
@@ -418,6 +426,7 @@
ThreadConnectionData *cdata;
CncProvData wdata;
gpointer res;
+ guint jid;
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
@@ -429,9 +438,9 @@
wdata.prov = cdata->cnc_provider;
wdata.cnc = cdata->sub_connection;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_close_connection, &wdata, NULL, NULL);
- res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, NULL);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_close_connection, &wdata, NULL, NULL);
+ res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
return GPOINTER_TO_INT (res) ? TRUE : FALSE;
}
@@ -447,7 +456,9 @@
/* WARNING: function executed in sub thread! */
const gchar *retval;
retval = PROV_CLASS (data->prov)->get_server_version (data->prov, data->cnc);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval);
+#endif
return retval;
}
static const gchar *
@@ -455,6 +466,7 @@
{
ThreadConnectionData *cdata;
CncProvData wdata;
+ guint jid;
if (!cnc)
return NULL;
@@ -469,9 +481,9 @@
wdata.prov = cdata->cnc_provider;
wdata.cnc = cdata->sub_connection;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_get_server_version, &wdata, NULL, NULL);
- return (const gchar*) gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, NULL);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_get_server_version, &wdata, NULL, NULL);
+ return (const gchar*) gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
}
/*
@@ -485,7 +497,9 @@
/* WARNING: function executed in sub thread! */
const gchar *retval;
retval = PROV_CLASS (data->prov)->get_database (data->prov, data->cnc);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval);
+#endif
return retval;
}
@@ -494,6 +508,7 @@
{
ThreadConnectionData *cdata;
CncProvData wdata;
+ guint jid;
if (!cnc)
return NULL;
@@ -508,9 +523,9 @@
wdata.prov = cdata->cnc_provider;
wdata.cnc = cdata->sub_connection;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_get_database, &wdata, NULL, NULL);
- return (const gchar *) gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, NULL);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_get_database, &wdata, NULL, NULL);
+ return (const gchar *) gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
}
/*
@@ -537,7 +552,9 @@
/* WARNING: function executed in sub thread! */
gboolean retval;
retval = PROV_CLASS (data->prov)->supports_operation (data->prov, data->cnc, data->type, data->options);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval ? "TRUE" : "FALSE");
+#endif
return GINT_TO_POINTER (retval ? 1 : 0);
}
@@ -548,6 +565,7 @@
ThreadConnectionData *cdata;
SupportsOperationData wdata;
gpointer res;
+ guint jid;
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
@@ -559,9 +577,9 @@
wdata.prov = cdata->cnc_provider;
wdata.cnc = cdata->sub_connection;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_supports_operation, &wdata, NULL, NULL);
- res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, NULL);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_supports_operation, &wdata, NULL, NULL);
+ res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
return GPOINTER_TO_INT (res) ? TRUE : FALSE;
}
@@ -588,7 +606,9 @@
data->type,
data->options,
error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %p\n", __FUNCTION__, op);
+#endif
return op;
}
@@ -598,6 +618,7 @@
{
ThreadConnectionData *cdata;
CreateOperationData wdata;
+ guint jid;
if (!cnc) {
g_set_error (error, 0, 0, _("A connection is required"));
@@ -615,9 +636,9 @@
wdata.type = type;
wdata.options = options;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_create_operation, &wdata, NULL, NULL);
- return (GdaServerOperation*) gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, error);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_create_operation, &wdata, NULL, NULL);
+ return (GdaServerOperation*) gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, error);
}
/*
@@ -638,7 +659,9 @@
data->cnc,
data->op,
error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, str);
+#endif
return str;
}
@@ -648,6 +671,7 @@
{
ThreadConnectionData *cdata;
RenderOperationData wdata;
+ guint jid;
if (!cnc) {
g_set_error (error, 0, 0, _("A connection is required"));
@@ -664,9 +688,9 @@
wdata.cnc = cdata->sub_connection;
wdata.op = op;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_render_operation, &wdata, NULL, NULL);
- return (gchar*) gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, error);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_render_operation, &wdata, NULL, NULL);
+ return (gchar*) gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, error);
}
/*
@@ -685,7 +709,9 @@
gboolean retval;
retval = PROV_CLASS (data->prov)->perform_operation (data->prov, data->cnc, data->op,
NULL, NULL, NULL, error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval ? "TRUE" : "FALSE");
+#endif
return GINT_TO_POINTER (retval ? 1 : 0);
}
@@ -697,6 +723,7 @@
ThreadConnectionData *cdata;
PerformOperationData wdata;
gpointer res;
+ guint jid;
/* If asynchronous connection opening is not supported, then exit now */
if (async_cb) {
@@ -721,9 +748,9 @@
wdata.cnc = cdata->sub_connection;
wdata.op = op;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_perform_operation, &wdata, NULL, error);
- res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, NULL);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_perform_operation, &wdata, NULL, error);
+ res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
return GPOINTER_TO_INT (res) ? TRUE : FALSE;
}
@@ -744,7 +771,9 @@
gboolean retval;
retval = PROV_CLASS (data->prov)->begin_transaction (data->prov, data->cnc, data->name,
data->level, error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval ? "TRUE" : "FALSE");
+#endif
return GINT_TO_POINTER (retval ? 1 : 0);
}
@@ -756,6 +785,7 @@
ThreadConnectionData *cdata;
BeginTransactionData wdata;
gpointer res;
+ guint jid;
if (!cnc) {
g_set_error (error, 0, 0, _("A connection is required"));
@@ -774,9 +804,9 @@
wdata.name = name;
wdata.level = level;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_begin_transaction, &wdata, NULL, error);
- res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, error);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_begin_transaction, &wdata, NULL, error);
+ res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, error);
return GPOINTER_TO_INT (res) ? TRUE : FALSE;
}
@@ -797,7 +827,9 @@
gboolean retval;
retval = PROV_CLASS (data->prov)->commit_transaction (data->prov, data->cnc, data->name,
error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval ? "TRUE" : "FALSE");
+#endif
return GINT_TO_POINTER (retval ? 1 : 0);
}
@@ -808,6 +840,7 @@
ThreadConnectionData *cdata;
TransactionData wdata;
gpointer res;
+ guint jid;
if (!cnc) {
g_set_error (error, 0, 0, _("A connection is required"));
@@ -825,9 +858,9 @@
wdata.cnc = cdata->sub_connection;
wdata.name = name;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_commit_transaction, &wdata, NULL, error);
- res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, NULL);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_commit_transaction, &wdata, NULL, error);
+ res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
return GPOINTER_TO_INT (res) ? TRUE : FALSE;
}
@@ -841,7 +874,9 @@
gboolean retval;
retval = PROV_CLASS (data->prov)->rollback_transaction (data->prov, data->cnc, data->name,
error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval ? "TRUE" : "FALSE");
+#endif
return GINT_TO_POINTER (retval ? 1 : 0);
}
@@ -852,6 +887,7 @@
ThreadConnectionData *cdata;
TransactionData wdata;
gpointer res;
+ guint jid;
if (!cnc) {
g_set_error (error, 0, 0, _("A connection is required"));
@@ -869,9 +905,9 @@
wdata.cnc = cdata->sub_connection;
wdata.name = name;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_rollback_transaction, &wdata, NULL, error);
- res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, NULL);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_rollback_transaction, &wdata, NULL, error);
+ res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
return GPOINTER_TO_INT (res) ? TRUE : FALSE;
}
@@ -885,7 +921,9 @@
gboolean retval;
retval = PROV_CLASS (data->prov)->add_savepoint (data->prov, data->cnc, data->name,
error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval ? "TRUE" : "FALSE");
+#endif
return GINT_TO_POINTER (retval ? 1 : 0);
}
@@ -896,6 +934,7 @@
ThreadConnectionData *cdata;
TransactionData wdata;
gpointer res;
+ guint jid;
if (!cnc) {
g_set_error (error, 0, 0, _("A connection is required"));
@@ -913,9 +952,9 @@
wdata.cnc = cdata->sub_connection;
wdata.name = name;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_add_savepoint, &wdata, NULL, error);
- res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, NULL);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_add_savepoint, &wdata, NULL, error);
+ res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
return GPOINTER_TO_INT (res) ? TRUE : FALSE;
}
@@ -929,7 +968,9 @@
gboolean retval;
retval = PROV_CLASS (data->prov)->rollback_savepoint (data->prov, data->cnc, data->name,
error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval ? "TRUE" : "FALSE");
+#endif
return GINT_TO_POINTER (retval ? 1 : 0);
}
@@ -940,6 +981,7 @@
ThreadConnectionData *cdata;
TransactionData wdata;
gpointer res;
+ guint jid;
if (!cnc) {
g_set_error (error, 0, 0, _("A connection is required"));
@@ -957,9 +999,9 @@
wdata.cnc = cdata->sub_connection;
wdata.name = name;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_rollback_savepoint, &wdata, NULL, error);
- res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, NULL);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_rollback_savepoint, &wdata, NULL, error);
+ res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
return GPOINTER_TO_INT (res) ? TRUE : FALSE;
}
@@ -973,7 +1015,9 @@
gboolean retval;
retval = PROV_CLASS (data->prov)->delete_savepoint (data->prov, data->cnc, data->name,
error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval ? "TRUE" : "FALSE");
+#endif
return GINT_TO_POINTER (retval ? 1 : 0);
}
@@ -984,6 +1028,7 @@
ThreadConnectionData *cdata;
TransactionData wdata;
gpointer res;
+ guint jid;
if (!cnc) {
g_set_error (error, 0, 0, _("A connection is required"));
@@ -1001,9 +1046,9 @@
wdata.cnc = cdata->sub_connection;
wdata.name = name;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_delete_savepoint, &wdata, NULL, error);
- res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, NULL);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_delete_savepoint, &wdata, NULL, error);
+ res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
return GPOINTER_TO_INT (res) ? TRUE : FALSE;
}
@@ -1054,7 +1099,9 @@
/* WARNING: function executed in sub thread! */
GdaDataHandler *retval;
retval = PROV_CLASS (data->prov)->get_data_handler (data->prov, data->cnc, data->type, data->dbms_type);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %p\n", __FUNCTION__, retval);
+#endif
return retval;
}
@@ -1065,6 +1112,7 @@
ThreadConnectionData *cdata;
GetDataHandlerData wdata;
GdaDataHandler *res;
+ guint jid;
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
@@ -1078,9 +1126,9 @@
wdata.type = type;
wdata.dbms_type = dbms_type;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_get_data_handler, &wdata, NULL, NULL);
- res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, NULL);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_get_data_handler, &wdata, NULL, NULL);
+ res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
return res;
}
@@ -1101,7 +1149,9 @@
/* WARNING: function executed in sub thread! */
const gchar *retval;
retval = PROV_CLASS (data->prov)->get_def_dbms_type (data->prov, data->cnc, data->type);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval);
+#endif
return retval;
}
@@ -1111,6 +1161,7 @@
ThreadConnectionData *cdata;
GetDefaultDbmsTypeData wdata;
const gchar *res;
+ guint jid;
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
@@ -1123,9 +1174,9 @@
wdata.cnc = cdata->sub_connection;
wdata.type = type;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_get_default_dbms_type, &wdata, NULL, NULL);
- res = (const gchar *) gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, NULL);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_get_default_dbms_type, &wdata, NULL, NULL);
+ res = (const gchar *) gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
return res;
}
@@ -1142,7 +1193,9 @@
/* WARNING: function executed in sub thread! */
GdaSqlParser *parser;
parser = PROV_CLASS (data->prov)->create_parser (data->prov, data->cnc);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %p\n", __FUNCTION__, parser);
+#endif
return parser;
}
@@ -1151,6 +1204,7 @@
{
ThreadConnectionData *cdata;
CncProvData wdata;
+ guint jid;
if (!cnc)
return NULL;
@@ -1165,9 +1219,9 @@
wdata.prov = cdata->cnc_provider;
wdata.cnc = cdata->sub_connection;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_create_parser, &wdata, NULL, NULL);
- return (GdaSqlParser *) gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, NULL);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_create_parser, &wdata, NULL, NULL);
+ return (GdaSqlParser *) gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
}
/*
@@ -1195,7 +1249,9 @@
const gchar *retval;
retval = PROV_CLASS (data->prov)->statement_to_sql (data->prov, data->cnc, data->stmt,
data->params, data->flags, data->params_used, error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval);
+#endif
return retval;
}
@@ -1206,6 +1262,7 @@
{
ThreadConnectionData *cdata;
StmtToSqlData wdata;
+ guint jid;
if (!cnc)
return NULL;
@@ -1224,9 +1281,9 @@
wdata.flags = flags;
wdata.params_used = params_used;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_statement_to_sql, &wdata, NULL, NULL);
- return (gchar *) gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, NULL);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_statement_to_sql, &wdata, NULL, NULL);
+ return (gchar *) gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
}
/*
@@ -1251,7 +1308,9 @@
data->cnc,
data->stmt,
error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval ? "TRUE" : "FALSE");
+#endif
return GINT_TO_POINTER (retval ? 1 : 0);
}
@@ -1262,6 +1321,7 @@
ThreadConnectionData *cdata;
PrepareStatementData wdata;
gpointer res;
+ guint jid;
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
@@ -1275,9 +1335,9 @@
wdata.cnc = cdata->sub_connection;
wdata.stmt = stmt;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_prepare_statement, &wdata, NULL, NULL);
- res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, error);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_prepare_statement, &wdata, NULL, NULL);
+ res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, error);
return GPOINTER_TO_INT (res) ? TRUE : FALSE;
}
@@ -1322,7 +1382,9 @@
data->last_inserted_row,
NULL, NULL, NULL,
error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %p\n", __FUNCTION__, retval);
+#endif
if (GDA_IS_DATA_MODEL (retval)) {
/* substitute the GdaDataSelect with a GdaThreadRecordset */
@@ -1334,6 +1396,7 @@
return retval;
}
+
static GObject *
gda_thread_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
GdaStatement *stmt, GdaSet *params,
@@ -1343,40 +1406,103 @@
GdaServerProviderExecCallback async_cb, gpointer cb_data, GError **error)
{
ThreadConnectionData *cdata;
- ExecuteStatementData wdata;
- /* FIXME: handle async requests */
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+ g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE);
+
+ cdata = (ThreadConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
+ return FALSE;
+
if (async_cb) {
- TO_IMPLEMENT;
+ ExecuteStatementData *wdata;
+ wdata = g_new0 (ExecuteStatementData, 1);
+ wdata->prov = cdata->cnc_provider;
+ wdata->cnc = cdata->sub_connection;
+ wdata->stmt = stmt;
+ wdata->params = params;
+ wdata->model_usage = model_usage;
+ wdata->col_types = col_types;
+ wdata->last_inserted_row = last_inserted_row;
+
+ wdata->real_cnc = cnc;
+ wdata->wrapper = cdata->wrapper;
+
+ ThreadConnectionAsyncTask *atd;
+ atd = g_new0 (ThreadConnectionAsyncTask, 1);
+ atd->async_cb = async_cb;
+ atd->cb_data = cb_data;
+ atd->jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_execute_statement, wdata,
+ (GDestroyNotify) g_free, error);
+ cdata->async_tasks = g_slist_append (cdata->async_tasks, atd);
+
+ *task_id = atd->jid;
+
return NULL;
}
+ else {
+ GObject *res;
+ ExecuteStatementData wdata;
+ guint jid;
+
+ wdata.prov = cdata->cnc_provider;
+ wdata.cnc = cdata->sub_connection;
+ wdata.stmt = stmt;
+ wdata.params = params;
+ wdata.model_usage = model_usage;
+ wdata.col_types = col_types;
+ wdata.last_inserted_row = last_inserted_row;
+
+ wdata.real_cnc = cnc;
+ wdata.wrapper = cdata->wrapper;
+
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_execute_statement, &wdata, NULL, NULL);
+ res = (GObject*) gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, error);
+
+ return res;
+ }
+}
+static gboolean
+gda_thread_provider_handle_async (GdaServerProvider *provider, GdaConnection *cnc, GError **error)
+{
+ ThreadConnectionData *cdata;
GObject *res;
+ GError *lerror = NULL;
+ ThreadConnectionAsyncTask *atd;
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
- g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE);
cdata = (ThreadConnectionData*) gda_connection_internal_get_provider_data (cnc);
if (!cdata)
return FALSE;
-
- wdata.prov = cdata->cnc_provider;
- wdata.cnc = cdata->sub_connection;
- wdata.stmt = stmt;
- wdata.params = params;
- wdata.model_usage = model_usage;
- wdata.col_types = col_types;
- wdata.last_inserted_row = last_inserted_row;
-
- wdata.real_cnc = cnc;
- wdata.wrapper = cdata->wrapper;
-
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_execute_statement, &wdata, NULL, NULL);
- res = (GObject*) gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, error);
- return res;
+ if (!cdata->async_tasks)
+ return TRUE;
+
+ atd = (ThreadConnectionAsyncTask*) cdata->async_tasks->data;
+ res = (GObject*) gda_thread_wrapper_fetch_result (cdata->wrapper, FALSE, atd->jid, &lerror);
+ if (res) {
+ atd->async_cb (provider, cnc, atd->jid, res, lerror, atd->cb_data);
+ if (lerror)
+ g_error_free (lerror);
+ g_object_unref (res);
+
+ _ThreadConnectionAsyncTask_free (atd);
+ cdata->async_tasks = g_slist_delete_link (cdata->async_tasks, cdata->async_tasks);
+ }
+
+ return TRUE;
+}
+
+void
+_ThreadConnectionAsyncTask_free (ThreadConnectionAsyncTask *atd)
+{
+ g_free (atd);
}
/*
@@ -1395,7 +1521,9 @@
gboolean retval = FALSE;
retval = PROV_CLASS (data->prov)->xa_funcs->xa_start (data->prov, data->cnc, data->xid,
error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval ? "TRUE" : "FALSE");
+#endif
return GINT_TO_POINTER (retval ? 1 : 0);
}
@@ -1406,6 +1534,7 @@
ThreadConnectionData *cdata;
XaTransactionData wdata;
gpointer res;
+ guint jid;
if (!cnc) {
g_set_error (error, 0, 0, _("A connection is required"));
@@ -1424,9 +1553,9 @@
wdata.cnc = cdata->sub_connection;
wdata.xid = xid;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_xa_start, &wdata, NULL, error);
- res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, NULL);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_xa_start, &wdata, NULL, error);
+ res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
return GPOINTER_TO_INT (res) ? TRUE : FALSE;
}
@@ -1441,7 +1570,9 @@
gboolean retval = FALSE;
retval = PROV_CLASS (data->prov)->xa_funcs->xa_end (data->prov, data->cnc, data->xid,
error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval ? "TRUE" : "FALSE");
+#endif
return GINT_TO_POINTER (retval ? 1 : 0);
}
@@ -1452,6 +1583,7 @@
ThreadConnectionData *cdata;
XaTransactionData wdata;
gpointer res;
+ guint jid;
if (!cnc) {
g_set_error (error, 0, 0, _("A connection is required"));
@@ -1470,9 +1602,9 @@
wdata.cnc = cdata->sub_connection;
wdata.xid = xid;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_xa_end, &wdata, NULL, error);
- res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, NULL);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_xa_end, &wdata, NULL, error);
+ res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
return GPOINTER_TO_INT (res) ? TRUE : FALSE;
}
@@ -1486,7 +1618,9 @@
gboolean retval = FALSE;
retval = PROV_CLASS (data->prov)->xa_funcs->xa_prepare (data->prov, data->cnc, data->xid,
error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval ? "TRUE" : "FALSE");
+#endif
return GINT_TO_POINTER (retval ? 1 : 0);
}
@@ -1497,6 +1631,7 @@
ThreadConnectionData *cdata;
XaTransactionData wdata;
gpointer res;
+ guint jid;
if (!cnc) {
g_set_error (error, 0, 0, _("A connection is required"));
@@ -1515,9 +1650,9 @@
wdata.cnc = cdata->sub_connection;
wdata.xid = xid;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_xa_prepare, &wdata, NULL, error);
- res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, NULL);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_xa_prepare, &wdata, NULL, error);
+ res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
return GPOINTER_TO_INT (res) ? TRUE : FALSE;
}
@@ -1532,7 +1667,9 @@
gboolean retval = FALSE;
retval = PROV_CLASS (data->prov)->xa_funcs->xa_commit (data->prov, data->cnc, data->xid,
error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval ? "TRUE" : "FALSE");
+#endif
return GINT_TO_POINTER (retval ? 1 : 0);
}
@@ -1543,6 +1680,7 @@
ThreadConnectionData *cdata;
XaTransactionData wdata;
gpointer res;
+ guint jid;
if (!cnc) {
g_set_error (error, 0, 0, _("A connection is required"));
@@ -1561,9 +1699,9 @@
wdata.cnc = cdata->sub_connection;
wdata.xid = xid;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_xa_commit, &wdata, NULL, error);
- res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, NULL);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_xa_commit, &wdata, NULL, error);
+ res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
return GPOINTER_TO_INT (res) ? TRUE : FALSE;
}
@@ -1577,7 +1715,9 @@
gboolean retval = FALSE;
retval = PROV_CLASS (data->prov)->xa_funcs->xa_rollback (data->prov, data->cnc, data->xid,
error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval ? "TRUE" : "FALSE");
+#endif
return GINT_TO_POINTER (retval ? 1 : 0);
}
@@ -1588,6 +1728,7 @@
ThreadConnectionData *cdata;
XaTransactionData wdata;
gpointer res;
+ guint jid;
if (!cnc) {
g_set_error (error, 0, 0, _("A connection is required"));
@@ -1606,9 +1747,9 @@
wdata.cnc = cdata->sub_connection;
wdata.xid = xid;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_xa_rollback, &wdata, NULL, error);
- res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, NULL);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_xa_rollback, &wdata, NULL, error);
+ res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
return GPOINTER_TO_INT (res) ? TRUE : FALSE;
}
@@ -1623,7 +1764,9 @@
/* WARNING: function executed in sub thread! */
GList *retval;
retval = PROV_CLASS (data->prov)->xa_funcs->xa_recover (data->prov, data->cnc, error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %p\n", __FUNCTION__, retval);
+#endif
return GINT_TO_POINTER (retval ? 1 : 0);
}
@@ -1634,6 +1777,7 @@
ThreadConnectionData *cdata;
CncProvData wdata;
GList *res;
+ guint jid;
if (!cnc) {
g_set_error (error, 0, 0, _("A connection is required"));
@@ -1650,9 +1794,9 @@
wdata.prov = cdata->cnc_provider;
wdata.cnc = cdata->sub_connection;
- gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_xa_recover, &wdata, NULL, error);
- res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, NULL, NULL);
+ jid = gda_thread_wrapper_execute (cdata->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_xa_recover, &wdata, NULL, error);
+ res = gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
return res;
}
@@ -1665,7 +1809,7 @@
if (!cdata)
return;
- /*disconnect signals handlers */
+ /* disconnect signals handlers */
gint i;
for (i = 0; i < cdata->handlers_ids->len; i++) {
gulong hid = g_array_index (cdata->handlers_ids, gulong, i);
@@ -1677,5 +1821,11 @@
(GdaThreadWrapperVoidFunc) g_object_unref,
cdata->sub_connection, NULL, NULL);
g_object_unref (cdata->wrapper);
+
+ /* free async data */
+ if (cdata->async_tasks) {
+ g_slist_foreach (cdata->async_tasks, (GFunc) _ThreadConnectionAsyncTask_free, NULL);
+ g_slist_free (cdata->async_tasks);
+ }
g_free (cdata);
}
Modified: trunk/libgda/thread-wrapper/gda-thread-provider.h
==============================================================================
--- trunk/libgda/thread-wrapper/gda-thread-provider.h (original)
+++ trunk/libgda/thread-wrapper/gda-thread-provider.h Tue Apr 14 18:49:11 2009
@@ -1,9 +1,7 @@
/* GDA Thread provider
- * Copyright (C) 1998 - 2009 The GNOME Foundation.
+ * Copyright (C) 2009 The GNOME Foundation.
*
* AUTHORS:
- * Rodrigo Moya <rodrigo gnome-db org>
- * Carlos Perellórí<carlos gnome-db org>
* Vivien Malerba <malerba gnome-db org>
*
* This Library is free software; you can redistribute it and/or
@@ -27,7 +25,7 @@
#include <libgda/gda-server-provider.h>
-#define GDA_TYPE_THREAD_PROVIDER (gda_thread_provider_get_type())
+#define GDA_TYPE_THREAD_PROVIDER (_gda_thread_provider_get_type())
#define GDA_THREAD_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GDA_TYPE_THREAD_PROVIDER, GdaThreadProvider))
#define GDA_THREAD_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST (klass, GDA_TYPE_THREAD_PROVIDER, GdaThreadProviderClass))
#define GDA_IS_THREAD_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GDA_TYPE_THREAD_PROVIDER))
@@ -50,7 +48,7 @@
G_BEGIN_DECLS
-GType gda_thread_provider_get_type (void) G_GNUC_CONST;
+GType _gda_thread_provider_get_type (void) G_GNUC_CONST;
G_END_DECLS
Modified: trunk/libgda/thread-wrapper/gda-thread-recordset.c
==============================================================================
--- trunk/libgda/thread-wrapper/gda-thread-recordset.c (original)
+++ trunk/libgda/thread-wrapper/gda-thread-recordset.c Tue Apr 14 18:49:11 2009
@@ -27,7 +27,7 @@
#include "gda-thread-recordset.h"
#include "gda-thread-provider.h"
#include <libgda/providers-support/gda-data-select-priv.h>
-//#include "gda-thread-blob-op.h"
+#include "gda-thread-blob-op.h"
static void gda_thread_recordset_class_init (GdaThreadRecordsetClass *klass);
static void gda_thread_recordset_init (GdaThreadRecordset *recset,
@@ -45,6 +45,8 @@
struct _GdaThreadRecordsetPrivate {
GdaDataModel *sub_model;
GdaThreadWrapper *wrapper;
+ gint nblobs;
+ gint *blobs_conv;
};
static GObjectClass *parent_class = NULL;
@@ -65,6 +67,7 @@
recset->priv = g_new0 (GdaThreadRecordsetPrivate, 1);
recset->priv->sub_model = NULL;
recset->priv->wrapper = NULL;
+ recset->priv->blobs_conv = NULL;
}
static void
@@ -96,11 +99,16 @@
if (recset->priv->sub_model) {
/* unref recset->priv->sub_model in sub thread */
gda_thread_wrapper_execute_void (recset->priv->wrapper,
- (GdaThreadWrapperFunc) g_object_unref,
+ (GdaThreadWrapperVoidFunc) g_object_unref,
recset->priv->sub_model, NULL, NULL);
recset->priv->sub_model = NULL;
g_object_unref (recset->priv->wrapper);
recset->priv->wrapper = NULL;
+
+ if (recset->priv->blobs_conv) {
+ g_free (recset->priv->blobs_conv);
+ recset->priv->blobs_conv = NULL;
+ }
}
g_free (recset->priv);
recset->priv = NULL;
@@ -159,6 +167,23 @@
model->priv->wrapper = g_object_ref (wrapper);
model->priv->sub_model = g_object_ref (sub_model);
+ gint ncols, i, nblobs;
+ gint *blobs_conv = NULL;
+ ncols = gda_data_model_get_n_columns (sub_model);
+ nblobs = 0;
+ for (i = 0; i < ncols; i++) {
+ GdaColumn *col;
+ col = gda_data_model_describe_column (sub_model, i);
+ if (gda_column_get_g_type (col) == GDA_TYPE_BLOB) {
+ if (!blobs_conv)
+ blobs_conv = g_new0 (gint, ncols);
+ blobs_conv [nblobs] = i;
+ nblobs++;
+ }
+ }
+ model->priv->blobs_conv = blobs_conv;
+ model->priv->nblobs = nblobs;
+
COPY_PUBLIC_DATA (sub_model, model);
return GDA_DATA_MODEL (model);
@@ -177,9 +202,14 @@
{
/* WARNING: function executed in sub thread! */
gint retval;
+ gint *res;
retval = DATA_SELECT_CLASS (model)->fetch_nb_rows (model);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %d\n", __FUNCTION__, retval);
- return GINT_TO_POINTER (retval);
+#endif
+ res = g_new (gint, 1);
+ *res = retval;
+ return res;
}
static gint
@@ -187,10 +217,15 @@
{
GdaThreadRecordset *rs = (GdaThreadRecordset*) model;
gint nb;
- gda_thread_wrapper_execute (rs->priv->wrapper,
- (GdaThreadWrapperFunc) sub_thread_fetch_nb_rows,
- rs->priv->sub_model, NULL, NULL);
- nb = GPOINTER_TO_INT (gda_thread_wrapper_fetch_result (rs->priv->wrapper, TRUE, NULL, NULL));
+ gint *res;
+ guint jid;
+ jid = gda_thread_wrapper_execute (rs->priv->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_fetch_nb_rows,
+ rs->priv->sub_model, NULL, NULL);
+
+ res = (gint*) gda_thread_wrapper_fetch_result (rs->priv->wrapper, TRUE, jid, NULL);
+ nb = *res;
+ g_free (res);
COPY_PUBLIC_DATA (rs->priv->sub_model, rs);
return nb;
}
@@ -210,27 +245,53 @@
/* WARNING: function executed in sub thread! */
gboolean retval;
retval = DATA_SELECT_CLASS (data->select)->fetch_random (data->select, data->row, data->rownum, error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval ? "TRUE" : "FALSE");
+#endif
return GINT_TO_POINTER (retval);
}
+static void
+alter_blob_values (GdaThreadRecordset *rs, GdaRow **prow)
+{
+ gint i;
+ for (i = 0; i < rs->priv->nblobs; i++) {
+ GValue *value = gda_row_get_value (*prow, rs->priv->blobs_conv[i]);
+ if (G_VALUE_TYPE (value) == GDA_TYPE_BLOB) {
+ GdaBlob *blob;
+ blob = (GdaBlob*) gda_value_get_blob (value);
+ if (blob->op) {
+ GdaBlobOp *nop;
+ nop = _gda_thread_blob_op_new (rs->priv->wrapper, blob->op);
+ g_object_unref (blob->op);
+ blob->op = nop;
+ }
+ }
+ }
+}
+
static gboolean
gda_thread_recordset_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
{
GdaThreadRecordset *rs = (GdaThreadRecordset*) model;
ThreadData wdata;
gboolean retval;
+ guint jid;
wdata.select = (GdaDataSelect *) rs->priv->sub_model;
wdata.rownum = rownum;
wdata.row = prow;
- gda_thread_wrapper_execute (rs->priv->wrapper,
- (GdaThreadWrapperFunc) sub_thread_fetch_random,
- &wdata, NULL, NULL);
+ jid = gda_thread_wrapper_execute (rs->priv->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_fetch_random,
+ &wdata, NULL, NULL);
- retval = GPOINTER_TO_INT (gda_thread_wrapper_fetch_result (rs->priv->wrapper, TRUE, NULL, error)) ?
+ retval = GPOINTER_TO_INT (gda_thread_wrapper_fetch_result (rs->priv->wrapper, TRUE, jid, error)) ?
TRUE : FALSE;
COPY_PUBLIC_DATA (rs->priv->sub_model, rs);
+
+ if (*prow && rs->priv->blobs_conv)
+ alter_blob_values (rs, prow);
+
return retval;
}
@@ -243,7 +304,9 @@
/* WARNING: function executed in sub thread! */
gboolean retval;
retval = DATA_SELECT_CLASS (data->select)->fetch_next (data->select, data->row, data->rownum, error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval ? "TRUE" : "FALSE");
+#endif
return GINT_TO_POINTER (retval);
}
@@ -253,16 +316,21 @@
GdaThreadRecordset *rs = (GdaThreadRecordset*) model;
ThreadData wdata;
gboolean retval;
+ guint jid;
wdata.select = (GdaDataSelect *) rs->priv->sub_model;
wdata.rownum = rownum;
wdata.row = prow;
- gda_thread_wrapper_execute (rs->priv->wrapper,
- (GdaThreadWrapperFunc) sub_thread_fetch_next,
- &wdata, NULL, NULL);
- retval = GPOINTER_TO_INT (gda_thread_wrapper_fetch_result (rs->priv->wrapper, TRUE, NULL, error)) ?
+ jid = gda_thread_wrapper_execute (rs->priv->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_fetch_next,
+ &wdata, NULL, NULL);
+ retval = GPOINTER_TO_INT (gda_thread_wrapper_fetch_result (rs->priv->wrapper, TRUE, jid, error)) ?
TRUE : FALSE;
COPY_PUBLIC_DATA (rs->priv->sub_model, rs);
+
+ if (*prow && rs->priv->blobs_conv)
+ alter_blob_values (rs, prow);
+
return retval;
}
@@ -275,7 +343,9 @@
/* WARNING: function executed in sub thread! */
gboolean retval;
retval = DATA_SELECT_CLASS (data->select)->fetch_prev (data->select, data->row, data->rownum, error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval ? "TRUE" : "FALSE");
+#endif
return GINT_TO_POINTER (retval);
}
@@ -285,16 +355,21 @@
GdaThreadRecordset *rs = (GdaThreadRecordset*) model;
ThreadData wdata;
gboolean retval;
+ guint jid;
wdata.select = (GdaDataSelect *) rs->priv->sub_model;
wdata.rownum = rownum;
wdata.row = prow;
- gda_thread_wrapper_execute (rs->priv->wrapper,
- (GdaThreadWrapperFunc) sub_thread_fetch_prev,
- &wdata, NULL, NULL);
- retval = GPOINTER_TO_INT (gda_thread_wrapper_fetch_result (rs->priv->wrapper, TRUE, NULL, error)) ?
+ jid = gda_thread_wrapper_execute (rs->priv->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_fetch_prev,
+ &wdata, NULL, NULL);
+ retval = GPOINTER_TO_INT (gda_thread_wrapper_fetch_result (rs->priv->wrapper, TRUE, jid, error)) ?
TRUE : FALSE;
COPY_PUBLIC_DATA (rs->priv->sub_model, rs);
+
+ if (*prow && rs->priv->blobs_conv)
+ alter_blob_values (rs, prow);
+
return retval;
}
@@ -307,7 +382,9 @@
/* WARNING: function executed in sub thread! */
gboolean retval;
retval = DATA_SELECT_CLASS (data->select)->fetch_at (data->select, data->row, data->rownum, error);
+#ifdef GDA_DEBUG_NO
g_print ("/%s() => %s\n", __FUNCTION__, retval ? "TRUE" : "FALSE");
+#endif
return GINT_TO_POINTER (retval);
}
@@ -317,15 +394,20 @@
GdaThreadRecordset *rs = (GdaThreadRecordset*) model;
ThreadData wdata;
gboolean retval;
+ guint jid;
wdata.select = (GdaDataSelect *) rs->priv->sub_model;
wdata.rownum = rownum;
wdata.row = prow;
- gda_thread_wrapper_execute (rs->priv->wrapper,
- (GdaThreadWrapperFunc) sub_thread_fetch_at,
- &wdata, NULL, NULL);
- retval = GPOINTER_TO_INT (gda_thread_wrapper_fetch_result (rs->priv->wrapper, TRUE, NULL, error)) ?
+ jid = gda_thread_wrapper_execute (rs->priv->wrapper,
+ (GdaThreadWrapperFunc) sub_thread_fetch_at,
+ &wdata, NULL, NULL);
+ retval = GPOINTER_TO_INT (gda_thread_wrapper_fetch_result (rs->priv->wrapper, TRUE, jid, error)) ?
TRUE : FALSE;
COPY_PUBLIC_DATA (rs->priv->sub_model, rs);
+
+ if (*prow && rs->priv->blobs_conv)
+ alter_blob_values (rs, prow);
+
return retval;
}
Modified: trunk/libgda/thread-wrapper/gda-thread-wrapper.c
==============================================================================
--- trunk/libgda/thread-wrapper/gda-thread-wrapper.c (original)
+++ trunk/libgda/thread-wrapper/gda-thread-wrapper.c Tue Apr 14 18:49:11 2009
@@ -341,6 +341,7 @@
}
job->shared->current_job = NULL;
shared_data_add_nb_waiting (job->shared, -1);
+ /*g_print ("... done job %d\n", job->job_id);*/
g_async_queue_push (job->reply_queue, res);
}
else
@@ -522,14 +523,14 @@
g_return_val_if_fail (wrapper->priv, 0);
g_return_val_if_fail (func, 0);
- gda_mutex_lock (wrapper->priv->mutex);
-
td = get_thread_data (wrapper);
shared_data_add_nb_waiting (td->shared, 1);
job = g_new0 (Job, 1);
job->type = JOB_TYPE_EXECUTE;
+ gda_mutex_lock (wrapper->priv->mutex);
job->job_id = wrapper->priv->next_job_id++;
+ gda_mutex_unlock (wrapper->priv->mutex);
job->func = func;
job->void_func = NULL;
job->arg = arg;
@@ -538,9 +539,25 @@
job->shared = shared_data_ref (td->shared);
id = job->job_id;
- gda_mutex_unlock (wrapper->priv->mutex);
+ /*g_print ("... submitted job %d\n", id);*/
- g_async_queue_push (wrapper->priv->to_sub_thread, job);
+ if (g_thread_self () == wrapper->priv->sub_thread) {
+ Result *res = g_new0 (Result, 1);
+ res->job = job;
+ res->type = RESULT_TYPE_EXECUTE;
+ job->shared->current_job = job;
+ if (job->func)
+ res->u.exe.result = job->func (job->arg, &(res->u.exe.error));
+ else {
+ res->u.exe.result = NULL;
+ job->void_func (job->arg, &(res->u.exe.error));
+ }
+ job->shared->current_job = NULL;
+ shared_data_add_nb_waiting (job->shared, -1);
+ g_async_queue_push (job->reply_queue, res);
+ }
+ else
+ g_async_queue_push (wrapper->priv->to_sub_thread, job);
return id;
}
@@ -582,14 +599,14 @@
g_return_val_if_fail (wrapper->priv, 0);
g_return_val_if_fail (func, 0);
- gda_mutex_lock (wrapper->priv->mutex);
-
td = get_thread_data (wrapper);
shared_data_add_nb_waiting (td->shared, 1);
job = g_new0 (Job, 1);
job->type = JOB_TYPE_EXECUTE;
+ gda_mutex_lock (wrapper->priv->mutex);
job->job_id = wrapper->priv->next_job_id++;
+ gda_mutex_unlock (wrapper->priv->mutex);
job->func = NULL;
job->void_func = func;
job->arg = arg;
@@ -598,9 +615,25 @@
job->shared = shared_data_ref (td->shared);
id = job->job_id;
- gda_mutex_unlock (wrapper->priv->mutex);
+ /*g_print ("... submitted VOID job %d\n", id);*/
- g_async_queue_push (wrapper->priv->to_sub_thread, job);
+ if (g_thread_self () == wrapper->priv->sub_thread) {
+ Result *res = g_new0 (Result, 1);
+ res->job = job;
+ res->type = RESULT_TYPE_EXECUTE;
+ job->shared->current_job = job;
+ if (job->func)
+ res->u.exe.result = job->func (job->arg, &(res->u.exe.error));
+ else {
+ res->u.exe.result = NULL;
+ job->void_func (job->arg, &(res->u.exe.error));
+ }
+ job->shared->current_job = NULL;
+ shared_data_add_nb_waiting (job->shared, -1);
+ g_async_queue_push (job->reply_queue, res);
+ }
+ else
+ g_async_queue_push (wrapper->priv->to_sub_thread, job);
return id;
}
@@ -627,11 +660,10 @@
g_return_if_fail (wrapper->priv);
gda_mutex_lock (wrapper->priv->mutex);
-
td = g_hash_table_lookup (wrapper->priv->threads_hash, g_thread_self());
+ gda_mutex_unlock (wrapper->priv->mutex);
if (!td) {
/* nothing to be done for this thread */
- gda_mutex_unlock (wrapper->priv->mutex);
return;
}
@@ -667,15 +699,13 @@
if (do_again)
goto again;
}
-
- gda_mutex_unlock (wrapper->priv->mutex);
}
/**
* gda_thread_wrapper_fetch_result
* @wrapper: a #GdaThreadWrapper object
* @may_lock: TRUE if this funct must lock the caller untill a result is available
- * @id: a place to store the job ID of the function which execution has finished
+ * @exp_id: ID of the job for which a result is expected
* @error: a place to store errors, for errors which may have occurred during the execution, or %NULL
*
* Use this method to check if the execution of a function is finished. The function's execution must have
@@ -689,7 +719,7 @@
* Since: 4.2
*/
gpointer
-gda_thread_wrapper_fetch_result (GdaThreadWrapper *wrapper, gboolean may_lock, guint *out_id, GError **error)
+gda_thread_wrapper_fetch_result (GdaThreadWrapper *wrapper, gboolean may_lock, guint exp_id, GError **error)
{
ThreadData *td;
Result *res = NULL;
@@ -697,32 +727,55 @@
g_return_val_if_fail (GDA_IS_THREAD_WRAPPER (wrapper), NULL);
g_return_val_if_fail (wrapper->priv, NULL);
+ g_return_val_if_fail (exp_id > 0, NULL);
gda_mutex_lock (wrapper->priv->mutex);
td = g_hash_table_lookup (wrapper->priv->threads_hash, g_thread_self());
+ gda_mutex_unlock (wrapper->priv->mutex);
if (!td) {
/* nothing to be done for this thread */
- gda_mutex_unlock (wrapper->priv->mutex);
return NULL;
}
- gda_thread_wrapper_iterate (wrapper, may_lock);
- if (td->results) {
- res = RESULT (td->results->data);
- td->results = g_slist_delete_link (td->results, td->results);
- if (!(td->results) &&
- (td->shared->nb_waiting == 0) &&
- (g_async_queue_length (td->from_sub_thread) == 0) &&
- !td->signals_list) {
- /* remove this ThreadData */
- g_hash_table_remove (wrapper->priv->threads_hash, g_thread_self());
+ do {
+ if (td->results) {
+ /* see if we have the result we want */
+ GSList *list;
+ for (list = td->results; list; list = list->next) {
+ res = RESULT (list->data);
+ if (res->job->job_id == exp_id) {
+ /* found it */
+ td->results = g_slist_delete_link (td->results, list);
+ if (!(td->results) &&
+ (td->shared->nb_waiting == 0) &&
+ (g_async_queue_length (td->from_sub_thread) == 0) &&
+ !td->signals_list) {
+ /* remove this ThreadData */
+ gda_mutex_lock (wrapper->priv->mutex);
+ g_hash_table_remove (wrapper->priv->threads_hash, g_thread_self());
+ gda_mutex_unlock (wrapper->priv->mutex);
+ }
+ goto out;
+ }
+ }
}
- }
+
+ if (may_lock)
+ gda_thread_wrapper_iterate (wrapper, TRUE);
+ else {
+ gint len;
+ len = g_slist_length (td->results);
+ gda_thread_wrapper_iterate (wrapper, FALSE);
+ if (g_slist_length (td->results) == len) {
+ res = NULL;
+ break;
+ }
+ }
+ } while (1);
+ out:
if (res) {
g_assert (res->type == RESULT_TYPE_EXECUTE);
- if (out_id)
- *out_id = res->job->job_id;
if (res->u.exe.error) {
g_propagate_error (error, res->u.exe.error);
res->u.exe.error = NULL;
@@ -732,7 +785,6 @@
result_free (res);
}
- gda_mutex_unlock (wrapper->priv->mutex);
return retval;
}
Modified: trunk/libgda/thread-wrapper/gda-thread-wrapper.h
==============================================================================
--- trunk/libgda/thread-wrapper/gda-thread-wrapper.h (original)
+++ trunk/libgda/thread-wrapper/gda-thread-wrapper.h Tue Apr 14 18:49:11 2009
@@ -75,7 +75,7 @@
gpointer arg, GDestroyNotify arg_destroy_func, GError **error);
void gda_thread_wrapper_iterate (GdaThreadWrapper *wrapper, gboolean may_block);
gpointer gda_thread_wrapper_fetch_result (GdaThreadWrapper *wrapper, gboolean may_lock,
- guint *out_id, GError **error);
+ guint exp_id, GError **error);
gint gda_thread_wrapper_get_waiting_size (GdaThreadWrapper *wrapper);
Added: trunk/samples/AsyncExec/Makefile
==============================================================================
--- (empty file)
+++ trunk/samples/AsyncExec/Makefile Tue Apr 14 18:49:11 2009
@@ -0,0 +1,12 @@
+CFLAGS = -Wall -g -DGDA_DISABLE_DEPRECATED `pkg-config --cflags libgda-4.0`
+LDFLAGS = `pkg-config --libs libgda-4.0`
+
+all: example
+
+example: example.c
+ $(CC) -o example example.c $(CFLAGS) $(LDFLAGS)
+
+clean:
+ rm -f *~
+ rm -f *.o
+ rm -f example
Added: trunk/samples/AsyncExec/README
==============================================================================
--- (empty file)
+++ trunk/samples/AsyncExec/README Tue Apr 14 18:49:11 2009
@@ -0,0 +1,61 @@
+Libgda simple example
+=====================
+
+Description:
+------------
+
+The example in this directory illustrate how to use the asynchronous statement execution
+introduced in Libgda 4.2.
+
+Compiling and running:
+----------------------
+
+To compile (make sure Libgda is installed prior to this):
+> make
+
+and to run:
+> ./example
+
+Output:
+-------
+Running should produce the following output:
+
+=========== Async. execution request:
+SELECT * from customers
+Assigned task id: 1
+=========== Async. execution request:
+SELECT * from products LIMIT 2
+Assigned task id: 2
+=========== Async. exececution request:
+SELECT * from customers WHERE id>=##theid::int
+ theid => 6
+Assigned task id: 3
+=========== Waiting for task 2
+Not yet executed...
+=========== Waiting for task 2
+Not yet executed...
+=========== Waiting for task 2
+ref | category | name | price | wh_stored
+----+----------+-----------------+-----------+----------
+1 | 14 | ACADEMY ACADEMY | 25.990000 | 0
+2 | 6 | ACADEMY ACE | 20.990000 | 0
+(2 rows)
+=========== Waiting for task 10
+Task not found error: Can't find task 10
+=========== Waiting for task 1
+id | name | default_served_by | country | city
+---+-----------------+-------------------+---------+-----
+ 2 | Ed Lamton | 4 | SP | MDR
+ 3 | Lew Bonito | 1 | FR | TLS
+ 4 | Mark Lawrencep | NULL | SP | MDR
+ 9 | Greg Popoff | 2 | SP | MDR
+10 | Vladimir Zirkov | 4 | NULL | NULL
+(5 rows)
+=========== Waiting for task 2
+Task not found error: Can't find task 2
+=========== Waiting for task 3
+id | name | default_served_by | country | city
+---+-----------------+-------------------+---------+-----
+ 9 | Greg Popoff | 2 | SP | MDR
+10 | Vladimir Zirkov | 4 | NULL | NULL
+(2 rows)
\ No newline at end of file
Added: trunk/samples/AsyncExec/example.c
==============================================================================
--- (empty file)
+++ trunk/samples/AsyncExec/example.c Tue Apr 14 18:49:11 2009
@@ -0,0 +1,153 @@
+#include <libgda/libgda.h>
+#include <sql-parser/gda-sql-parser.h>
+#include <string.h>
+#include <unistd.h>
+
+static GdaStatement *create_statement (const gchar *sql);
+static void fetch_execute_result (GdaConnection *cnc, guint task_id);
+static guint request_execution (GdaConnection *cnc, const gchar *sql);
+static guint request_execution_with_params (GdaConnection *cnc, const gchar *sql, ...);
+
+int
+main (int argc, char** argv)
+{
+ GdaConnection *cnc;
+ guint id1, id2, id3;
+ GError *error = NULL;
+
+ gda_init ();
+
+ cnc = gda_connection_open_from_dsn ("SalesTest", NULL, GDA_CONNECTION_OPTIONS_THREAD_SAFE, NULL);
+ if (!cnc) {
+ g_print ("Can't open connection: %s\n", error && error->message ? error->message : "No detail");
+ return 1;
+ }
+
+ /* execute */
+ id1 = request_execution (cnc, "SELECT * from customers");
+ id2 = request_execution (cnc, "SELECT * from products LIMIT 2");
+ id3 = request_execution_with_params (cnc, "SELECT * from customers WHERE id>=##theid::int", "theid", "6", NULL);
+
+ /* fetch result */
+ fetch_execute_result (cnc, id2);
+ fetch_execute_result (cnc, 10);
+ fetch_execute_result (cnc, id1);
+ fetch_execute_result (cnc, id2);
+ fetch_execute_result (cnc, id3);
+
+ /*gda_statement_get_parameters (stmt, ¶meters, NULL);*/
+
+ g_object_unref (cnc);
+
+ return 0;
+}
+
+static GdaStatement *
+create_statement (const gchar *sql)
+{
+ GdaSqlParser *parser;
+ GdaStatement *stmt;
+ parser = gda_sql_parser_new ();
+ stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL);
+ g_object_unref (parser);
+ return stmt;
+}
+
+static guint
+request_execution (GdaConnection *cnc, const gchar *sql)
+{
+ GdaStatement *stmt;
+ guint id;
+ GError *error = NULL;
+
+ g_print ("=========== Async. execution request:\n%s\n", sql);
+ stmt = create_statement (sql);
+ id = gda_connection_async_statement_execute (cnc, stmt, NULL, GDA_STATEMENT_MODEL_RANDOM_ACCESS, NULL, FALSE,
+ &error);
+ g_object_unref (stmt);
+ if (id == 0) {
+ g_print ("Can't execute ASYNC: %s\n", error && error->message ? error->message : "No detail");
+ exit (1);
+ }
+ g_print ("Assigned task id: %u\n", id);
+ return id;
+}
+
+/*
+ * ... is a list of (const gchar *name, const gchar *value) couples, terminated by %NULL
+ */
+static guint
+request_execution_with_params (GdaConnection *cnc, const gchar *sql, ...)
+{
+ GdaStatement *stmt;
+ guint id;
+ GError *error = NULL;
+ GdaSet *params;
+ const gchar *pname;
+
+ g_print ("=========== Async. exececution request:\n%s\n", sql);
+ stmt = create_statement (sql);
+ if (! gda_statement_get_parameters (stmt, ¶ms, &error)) {
+ g_print ("Can't get statement's parameters: %s\n", error && error->message ? error->message : "No detail");
+ exit (1);
+ }
+
+ if (params) {
+ va_list ap;
+ va_start (ap, sql);
+ for (pname = va_arg (ap, const gchar *); pname; pname = va_arg (ap, const gchar *)) {
+ const gchar *value;
+ GdaHolder *holder;
+ holder = gda_set_get_holder (params, pname);
+ value = va_arg (ap, const gchar *);
+ if (holder)
+ g_assert (gda_holder_set_value_str (holder, NULL, value, NULL));
+ g_print ("\t%s => %s\n", pname, value);
+ va_end (ap);
+ }
+ }
+
+ id = gda_connection_async_statement_execute (cnc, stmt, params, GDA_STATEMENT_MODEL_RANDOM_ACCESS, NULL, FALSE,
+ &error);
+ if (params)
+ g_object_unref (params);
+ g_object_unref (stmt);
+ if (id == 0) {
+ g_print ("Can't execute ASYNC: %s\n", error && error->message ? error->message : "No detail");
+ exit (1);
+ }
+ g_print ("Assigned task id: %u\n", id);
+ return id;
+}
+
+static void
+fetch_execute_result (GdaConnection *cnc, guint task_id)
+{
+ GObject *result;
+ GError *error = NULL;
+ gint i;
+ for (i = 0; i < 10; i++) {
+ g_print ("=========== Waiting for task %u\n", task_id);
+ result = gda_connection_async_fetch_result (cnc, task_id, NULL, &error);
+ if (result) {
+ if (GDA_IS_DATA_MODEL (result))
+ gda_data_model_dump (GDA_DATA_MODEL (result), NULL);
+ else
+ g_print ("Unknown result: %s\n", G_OBJECT_TYPE_NAME (result));
+ g_object_unref (result);
+ return;
+ }
+ else if (error) {
+ if (error && (error->domain == GDA_CONNECTION_ERROR) &&
+ (error->code == GDA_CONNECTION_TASK_NOT_FOUND_ERROR))
+ g_print ("Task not found error: %s\n", error->message);
+ else
+ g_print ("Execution failed: %s\n", error->message ? error->message : "No detail");
+ return;
+ }
+ else {
+ g_print ("Not yet executed...\n");
+ g_usleep (100000);
+ }
+ }
+}
Modified: trunk/samples/Makefile
==============================================================================
--- trunk/samples/Makefile (original)
+++ trunk/samples/Makefile Tue Apr 14 18:49:11 2009
@@ -1,5 +1,5 @@
SHELL= /bin/sh
-SUBDIRS = BDB DDL DirDataModel F-Spot Report SimpleExample SqlParserConsole TableCopy Virtual XSLT MetaStore Tree SqlBuilder
+SUBDIRS = BDB DDL DirDataModel F-Spot Report SimpleExample SqlParserConsole TableCopy Virtual XSLT MetaStore Tree SqlBuilder AsyncExec
all:
for dir in ${SUBDIRS} ; do ( cd $$dir ; ${MAKE} ) ; done
clean:
Modified: trunk/samples/README
==============================================================================
--- trunk/samples/README (original)
+++ trunk/samples/README Tue Apr 14 18:49:11 2009
@@ -19,5 +19,6 @@
* in MetaStore/: simple example to show how to use and update a GdaMetaStore
* in Tree/: simple example to show how to use the GdaTree object
* in SqlBuilder: simple example to show how to use GdaSqlBuilder object to build various statements
+* in AsyncExec: simple example illustrating how to perform asynchronous statement execution
Good luck and happy hacking!
Modified: trunk/tests/multi-threading/check_wrapper.c
==============================================================================
--- trunk/tests/multi-threading/check_wrapper.c (original)
+++ trunk/tests/multi-threading/check_wrapper.c Tue Apr 14 18:49:11 2009
@@ -178,19 +178,13 @@
/* pick up results */
for (i = 0; i < NCALLS; i++) {
- guint id;
gpointer res;
- res = gda_thread_wrapper_fetch_result (wrapper, TRUE, &id, NULL);
+ res = gda_thread_wrapper_fetch_result (wrapper, TRUE, ids[2*i], NULL);
if (GPOINTER_TO_INT (res) != i + GPOINTER_TO_INT (int_id) * 1000) {
g_print ("Error in %s() for thread %d: sub thread's exec result is wrong\n",
__FUNCTION__, GPOINTER_TO_INT (int_id));
nfailed ++;
}
- if (id != ids[2*i]) {
- g_print ("Error in %s() for thread %d: sub thread's exec result is for wrong ID\n",
- __FUNCTION__, GPOINTER_TO_INT (int_id));
- nfailed ++;
- }
#ifdef PRINT_CALLS
g_print ("<-- Thread %d jobID %u arg %d\n", GPOINTER_TO_INT (int_id), id, i + GPOINTER_TO_INT (int_id) * 1000);
#endif
@@ -199,18 +193,13 @@
gchar *str;
estr = g_strdup_printf ("Hello %d.%d", GPOINTER_TO_INT (int_id), i);
- str = gda_thread_wrapper_fetch_result (wrapper, TRUE, &id, NULL);
+ str = gda_thread_wrapper_fetch_result (wrapper, TRUE, ids[2*i+1], NULL);
if (!str || strcmp (str, estr)) {
g_print ("Error in %s() for thread %d: sub thread's exec result is wrong: got %s, exp: %s\n",
__FUNCTION__, GPOINTER_TO_INT (int_id), str, estr);
nfailed ++;
}
g_free (estr);
- if (id != ids[2*i+1]) {
- g_print ("Error in %s() for thread %d: sub thread's exec result is for wrong ID\n",
- __FUNCTION__, GPOINTER_TO_INT (int_id));
- nfailed ++;
- }
#ifdef PRINT_CALLS
g_print ("<-- Thread %d jobID %u arg %s\n", GPOINTER_TO_INT (int_id), id, str);
#endif
@@ -583,22 +572,16 @@
/* pick up results */
for (i = 0; i < NCALLS; i++) {
- guint id;
gpointer res;
g_signal_emit_by_name (dummy, "sig0", NULL); /* this signal should be ignored */
- res = gda_thread_wrapper_fetch_result (wrapper, TRUE, &id, NULL);
+ res = gda_thread_wrapper_fetch_result (wrapper, TRUE, ids[i], NULL);
if (GPOINTER_TO_INT (res) != INT_TOKEN) {
g_print ("Error in %s() for thread %p: sub thread's exec result is wrong\n",
__FUNCTION__, g_thread_self ());
nfailed ++;
}
- if (id != ids[i]) {
- g_print ("Error in %s() for thread %p: sub thread's exec result is for wrong ID\n",
- __FUNCTION__, g_thread_self ());
- nfailed ++;
- }
#ifdef PRINT_CALLS
g_print ("<-- Thread %p jobID %u arg %d\n", g_thread_self (), id, INT_TOKEN);
#endif
Modified: trunk/tools/test_blob.sh
==============================================================================
--- trunk/tools/test_blob.sh (original)
+++ trunk/tools/test_blob.sh Tue Apr 14 18:49:11 2009
@@ -21,7 +21,7 @@
#prefix=sqlite
rm -f EXPORT_gda_sql_c EXPORT_gda_sql_ico
-./gda-sql-4.0 ${prefix}blobs <<EOF
+./gda-sql-4.1 ${prefix}blobs <<EOF
delete from blobs;
.setex bl gda-sql.c
insert into blobs (id, descr, blob) values (1, 'descr1', ##bl::GdaBlob);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]