[libgda] Major rework of the way multi threading is handled
- From: Vivien Malerba <vivien src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgda] Major rework of the way multi threading is handled
- Date: Wed, 5 Feb 2014 20:58:09 +0000 (UTC)
commit 0111e1411cdaa9bca1169b367ef2ec26338c432b
Author: Vivien Malerba <malerba gnome-db org>
Date: Wed Feb 5 21:41:15 2014 +0100
Major rework of the way multi threading is handled
Most if not all calls using connections can now be made
non blocking for the calling thread
.gitignore | 2 +
configure.ac | 30 +-
control-center/dsn-properties-dialog.c | 2 +-
doc/C/data-model-writing.xml | 6 +-
doc/C/libgda-5.0-docs.sgml | 2 +-
doc/C/libgda-sections.txt | 55 +-
doc/C/libgda.types.in | 3 +-
doc/C/prov-writing-virtual-methods.xml | 98 +-
libgda-report/engine/gda-report-engine.c | 2 +-
libgda-ui/Makefile.am | 4 +-
libgda-ui/demos/main.c | 96 +-
libgda/.gitignore | 3 +
libgda/Makefile.am | 43 +-
libgda/dir-blob-op.c | 15 +-
libgda/gda-blob-op-impl.h | 47 +
libgda/gda-blob-op.c | 314 ++-
libgda/gda-blob-op.h | 10 +-
libgda/gda-connection-internal.h | 43 +-
libgda/gda-connection-private.h | 29 +-
libgda/gda-connection.c | 2107 ++++----------
libgda/gda-connection.h | 106 +-
libgda/gda-data-model.h | 2 +
libgda/gda-data-pivot.c | 2 +-
libgda/gda-data-proxy.c | 6 +-
libgda/gda-data-select.c | 252 ++-
libgda/gda-enums.h | 17 +-
libgda/gda-holder.c | 11 +-
libgda/gda-meta-store.c | 25 +-
libgda/gda-quark-list.c | 26 +-
libgda/gda-server-provider-extra.h | 1 +
libgda/gda-server-provider-impl.h | 491 +++
libgda/gda-server-provider-private.h | 125 +-
libgda/gda-server-provider.c | 3192 ++++++++++++++++++--
libgda/gda-server-provider.h | 351 +---
libgda/gda-statement.c | 17 +-
libgda/gda-util.c | 12 +-
libgda/gda-xa-transaction.c | 159 +-
libgda/libgda.h.in | 1 -
libgda/libgda.symbols | 71 +-
libgda/providers-support/gda-pstmt.c | 2 +
libgda/sql-parser/Makefile.am | 4 +-
libgda/sqlite/gda-sqlite-blob-op.c | 19 +-
libgda/sqlite/gda-sqlite-blob-op.h | 2 +-
libgda/sqlite/gda-sqlite-provider.c | 338 +--
libgda/sqlite/gda-sqlite-recordset.c | 12 +-
libgda/sqlite/gda-sqlite-recordset.h | 4 +-
libgda/sqlite/gda-sqlite.h | 2 +
libgda/sqlite/virtual/gda-vconnection-data-model.c | 2 +-
libgda/sqlite/virtual/gda-vconnection-hub.c | 3 +-
libgda/sqlite/virtual/gda-virtual-connection.c | 71 +-
libgda/sqlite/virtual/gda-virtual-connection.h | 5 +-
libgda/sqlite/virtual/gda-virtual-provider.c | 17 +-
libgda/sqlite/virtual/gda-virtual-provider.h | 8 +-
libgda/sqlite/virtual/gda-vprovider-data-model.c | 116 +-
libgda/sqlite/virtual/gda-vprovider-data-model.h | 1 -
libgda/sqlite/virtual/gda-vprovider-hub.c | 73 +-
libgda/test-cnc-exec.c | 142 +
libgda/test-cnc-meta.c | 147 +
libgda/test-cnc-open.c | 266 ++
libgda/thread-wrapper/.gitignore | 8 +
libgda/thread-wrapper/Makefile.am | 141 +-
libgda/thread-wrapper/dummy-object.c | 1 +
libgda/thread-wrapper/dummy-object.h | 1 +
libgda/thread-wrapper/gda-connect.c | 327 ++
libgda/thread-wrapper/gda-connect.h | 56 +
libgda/thread-wrapper/gda-thread-blob-op.c | 244 --
libgda/thread-wrapper/gda-thread-blob-op.h | 53 -
libgda/thread-wrapper/gda-thread-meta.c | 856 ------
libgda/thread-wrapper/gda-thread-meta.h | 210 --
libgda/thread-wrapper/gda-thread-provider.c | 2181 -------------
libgda/thread-wrapper/gda-thread-provider.h | 58 -
libgda/thread-wrapper/gda-thread-recordset.c | 412 ---
libgda/thread-wrapper/gda-thread-recordset.h | 54 -
libgda/thread-wrapper/gda-thread-wrapper.c | 1626 ----------
libgda/thread-wrapper/gda-thread-wrapper.h | 251 --
libgda/thread-wrapper/gda-worker.c | 1016 +++++++
libgda/thread-wrapper/gda-worker.h | 112 +
libgda/thread-wrapper/itsignaler.c | 984 ++++++
libgda/thread-wrapper/itsignaler.h | 58 +
libgda/thread-wrapper/test-blocking-itsignaler.c | 102 +
libgda/thread-wrapper/test-connect.c | 126 +
libgda/thread-wrapper/test-itsignaler.c | 248 ++
libgda/thread-wrapper/test-raw-itsignaler.c | 187 ++
libgda/thread-wrapper/test-worker.c | 835 +++++
m4/java.m4 | 7 +-
m4/misc.m4 | 21 +
po/POTFILES.in | 3 +-
providers/bdb/gda-bdb-provider.c | 95 +-
providers/bdb/gda-bdb-test.c | 12 +-
providers/firebird/gda-firebird-blob-op.c | 11 +-
providers/firebird/gda-firebird-provider.c | 269 +-
providers/firebird/gda-firebird-recordset.c | 2 +-
providers/firebird/gda-firebird-util.c | 2 +-
providers/firebird/gda-firebird.h | 4 +-
providers/jdbc/gda-jdbc-blob-op.c | 11 +-
providers/jdbc/gda-jdbc-provider.c | 280 +-
providers/jdbc/gda-jdbc-recordset.c | 2 +-
providers/jdbc/gda-jdbc-test.c | 39 +-
providers/jdbc/gda-jdbc.h | 2 +
providers/ldap/gda-ldap-provider.c | 110 +-
providers/ldap/gda-ldap.h | 2 +
providers/mdb/gda-mdb-provider.c | 94 +-
providers/mysql/gda-mysql-blob-op.c | 11 +-
providers/mysql/gda-mysql-provider.c | 299 +--
providers/mysql/gda-mysql-recordset.c | 4 +-
providers/mysql/gda-mysql.h | 2 +
providers/oracle/gda-oracle-blob-op.c | 11 +-
providers/oracle/gda-oracle-provider.c | 322 +-
providers/oracle/gda-oracle-recordset.c | 2 +-
providers/oracle/gda-oracle-util.c | 2 +-
providers/oracle/gda-oracle.h | 2 +
providers/postgres/gda-postgres-blob-op.c | 15 +-
providers/postgres/gda-postgres-handler-bin.c | 2 +-
providers/postgres/gda-postgres-provider.c | 339 +--
providers/postgres/gda-postgres-recordset.c | 4 +-
providers/postgres/gda-postgres.h | 2 +
providers/reuseable/gda-provider-reuseable.h | 2 +-
.../skel-implementation/capi/gda-capi-blob-op.c | 9 +-
.../skel-implementation/capi/gda-capi-provider.c | 370 ++-
.../skel-implementation/capi/gda-capi-recordset.c | 2 +-
providers/skel-implementation/capi/gda-capi.h | 3 +
.../models/gda-models-provider.c | 110 +-
providers/web/gda-web-blob-op.c | 11 +-
providers/web/gda-web-provider.c | 286 +-
providers/web/gda-web-pstmt.c | 2 +-
providers/web/gda-web-util.c | 2 +-
providers/web/gda-web.h | 2 +
samples/DirDataModel/find-duplicates.c | 2 +-
samples/F-Spot/repair-path.c | 2 +-
samples/TableCopy/table-copy-easier.c | 2 +-
samples/Virtual/virtual-test.c | 2 +-
testing/Makefile.am | 2 +-
testing/gda-test-blob.c | 3 +-
testing/gda-test-connection.c | 6 +-
testing/virtual-test-2.c | 2 +-
testing/virtual-test.c | 2 +-
tests/data-models/check_data_proxy.c | 2 +-
tests/data-models/check_model_errors.c | 2 +-
tests/data-models/check_vcnc.c | 31 +-
tests/data-models/check_virtual.c | 4 +-
tests/meta-store/common.c | 3 +-
tests/multi-threading/Makefile.am | 14 +-
tests/multi-threading/check_cnc_lock.c | 2 -
tests/multi-threading/check_threaded_cnc.c | 683 -----
tests/multi-threading/check_wrapper.c | 672 ----
tests/multi-threading/common.c | 2 +-
tests/test-cnc-utils.c | 4 +-
tests/test-sql-renderer.c | 35 +-
tools/browser/auth-dialog.c | 117 +-
tools/browser/browser-connection-priv.h | 19 +-
tools/browser/browser-connection.c | 1207 +-------
tools/browser/browser-connection.h | 57 +-
tools/browser/browser-virtual-connection.c | 116 +-
tools/browser/common/ui-formgrid.c | 239 +-
tools/browser/data-manager/data-source-manager.c | 1 -
tools/browser/data-manager/data-source.c | 122 +-
tools/browser/doc/gda-browser-sections.txt | 4 -
tools/browser/ldap-browser/entry-properties.c | 334 +--
tools/browser/ldap-browser/ldap-search-page.c | 54 +-
tools/browser/ldap-browser/mgr-ldap-entries.c | 56 +-
tools/browser/login-dialog.c | 131 +-
tools/browser/mgr-favorites.c | 27 +-
tools/browser/query-exec/query-console-page.c | 288 +--
tools/browser/schema-browser/table-info.c | 78 +-
tools/browser/support.c | 2 +-
tools/gda-sql.c | 5 +-
tools/tools-favorites.c | 1 -
167 files changed, 12405 insertions(+), 13871 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 52975de..380fa8c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -54,3 +54,5 @@ gtk-doc.make
xmldocs.make
omf.make
ylwrap
+*.log
+*.trs
diff --git a/configure.ac b/configure.ac
index d4c0e93..2fcfe02 100644
--- a/configure.ac
+++ b/configure.ac
@@ -14,6 +14,7 @@ m4_include(m4/firebird.m4)
m4_include(m4/oracle.m4)
m4_include(m4/java.m4)
m4_include(m4/ldap.m4)
+m4_include(m4/misc.m4)
AC_INIT([GNU Data
Access],[major.minor.micro],[https://bugzilla.gnome.org/enter_bug.cgi?product=libgda],[libgda],[http://www.gnome-db.org])
AC_PREREQ([2.68])
@@ -70,6 +71,12 @@ AC_CHECK_TYPE(uint8_t, unsigned char)
AC_CHECK_FUNCS(localtime_r localtime_s)
AC_CHECK_HEADER(sys/mman.h,
AC_CHECK_FUNC(mlock, [AC_DEFINE(USE_MLOCK, 1, [Use POSIX memory locking])]))
+AC_CHECK_FUNC(fork, [AC_DEFINE(HAVE_FORK, 1, [Have the fork() function])])
+CHECK_FD_CLOEXEC([AC_DEFINE(
+ [HAVE_FD_CLOEXEC],
+ [1],
+ [Whether FD_CLOEXEC is defined.])
+ ])
GDA_BUILDDATE=`date '+%F'`
AC_SUBST(GDA_BUILDDATE, $GDA_BUILDDATE)
@@ -143,7 +150,17 @@ dnl ******************************
dnl glib utilities
dnl ******************************
AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal)
+if test -z "$GLIB_GENMARSHAL"; then
+ AC_MSG_ERROR([glib-genmarshal not found])
+fi
+AC_PATH_PROG(GLIB_MKENUMS, glib-mkenums)
+if test -z "$GLIB_MKENUMS"; then
+ AC_MSG_ERROR([glib-mkenums not found])
+fi
AC_PATH_PROG(GLIB_COMPILE_RESOURCES, glib-compile-resources)
+if test -z "$GLIB_COMPILE_RESOURCES"; then
+ AC_MSG_ERROR([glib-compile-resources not found])
+fi
dnl ******************************
dnl Translations
@@ -368,6 +385,7 @@ case "$host" in
AC_SUBST(WINDRES)
AC_CHECK_TOOL(DLLTOOL, dlltool, dlltool)
AC_SUBST(DLLTOOL)
+ COREDEPS_LIBS="$COREDEPS_LIBS -lwsock32 -lws2_32"
;;
*-*-darwin*)
dnl Darwin based distributions (including Mac OS X)
@@ -545,7 +563,7 @@ fi
if test "x$enable_vala" = "xyes"
then
AM_PROG_VALAC([0.17.7])
- VAPIGEN_CHECK([0.17.7],[0.18],,no)
+ VAPIGEN_CHECK([0.17.7],[0.22],,no)
else
AM_CONDITIONAL(ENABLE_VAPIGEN,false)
fi
@@ -823,6 +841,16 @@ fi
AM_CONDITIONAL(HISTORY_LIB, test ! "x$HISTORY_LIB" = "x")
AC_SUBST(HISTORY_LIB)
+dnl *****************
+dnl Check for eventfd
+dnl *****************
+AC_ARG_ENABLE([eventfd], [AS_HELP_STRING([--disable-eventfd], [disable eventfd [default=no]])],
+ [disable_eventfd=yes], [disable_eventfd=no])
+
+if test "x$disable_eventfd" != "xyes"; then
+ AC_CHECK_HEADERS(sys/eventfd.h,
+ [AC_DEFINE(HAVE_EVENTFD, 1, [Have eventfd extension.])])
+fi
dnl
dnl TERMIOS.H
diff --git a/control-center/dsn-properties-dialog.c b/control-center/dsn-properties-dialog.c
index 06705d1..1c58e0f 100644
--- a/control-center/dsn-properties-dialog.c
+++ b/control-center/dsn-properties-dialog.c
@@ -222,7 +222,7 @@ dsn_properties_dialog (GtkWindow *parent, const gchar *dsn)
GTK_DIALOG_MODAL,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"<b>%s</b>",
_("Connection successfully opened!"));
- gda_connection_close (cnc);
+ gda_connection_close (cnc, NULL);
}
else {
msgdialog = gtk_message_dialog_new_with_markup (test_dialog ?
GTK_WINDOW (test_dialog) : parent,
diff --git a/doc/C/data-model-writing.xml b/doc/C/data-model-writing.xml
index 1739b53..6024514 100644
--- a/doc/C/data-model-writing.xml
+++ b/doc/C/data-model-writing.xml
@@ -12,12 +12,16 @@
<para>
Implementing a new <link linkend="GdaDataModel">GdaDataModel</link> is simply a matter of
creating a new GObject which implements the <link linkend="GdaDataModel">GdaDataModel</link>
- interface, which is described below. Thos new class needs to inherit GObject, but needs not
+ interface, which is described below. This new class needs to inherit GObject, but needs not
be direct descendant of it. The way to subclass an object using GLib
is not covered in this documentation, for this matter reref to
<link linkend="howto-gobject-code">GObject's documentation</link>, or
<ulink url="http://developer.gnome.org/gobject/stable/howto-gobject.html">online</ulink>.
</para>
+ <para>
+ Note that all the data models need to implement their lockung mechanism to be thread safe (i.e.
+ to be useable from several threads simultaneously).
+ </para>
<sect2 id="gda-data-model-writing-virtual-methods">
<title>Virtual methods</title>
diff --git a/doc/C/libgda-5.0-docs.sgml b/doc/C/libgda-5.0-docs.sgml
index 8502b68..da5d0fd 100644
--- a/doc/C/libgda-5.0-docs.sgml
+++ b/doc/C/libgda-5.0-docs.sgml
@@ -1115,7 +1115,7 @@ g_object_unref (store);
<title>Multi threading</title>
<xi:include href="xml/gda-mutex.xml"/>
<xi:include href="xml/gda-lockable.xml"/>
- <xi:include href="xml/gda-thread-wrapper.xml"/>
+ <xi:include href="xml/gda-worker.xml"/>
</chapter>
<chapter id="misc">
diff --git a/doc/C/libgda-sections.txt b/doc/C/libgda-sections.txt
index 1e17549..5626022 100644
--- a/doc/C/libgda-sections.txt
+++ b/doc/C/libgda-sections.txt
@@ -108,15 +108,18 @@ GdaConnection
GdaConnectionOptions
GdaConnectionError
GDA_CONNECTION_ERROR
-gda_connection_open_from_dsn
-gda_connection_open_from_string
gda_connection_new_from_dsn
gda_connection_new_from_string
gda_connection_open
+GdaConnectionOpenFunc
+gda_connection_open_async
gda_connection_close
gda_connection_close_no_warning
gda_connection_is_opened
<SUBSECTION>
+gda_connection_set_main_context
+gda_connection_get_main_context
+<SUBSECTION>
gda_connection_create_parser
gda_connection_value_to_sql_string
gda_connection_quote_sql_identifier
@@ -695,7 +698,6 @@ gda_vprovider_hub_get_type
<TITLE>GdaVirtualConnection</TITLE>
GdaVirtualConnection
gda_virtual_connection_open
-gda_virtual_connection_open_extended
<SUBSECTION>
gda_virtual_connection_internal_set_provider_data
gda_virtual_connection_internal_get_provider_data
@@ -1619,7 +1621,6 @@ gda_server_provider_find_file
gda_server_provider_load_file_contents
<SUBSECTION>
gda_connection_internal_set_provider_data
-gda_connection_internal_get_provider_data
gda_connection_internal_get_provider_data_error
<SUBSECTION>
gda_connection_add_event
@@ -1904,33 +1905,25 @@ gda_sql_builder_get_type
</SECTION>
<SECTION>
-<FILE>gda-thread-wrapper</FILE>
-<TITLE>GdaThreadWrapper</TITLE>
-<INCLUDE>libgda/thread-wrapper/gda-thread-wrapper.h</INCLUDE>
-GdaThreadWrapper
-gda_thread_wrapper_new
-GdaThreadNotification
-GdaThreadNotificationType
-gda_thread_wrapper_get_io_channel
-gda_thread_wrapper_unset_io_channel
-GdaThreadWrapperFunc
-gda_thread_wrapper_execute
-GdaThreadWrapperVoidFunc
-gda_thread_wrapper_execute_void
-gda_thread_wrapper_cancel
-gda_thread_wrapper_iterate
-gda_thread_wrapper_fetch_result
-gda_thread_wrapper_get_waiting_size
-GdaThreadWrapperCallback
-gda_thread_wrapper_connect_raw
-gda_thread_wrapper_disconnect
-gda_thread_wrapper_steal_signal
-<SUBSECTION Standard>
-GDA_THREAD_WRAPPER
-GDA_THREAD_WRAPPER_GET_CLASS
-GDA_IS_THREAD_WRAPPER
-GDA_TYPE_THREAD_WRAPPER
-gda_thread_wrapper_get_type
+<FILE>gda-worker</FILE>
+<TITLE>GdaWorker</TITLE>
+GdaWorker
+gda_worker_new
+gda_worker_ref
+gda_worker_unref
+gda_worker_kill
+<SUBSECTION>
+GdaWorkerFunc
+gda_worker_submit_job
+gda_worker_fetch_job_result
+gda_worker_cancel_job
+gda_worker_forget_job
+gda_worker_do_job
+gda_worker_wait_job
+gda_worker_thread_is_worker
+<SUBSECTION>
+GdaWorkerCallback
+gda_worker_set_callback
</SECTION>
<SECTION>
diff --git a/doc/C/libgda.types.in b/doc/C/libgda.types.in
index 1e81e43..1a63349 100644
--- a/doc/C/libgda.types.in
+++ b/doc/C/libgda.types.in
@@ -1,7 +1,7 @@
#include <libgda/libgda.h>
#include <libgda/gda-blob-op.h>
#include <libgda/sql-parser/gda-sql-parser.h>
-#include <libgda/thread-wrapper/gda-thread-wrapper.h>
+#include <libgda/thread-wrapper/gda-worker.h>
#include <virtual/libgda-virtual.h>
#include <engine/gda-report-engine.h>
#include <gda-report-document.h>
@@ -67,4 +67,3 @@ gda_tree_mgr_select_get_type
gda_tree_mgr_tables_get_type
gda_tree_node_get_type
gda_sql_builder_get_type
-gda_thread_wrapper_get_type
diff --git a/doc/C/prov-writing-virtual-methods.xml b/doc/C/prov-writing-virtual-methods.xml
index 6901635..7ad5f21 100644
--- a/doc/C/prov-writing-virtual-methods.xml
+++ b/doc/C/prov-writing-virtual-methods.xml
@@ -12,7 +12,7 @@
</para>
<para>
Virtual providers are database providers when the database engine accessed does not support SQL (or
- supports it poorly), such as Berkeley databases or MDB (or even LDAP). These provider's implementation's
+ supports it poorly), such as Berkeley databases, MDB, or LDAP. These provider's implementation's
design is to create <link linkend="GdaDataModel">GdaDataModel</link> data model objects and make
each of them appear as a named table once the connection is opened. For example the MDB provider creates
a read-only data model for each table in an MDB file and make it appear using the original table
@@ -32,53 +32,39 @@
<sect1>
<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 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.
+ Since version 6, all the provider's code is executed in a <link linkend="GdaWorker">GdaWorker</link>'s
worker thread
+ and will not block the user thread (refer to
+ <link linkend="gda-connection-set-main-context">gda_connection_set_main_context()</link>'s
documentation). Normally
+ each connection is associated with such a worker thread and any provider code for that connection will
be executed in
+ the context of that thread.
</para>
<para>
- 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>
- with the <parameter>cb_data</parameter> as last parameters.
+ The database provider can however decide, by the way the <link
linkend="prov-create-worker">create_worker()</link> is
+ implemented, if each connection can have its own <link linkend="GdaWorker">GdaWorker</link> object, or
if all the
+ connections share the same object (in which case any provider code will only be called within the
context of that
+ <link linkend="GdaWorker">GdaWorker</link>'s working thread).
</para>
</sect1>
<sect1>
<title>Multi threaded environment</title>
<para>
- Each database provider should be usable in a multi threaded environment, even if they impose some
restrictions
- as to how they can be used in such an environment. The &LIBGDA;'s framework provides some locking
mechanism which
- is:
- <itemizedlist>
- <listitem><para>if multi threading cannot be supported at all (for example if the client library
internally
- used by the provider does not support it), then the provider's
- class implementation should set the class's <structfield>limiting_thread</structfield> attribute
to:
- the GDA_SERVER_PROVIDER_UNDEFINED_LIMITING_THREAD constant.
- This constant will be resolved at run time as the thread which creates the 1st connection using
that
- provider.</para>
- </listitem>
- <listitem><para>if multi threading is supported but any connection (or related object) can only be
- used by the thread in which it was created, then for each opened connection, the
- "<link linkend="GdaConnection--thread-owner">thread-owner</link>" connection's property
- must be set to the current thread (and other related objects must be locked in a similar
way)</para>
- </listitem>
- <listitem><para>if no locking is done, then the provider is assumed to support full multi threading
access,
- in this case make sure to set class's <structfield>limiting_thread</structfield> attribute to the
NULL constant.</para>
- </listitem>
- </itemizedlist>
+ Since version 6, the connections are fully thread safe (i.e. can be created and used by any thread)
for any
+ kind of connection.
+ </para>
+ <para>
+ FIXME: document object which implement the <link linkend="GdaLockable">GdaLockable</link> and objects
which don't (and are not thread safe).
</para>
<para>
- Note that the default provider's class value for the <structfield>limiting_thread</structfield> is
safely set to the
- GDA_SERVER_PROVIDER_UNDEFINED_LIMITING_THREAD constant.
+ Each time a <link linkend="GdaConnection">GdaConnection</link> is passed as an argument of any virtual
function
+ implemented by the provider, the connection will have been locked, so no other thread can modify it.
+ </para>
+ <para>
+ Note that any of the provider specific code will only ever be executed within the worker thread of a
+ <link linkend="GdaWorker">GdaWorker</link> object created by <link
linkend="prov-create-worker">create_worker()</link>,
+ except, of course, for that method's code which will be executed from within any thread. Also note that
+ no other code than the provider's code will ever be executed from within the worker thread (and some
code from
+ the GdaServerProvider object itself to do the binding).
</para>
</sect1>
@@ -95,11 +81,13 @@
</sect2>
<sect2 id="prov-get-server-version">
<title>get_server_version() - mandatory</title>
- <para>This method returns the version of the database server to which a connection is opened</para>
+ <para>This method returns the version of the database server to which a connection is opened. The
connection argument will always be non NULL
+ and in an opened state.</para>
</sect2>
<sect2>
- <title>supports_feature()</title>
- <para>This method allows one to ask the provider if some specific features are available</para>
+ <title>supports_feature() - mandatory</title>
+ <para>This method allows one to ask the provider if some specific features are available. The
connection argument may be NULL or not
+ NULL but in an opened state.</para>
</sect2>
</sect1>
@@ -128,7 +116,7 @@
</para>
<para>
The connection specific data for the database API can be retrieved using the
- <link
linkend="gda-connection-internal-get-provider-data">gda_connection_internal_get_provider_data()</link> method.
+ <link
linkend="gda-connection-internal-get-provider-data-error">gda_connection_internal_get_provider_data_error()</link>
method.
</para>
</sect2>
<sect2>
@@ -149,24 +137,26 @@
Implementing these methods is not mandatory, and virtual provider's implementation should not
implement them.
</para>
<sect2>
- <title>supports_operation()</title>
+ <title>supports_operation() - optional</title>
<para>
This virtual method tells if a particular DDL query type is supported (DDL query types are identified
as
- <link linkend="GdaServerOperationType">GdaServerOperationType</link> enums).
+ <link linkend="GdaServerOperationType">GdaServerOperationType</link> enums). The connection argument
may be NULL
+ or not NULL but in an opened state.
</para>
</sect2>
<sect2>
- <title>create_operation()</title>
+ <title>create_operation() - optional</title>
<para>
This virtual method is used to create and initialize a <link
linkend="GdaServerOperation">GdaServerOperation</link>
- object.
+ object. The connection argument may be NULL or not NULL but in an opened state.
</para>
</sect2>
<sect2>
- <title>render_operation()</title>
+ <title>render_operation() - optional</title>
<para>
This virtual method uses the information stored in a <link
linkend="GdaServerOperation">GdaServerOperation</link> object
- to create the SQL statement(s) which would be executed if the operation was performed.
+ to create the SQL statement(s) which would be executed if the operation was performed. The connection
argument may be NULL or not
+ NULL but in an opened state.
</para>
<para>
Note: more than one SQL statement may be returned by this method
@@ -176,9 +166,12 @@
</para>
</sect2>
<sect2>
- <title>perform_operation()</title>
+ <title>perform_operation() - optional</title>
<para>
This virtual method "performs" (execute) a <link
linkend="GdaServerOperation">GdaServerOperation</link> object.
+ The connection argument may be NULL or not NULL but in an opened state. If this method is not
defined, but the create_operation() one
+ is defined, then the default rendering and executing is done (with the information in the
+ <link linkend="GdaServerOperation">GdaServerOperation</link> object)
</para>
</sect2>
</sect1>
@@ -315,11 +308,14 @@
object is responsible of the conversions.
</para>
<sect2>
- <title>get_data_handler()</title>
+ <title>get_data_handler() - optional</title>
<para>
This method returns a <link linkend="GdaDataHandler">GdaDataHandler</link> for the requested data
type. It should
only instantiate each <link linkend="GdaDataHandler">GdaDataHandler</link> once and reuse it if the
same request happens
- (the returned object will not be modified).
+ (the returned object will not be modified). The connection argument may be NULL or not NULL but in an
opened state.
+ </para>
+ <para>
+ If the GType is G_TYPE_INVALID, then this method should consider the dbms_type argument; otherwise it
should ignore it.
</para>
<para>
This method is called by both
diff --git a/libgda-report/engine/gda-report-engine.c b/libgda-report/engine/gda-report-engine.c
index 2ab60bf..92f9f01 100644
--- a/libgda-report/engine/gda-report-engine.c
+++ b/libgda-report/engine/gda-report-engine.c
@@ -1120,7 +1120,7 @@ evaluate_expression (GdaReportEngine *engine, RunContext *context, const gchar *
if (!provider)
provider = gda_vprovider_data_model_new ();
- vcnc = gda_virtual_connection_open (provider, error);
+ vcnc = gda_virtual_connection_open (provider, GDA_CONNECTION_OPTIONS_NONE, error);
if (! vcnc) {
g_mutex_unlock (&init_mutex);
return NULL;
diff --git a/libgda-ui/Makefile.am b/libgda-ui/Makefile.am
index 27803d6..0f011b0 100644
--- a/libgda-ui/Makefile.am
+++ b/libgda-ui/Makefile.am
@@ -83,7 +83,7 @@ gdaui-enum-types.h: s-enum-types-h
@true
s-enum-types-h: @REBUILD@ $(ui_headers) Makefile
- ( cd $(srcdir) && glib-mkenums \
+ ( cd $(srcdir) && $(GLIB_MKENUMS) \
--fhead "#ifndef __LIBGDAUI_ENUM_TYPES_H__\n#define
__LIBGDAUI_ENUM_TYPES_H__\n\n#include <glib-object.h>\n\nG_BEGIN_DECLS\n" \
--vhead "GType @enum_name _get_type (void);\n#define GDAUI_TYPE_ ENUMSHORT@
(@enum_name _get_type())\n" \
--ftail "G_END_DECLS\n\n#endif /* __LIBGDAUI_ENUM_TYPES_H__ */" \
@@ -96,7 +96,7 @@ gdaui-enum-types.c: s-enum-types-c
@true
s-enum-types-c: @REBUILD@ $(ui_headers) Makefile
- ( cd $(srcdir) && glib-mkenums \
+ ( cd $(srcdir) && $(GLIB_MKENUMS) \
--fhead "#include <libgda-ui/libgda-ui.h>\n" \
--fhead "#include <glib-object.h>" \
--vhead "GType\n enum_name@_get_type (void)\n{\n static GType etype = 0;\n if
(etype == 0) {\n static const G Type@Value values[] = {" \
diff --git a/libgda-ui/demos/main.c b/libgda-ui/demos/main.c
index adf0aef..f26973d 100644
--- a/libgda-ui/demos/main.c
+++ b/libgda-ui/demos/main.c
@@ -719,10 +719,17 @@ create_tree (void)
GTK_POLICY_AUTOMATIC);
gtk_container_add (GTK_CONTAINER (scrolled_window), tree_view);
+ GtkWidget *hbox, *spin;
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
label = gtk_label_new ("Widget (double click for demo)");
+ gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
+ spin = gtk_spinner_new ();
+ gtk_spinner_start (GTK_SPINNER (spin));
+ gtk_box_pack_start (GTK_BOX (hbox), spin, FALSE, FALSE, 10);
+ gtk_widget_show_all (hbox);
box = gtk_notebook_new ();
- gtk_notebook_append_page (GTK_NOTEBOOK (box), scrolled_window, label);
+ gtk_notebook_append_page (GTK_NOTEBOOK (box), scrolled_window, hbox);
gtk_widget_grab_focus (tree_view);
@@ -736,11 +743,9 @@ main (int argc, char **argv)
GtkWidget *notebook;
GtkWidget *hbox;
GtkWidget *tree;
- GtkTextTag *tag;
GError *error = NULL;
gchar *full_filename, *dirname;
gchar *cncstring;
- GtkWidget *msg;
gchar *str;
GdaMetaStore *mstore;
@@ -791,6 +796,13 @@ main (int argc, char **argv)
if (! full_filename)
gda_connection_update_meta_store (demo_cnc, NULL, NULL);
+ /* set main context for connection */
+ GMainContext *context;
+ context = g_main_context_ref_thread_default ();
+ gda_connection_set_main_context (demo_cnc, context);
+ g_main_context_unref (context);
+ g_object_set (demo_cnc, "execution-slowdown", 1000000, NULL);
+
/* Initialize parser object */
demo_parser = gda_connection_create_parser (demo_cnc);
if (!demo_parser)
@@ -818,50 +830,50 @@ main (int argc, char **argv)
create_text (&source_buffer, TRUE),
gtk_label_new_with_mnemonic ("_Source"));
- tag = gtk_text_buffer_create_tag (info_buffer, "title",
- "font", "Sans 18",
- NULL);
-
- tag = gtk_text_buffer_create_tag (source_buffer, "comment",
- "foreground", "DodgerBlue",
- NULL);
- tag = gtk_text_buffer_create_tag (source_buffer, "type",
- "foreground", "ForestGreen",
- NULL);
- tag = gtk_text_buffer_create_tag (source_buffer, "string",
- "foreground", "RosyBrown",
- "weight", PANGO_WEIGHT_BOLD,
- NULL);
- tag = gtk_text_buffer_create_tag (source_buffer, "control",
- "foreground", "purple",
- NULL);
- tag = gtk_text_buffer_create_tag (source_buffer, "preprocessor",
- "style", PANGO_STYLE_OBLIQUE,
- "foreground", "burlywood4",
- NULL);
- tag = gtk_text_buffer_create_tag (source_buffer, "function",
- "weight", PANGO_WEIGHT_BOLD,
- "foreground", "DarkGoldenrod4",
- NULL);
+ gtk_text_buffer_create_tag (info_buffer, "title",
+ "font", "Sans 18",
+ NULL);
+ gtk_text_buffer_create_tag (source_buffer, "comment",
+ "foreground", "DodgerBlue",
+ NULL);
+ gtk_text_buffer_create_tag (source_buffer, "type",
+ "foreground", "ForestGreen",
+ NULL);
+ gtk_text_buffer_create_tag (source_buffer, "string",
+ "foreground", "RosyBrown",
+ "weight", PANGO_WEIGHT_BOLD,
+ NULL);
+ gtk_text_buffer_create_tag (source_buffer, "control",
+ "foreground", "purple",
+ NULL);
+ gtk_text_buffer_create_tag (source_buffer, "preprocessor",
+ "style", PANGO_STYLE_OBLIQUE,
+ "foreground", "burlywood4",
+ NULL);
+ gtk_text_buffer_create_tag (source_buffer, "function",
+ "weight", PANGO_WEIGHT_BOLD,
+ "foreground", "DarkGoldenrod4",
+ NULL);
- gtk_window_set_default_size (GTK_WINDOW (window), 600, 700);
+ gtk_window_set_default_size (GTK_WINDOW (window), 700, 700);
gtk_widget_show_all (window);
load_file (gdaui_demos[0].filename);
- full_filename = demo_find_file ("demo_db.db", NULL);
- msg = gtk_message_dialog_new_with_markup (GTK_WINDOW (window), GTK_DIALOG_MODAL,
- GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
- _("<b><big>Note:\n</big></b>Many of the demonstrated items
use an\n"
- "opened connection to the SQLite using the\n"
- "'%s' file.\n\n"
- "In the source code shown here, the <i>demo_cnc</i> and
\n"
- "<i>demo_parser</i> objects are created by the framework
and\n"
- "made available to all the demonstrated items."),
full_filename);
- g_free (full_filename);
- g_signal_connect_swapped (msg, "response",
- G_CALLBACK (gtk_widget_destroy), msg);
- gtk_widget_show (msg);
+
+ if (! g_getenv ("NO_DEMO_NOTICE")) {
+ GtkWidget *msg;
+ full_filename = demo_find_file ("demo_db.db", NULL);
+ msg = gtk_message_dialog_new_with_markup (GTK_WINDOW (window), GTK_DIALOG_MODAL,
+ GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
+ _("<b><big>Note:\n</big></b>Many of the
demonstrated items use an opened connection to the SQLite using the '%s' file.\n\n"
+ "In the source code shown here, the
<i>demo_cnc</i> and <i>demo_parser</i> objects are created by the framework and made available to all the
demonstrated items.\n\n"
+ "To illustrate that calls are non blocking, there
is a spinner at the top (which must never stop spinning), and a 1 second delay has been added whenever the
connection is used."), full_filename);
+ g_free (full_filename);
+ g_signal_connect_swapped (msg, "response",
+ G_CALLBACK (gtk_widget_destroy), msg);
+ gtk_widget_show (msg);
+ }
gtk_main ();
diff --git a/libgda/.gitignore b/libgda/.gitignore
index 64a3184..0534d7a 100644
--- a/libgda/.gitignore
+++ b/libgda/.gitignore
@@ -9,3 +9,6 @@ libgda.def
Gda-5.0.gir
Gda-5.0.typelib
*.vapi
+test-cnc-open
+test-cnc-exec
+test-cnc-meta
\ No newline at end of file
diff --git a/libgda/Makefile.am b/libgda/Makefile.am
index 45f96cd..c3ad2c4 100644
--- a/libgda/Makefile.am
+++ b/libgda/Makefile.am
@@ -2,6 +2,9 @@ QUIET_GEN = $(Q:@= echo ' GEN '$@;)
lib_LTLIBRARIES = libgda-5.0.la
+check_PROGRAMS = test-cnc-open test-cnc-exec test-cnc-meta
+TESTS = test-cnc-open test-cnc-exec test-cnc-meta
+
if ENABLE_VALA_EXTENSIONS
VALA_EXTENSIONS= . data
endif
@@ -90,6 +93,7 @@ gda_headers = \
gda-server-provider.h \
gda-server-provider-extra.h \
gda-server-provider-private.h \
+ gda-server-provider-impl.h \
gda-statement.h \
gda-statement-extra.h \
gda-sql-builder.h \
@@ -115,6 +119,7 @@ gda_built_sources= \
gda_sources= \
gda-batch.c \
gda-blob-op.c \
+ gda-blob-op-impl.h \
gda-column.c \
gda-config.c \
gda-connection.c \
@@ -192,15 +197,17 @@ libgda_sources = \
$(gda_built_sources) \
$(gda_sources)
+gda_enum_header_files = gda-connection.h gda-enums.h
+
gda-enum-types.h: s-enum-types-h
@true
-s-enum-types-h: @REBUILD@ $(gda_headers) Makefile
- ( cd $(srcdir) && glib-mkenums \
+s-enum-types-h: @REBUILD@ $(gda_enum_header_files) Makefile
+ ( cd $(srcdir) && $(GLIB_MKENUMS) \
--fhead "#ifndef __LIBGDA_ENUM_TYPES_H__\n#define __LIBGDA_ENUM_TYPES_H__\n\n#include
<glib-object.h>\n\nG_BEGIN_DECLS\n" \
--vhead "GType @enum_name _get_type (void);\n#define GDA_TYPE_ ENUMSHORT@ (@enum_name
_get_type())\n" \
--ftail "G_END_DECLS\n\n#endif /* __LIBGDA_ENUM_TYPES_H__ */" \
- $(gda_headers)) > tmp-gda-enum-types.h \
+ $(gda_enum_header_files)) > tmp-gda-enum-types.h \
&& (cmp -s tmp-gda-enum-types.h gda-enum-types.h || cp tmp-gda-enum-types.h gda-enum-types.h ) \
&& rm -f tmp-gda-enum-types.h \
&& echo timestamp > $(@F)
@@ -208,14 +215,14 @@ s-enum-types-h: @REBUILD@ $(gda_headers) Makefile
gda-enum-types.c: s-enum-types-c
@true
-s-enum-types-c: @REBUILD@ $(gda_headers) Makefile
- ( cd $(srcdir) && glib-mkenums \
+s-enum-types-c: @REBUILD@ $(gda_enum_header_files) Makefile
+ ( cd $(srcdir) && $(GLIB_MKENUMS) \
--fhead "#include <libgda/libgda.h>\n" \
--fhead "#include <glib-object.h>" \
--vhead "GType\n enum_name@_get_type (void)\n{\n static GType etype = 0;\n if
(etype == 0) {\n static const G Type@Value values[] = {" \
--vprod " { @VALUENAME@, \"@VALUENAME \", \"@valuenick \" }," \
--vtail " { 0, NULL, NULL }\n };\n etype = g_ type@_register_static
(\"@EnumName \", values);\n }\n return etype;\n}\n" \
- $(gda_headers)) > tmp-gda-enum-types.c \
+ $(gda_enum_header_files)) > tmp-gda-enum-types.c \
&& (cmp -s tmp-gda-enum-types.c gda-enum-types.c || cp tmp-gda-enum-types.c gda-enum-types.c ) \
&& rm -f tmp-gda-enum-types.c \
&& echo timestamp > $(@F)
@@ -314,8 +321,8 @@ psupport = \
providers-support/gda-pstmt.c
threadwrapper = \
- thread-wrapper/gda-thread-wrapper.h \
- thread-wrapper/gda-thread-wrapper.c
+ thread-wrapper/gda-worker.h \
+ thread-wrapper/gda-worker.c
sqlparser = \
sql-parser/gda-sql-parser.h \
@@ -386,3 +393,23 @@ clean-local:
then \
rm -f $(gir_DATA) $(vapi_DATA); \
fi
+
+
+test_cnc_open_SOURCES = test-cnc-open.c
+test_cnc_open_LDADD = \
+ $(top_builddir)/libgda/libgda-5.0.la \
+ $(COREDEPS_LIBS)
+
+test_cnc_exec_SOURCES = test-cnc-exec.c
+test_cnc_exec_CFLAGS = \
+ -DROOT_DIR=\""$(top_srcdir)"\"
+test_cnc_exec_LDADD = \
+ $(top_builddir)/libgda/libgda-5.0.la \
+ $(COREDEPS_LIBS)
+
+test_cnc_meta_SOURCES = test-cnc-meta.c
+test_cnc_meta_CFLAGS = \
+ -DROOT_DIR=\""$(top_srcdir)"\"
+test_cnc_meta_LDADD = \
+ $(top_builddir)/libgda/libgda-5.0.la \
+ $(COREDEPS_LIBS)
diff --git a/libgda/dir-blob-op.c b/libgda/dir-blob-op.c
index 8f5e55c..15a7a79 100644
--- a/libgda/dir-blob-op.c
+++ b/libgda/dir-blob-op.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 - 2011 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2007 - 2014 Vivien Malerba <malerba gnome-db org>
* Copyright (C) 2010 David King <davidk openismus com>
*
* This library is free software; you can redistribute it and/or
@@ -21,6 +21,7 @@
#include <string.h>
#define __GDA_INTERNAL__
#include "dir-blob-op.h"
+#include <libgda/gda-blob-op-impl.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -33,7 +34,7 @@ struct _GdaDirBlobOpPrivate {
static void gda_dir_blob_op_class_init (GdaDirBlobOpClass *klass);
static void gda_dir_blob_op_init (GdaDirBlobOp *blob,
- GdaDirBlobOpClass *klass);
+ GdaDirBlobOpClass *klass);
static void gda_dir_blob_op_finalize (GObject *object);
static glong gda_dir_blob_op_get_length (GdaBlobOp *op);
@@ -74,7 +75,7 @@ _gda_dir_blob_op_get_type (void)
static void
gda_dir_blob_op_init (GdaDirBlobOp *op,
- G_GNUC_UNUSED GdaDirBlobOpClass *klass)
+ G_GNUC_UNUSED GdaDirBlobOpClass *klass)
{
g_return_if_fail (GDA_IS_DIR_BLOB_OP (op));
@@ -91,9 +92,9 @@ gda_dir_blob_op_class_init (GdaDirBlobOpClass *klass)
parent_class = g_type_class_peek_parent (klass);
object_class->finalize = gda_dir_blob_op_finalize;
- blob_class->get_length = gda_dir_blob_op_get_length;
- blob_class->read = gda_dir_blob_op_read;
- blob_class->write = gda_dir_blob_op_write;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->get_length = gda_dir_blob_op_get_length;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->read = gda_dir_blob_op_read;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->write = gda_dir_blob_op_write;
}
@@ -241,7 +242,7 @@ gda_dir_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset)
if (blob->op && (blob->op != op)) {
/* use data through blob->op */
- #define buf_size 16384
+#define buf_size 16384
gint nread = 0;
GdaBlob *tmpblob = g_new0 (GdaBlob, 1);
gda_blob_set_op (tmpblob, blob->op);
diff --git a/libgda/gda-blob-op-impl.h b/libgda/gda-blob-op-impl.h
new file mode 100644
index 0000000..5ac228f
--- /dev/null
+++ b/libgda/gda-blob-op-impl.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 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 Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GDA_BLOB_OP_IMPL_H__
+#define __GDA_BLOB_OP_IMPL_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libgda/gda-value.h>
+#include <libgda/gda-decl.h>
+
+G_BEGIN_DECLS
+
+
+/**
+ * GdaBlobOpFunctions: (skip)
+ */
+typedef struct {
+ /* Virtual methods */
+ glong (* get_length) (GdaBlobOp *op);
+ glong (* read) (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size);
+ glong (* write) (GdaBlobOp *op, GdaBlob *blob, glong offset);
+ gboolean (* write_all) (GdaBlobOp *op, GdaBlob *blob);
+} GdaBlobOpFunctions;
+
+#define GDA_BLOB_OP_FUNCTIONS(x) ((GdaBlobOpFunctions*)(x))
+
+G_END_DECLS
+
+#endif
+
diff --git a/libgda/gda-blob-op.c b/libgda/gda-blob-op.c
index 018b98d..5017a0f 100644
--- a/libgda/gda-blob-op.c
+++ b/libgda/gda-blob-op.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2007 Armin Burgmeier <armin openismus com>
* Copyright (C) 2007 Murray Cumming <murrayc murryac com>
- * Copyright (C) 2007 - 2011 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2007 - 2014 Vivien Malerba <malerba gnome-db org>
* Copyright (C) 2010 David King <davidk openismus com>
*
* This library is free software; you can redistribute it and/or
@@ -25,16 +25,46 @@
*/
#include "gda-blob-op.h"
+#include "gda-blob-op-impl.h"
+#include "gda-lockable.h"
+#include "gda-connection.h"
+#include "gda-connection-internal.h"
+#include "gda-server-provider-private.h"
+#include "thread-wrapper/gda-worker.h"
#include "gda-value.h"
#define PARENT_TYPE G_TYPE_OBJECT
#define CLASS(blob) (GDA_BLOB_OP_CLASS (G_OBJECT_GET_CLASS (blob)))
+#define VFUNCTIONS(blob) (GDA_BLOB_OP_FUNCTIONS (CLASS(blob)->functions))
static void gda_blob_op_class_init (GdaBlobOpClass *klass);
-static void gda_blob_op_init (GdaBlobOp *provider, GdaBlobOpClass *klass);
-static void gda_blob_op_finalize (GObject *object);
+static void gda_blob_op_init (GdaBlobOp *op, GdaBlobOpClass *klass);
+static void gda_blob_op_dispose (GObject *object);
+
+
+static void gda_blob_op_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gda_blob_op_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
static GObjectClass *parent_class = NULL;
+struct _GdaBlobOpPrivate {
+ GdaConnection *cnc;
+ GdaWorker *worker;
+};
+
+/* properties */
+enum
+{
+ PROP_0,
+ PROP_CNC,
+};
+
+
GType
gda_blob_op_get_type (void)
{
@@ -70,25 +100,108 @@ gda_blob_op_class_init (GdaBlobOpClass *klass)
parent_class = g_type_class_peek_parent (klass);
- object_class->finalize = gda_blob_op_finalize;
- klass->get_length = NULL;
- klass->read = NULL;
- klass->write = NULL;
+ /* properties */
+ object_class->set_property = gda_blob_op_set_property;
+ object_class->get_property = gda_blob_op_get_property;
+ g_object_class_install_property (object_class, PROP_CNC,
+ g_param_spec_object ("connection", NULL,
+ "Connection used to fetch and write data",
+ GDA_TYPE_CONNECTION,
+ G_PARAM_WRITABLE | G_PARAM_READABLE |
G_PARAM_CONSTRUCT_ONLY));
+
+ /* virtual functions */
+ object_class->dispose = gda_blob_op_dispose;
+ klass->functions = g_new0 (GdaBlobOpFunctions, 1);
}
static void
-gda_blob_op_init (G_GNUC_UNUSED GdaBlobOp *provider, G_GNUC_UNUSED GdaBlobOpClass *klass)
+gda_blob_op_init (GdaBlobOp *op, G_GNUC_UNUSED GdaBlobOpClass *klass)
{
-
+ op->priv = g_slice_new0 (GdaBlobOpPrivate);
}
static void
-gda_blob_op_finalize (GObject *object)
+gda_blob_op_dispose (GObject *object)
{
+ GdaBlobOp *op = (GdaBlobOp *) object;
+
+ if (op->priv) {
+ if (op->priv->worker)
+ gda_worker_unref (op->priv->worker);
+ if (op->priv->cnc)
+ g_object_unref (op->priv->cnc);
+ g_slice_free (GdaBlobOpPrivate, op->priv);
+ op->priv = NULL;
+ }
+
/* chain to parent class */
- parent_class->finalize (object);
+ parent_class->dispose (object);
}
+static void
+gda_blob_op_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdaBlobOp *op = (GdaBlobOp *) object;
+ if (op->priv) {
+ switch (param_id) {
+ case PROP_CNC:
+ op->priv->cnc = g_value_get_object (value);
+ if (op->priv->cnc) {
+ g_object_ref (op->priv->cnc);
+ op->priv->worker = _gda_connection_get_worker (op->priv->cnc);
+ g_assert (op->priv->worker);
+ gda_worker_ref (op->priv->worker);
+ }
+ else
+ g_warning ("GdaBlobOp created without any associated connection!");
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+ }
+}
+
+static void
+gda_blob_op_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdaBlobOp *op = (GdaBlobOp *) object;
+ if (op->priv) {
+ switch (param_id) {
+ case PROP_CNC:
+ g_value_set_object (value, op->priv->cnc);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+ }
+}
+
+typedef struct {
+ GdaBlobOp *op;
+ GdaBlob *blob;
+ glong offset;
+ glong size;
+
+ glong retval;
+} WorkerData;
+
+static gpointer
+worker_get_length (WorkerData *data, GError **error)
+{
+ if (VFUNCTIONS (data->op)->get_length != NULL)
+ data->retval = VFUNCTIONS (data->op)->get_length (data->op);
+ else
+ data->retval = -1;
+ return (gpointer) 0x01;
+}
/**
* gda_blob_op_get_length:
@@ -100,12 +213,51 @@ gda_blob_op_finalize (GObject *object)
glong
gda_blob_op_get_length (GdaBlobOp *op)
{
+ GdaWorker *worker;
g_return_val_if_fail (GDA_IS_BLOB_OP (op), -1);
+ if (op->priv) {
+ if (! op->priv->cnc || !op->priv->worker) {
+ g_warning ("Internal error: no connection of GdaWorker associated to blob operations
object");
+ return -1;
+ }
+
+ gda_lockable_lock ((GdaLockable*) op->priv->cnc); /* CNC LOCK */
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (op->priv->cnc);
+
+ WorkerData data;
+ data.op = op;
+ data.retval = -1;
+
+ gpointer callval;
+ gda_worker_do_job (op->priv->worker, context, 0, &callval, NULL,
+ (GdaWorkerFunc) worker_get_length, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+
+ gda_lockable_unlock ((GdaLockable*) op->priv->cnc); /* CNC UNLOCK */
+
+ if (callval == (gpointer) 0x01)
+ return data.retval;
+ else
+ return -1;
+ }
+ else {
+ if (VFUNCTIONS (op)->get_length != NULL)
+ return VFUNCTIONS (op)->get_length (op);
+ else
+ return -1;
+ }
+}
- if (CLASS (op)->get_length != NULL)
- return CLASS (op)->get_length (op);
+static gpointer
+worker_read (WorkerData *data, GError **error)
+{
+ if (VFUNCTIONS (data->op)->read != NULL)
+ data->retval = VFUNCTIONS (data->op)->read (data->op, data->blob, data->offset, data->size);
else
- return -1;
+ data->retval = -1;
+ return (gpointer) 0x01;
}
/**
@@ -123,12 +275,45 @@ gda_blob_op_get_length (GdaBlobOp *op)
glong
gda_blob_op_read (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size)
{
+ GdaWorker *worker;
g_return_val_if_fail (GDA_IS_BLOB_OP (op), -1);
- if (CLASS (op)->read != NULL)
- return CLASS (op)->read (op, blob, offset, size);
- else
- return -1;
+ if (op->priv) {
+ if (! op->priv->cnc || !op->priv->worker) {
+ g_warning ("Internal error: no connection of GdaWorker associated to blob operations
object");
+ return -1;
+ }
+
+ gda_lockable_lock ((GdaLockable*) op->priv->cnc); /* CNC LOCK */
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (op->priv->cnc);
+
+ WorkerData data;
+ data.op = op;
+ data.blob = blob;
+ data.offset = offset;
+ data.size = size;
+ data.retval = -1;
+
+ gpointer callval;
+ gda_worker_do_job (op->priv->worker, context, 0, &callval, NULL,
+ (GdaWorkerFunc) worker_read, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+
+ gda_lockable_unlock ((GdaLockable*) op->priv->cnc); /* CNC UNLOCK */
+
+ if (callval == (gpointer) 0x01)
+ return data.retval;
+ else
+ return -1;
+ }
+ else {
+ if (VFUNCTIONS (op)->read != NULL)
+ return VFUNCTIONS (op)->read (op, blob, offset, size);
+ else
+ return -1;
+ }
}
/**
@@ -154,6 +339,16 @@ gda_blob_op_read_all (GdaBlobOp *op, GdaBlob *blob)
return FALSE;
}
+static gpointer
+worker_write (WorkerData *data, GError **error)
+{
+ if (VFUNCTIONS (data->op)->write != NULL)
+ data->retval = VFUNCTIONS (data->op)->write (data->op, data->blob, data->offset);
+ else
+ data->retval = -1;
+ return (gpointer) 0x01;
+}
+
/**
* gda_blob_op_write:
* @op: a #GdaBlobOp
@@ -172,12 +367,54 @@ gda_blob_op_read_all (GdaBlobOp *op, GdaBlob *blob)
glong
gda_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset)
{
+ GdaWorker *worker;
g_return_val_if_fail (GDA_IS_BLOB_OP (op), -1);
- if (CLASS (op)->write != NULL)
- return CLASS (op)->write (op, blob, offset);
+ if (op->priv) {
+ if (! op->priv->cnc || !op->priv->worker) {
+ g_warning ("Internal error: no connection of GdaWorker associated to blob operations
object");
+ return -1;
+ }
+
+ gda_lockable_lock ((GdaLockable*) op->priv->cnc); /* CNC LOCK */
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (op->priv->cnc);
+
+ WorkerData data;
+ data.op = op;
+ data.blob = blob;
+ data.offset = offset;
+ data.retval = -1;
+
+ gpointer callval;
+ gda_worker_do_job (op->priv->worker, context, 0, &callval, NULL,
+ (GdaWorkerFunc) worker_write, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+
+ gda_lockable_unlock ((GdaLockable*) op->priv->cnc); /* CNC UNLOCK */
+
+ if (callval == (gpointer) 0x01)
+ return data.retval;
+ else
+ return -1;
+ }
+ else {
+ if (VFUNCTIONS (op)->write != NULL)
+ return VFUNCTIONS (op)->write (op, blob, offset);
+ else
+ return -1;
+ }
+}
+
+static gpointer
+worker_write_all (WorkerData *data, GError **error)
+{
+ if (VFUNCTIONS (data->op)->write_all != NULL)
+ data->retval = VFUNCTIONS (data->op)->write_all (data->op, data->blob) ? 1 : 0;
else
- return -1;
+ data->retval = 0;
+ return (gpointer) 0x01;
}
/**
@@ -195,8 +432,39 @@ gda_blob_op_write_all (GdaBlobOp *op, GdaBlob *blob)
{
g_return_val_if_fail (GDA_IS_BLOB_OP (op), FALSE);
- if (CLASS (op)->write_all != NULL)
- return CLASS (op)->write_all (op, blob);
+ if (VFUNCTIONS (op)->write_all != NULL) {
+ if (op->priv) {
+ GdaWorker *worker;
+ if (! op->priv->cnc || !op->priv->worker) {
+ g_warning ("Internal error: no connection of GdaWorker associated to blob
operations object");
+ return -1;
+ }
+
+ gda_lockable_lock ((GdaLockable*) op->priv->cnc); /* CNC LOCK */
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (op->priv->cnc);
+
+ WorkerData data;
+ data.op = op;
+ data.blob = blob;
+ data.retval = -1;
+
+ gpointer callval;
+ gda_worker_do_job (op->priv->worker, context, 0, &callval, NULL,
+ (GdaWorkerFunc) worker_write_all, (gpointer) &data, NULL, NULL,
NULL);
+ g_main_context_unref (context);
+
+ gda_lockable_unlock ((GdaLockable*) op->priv->cnc); /* CNC UNLOCK */
+
+ if (callval == (gpointer) 0x01)
+ return data.retval ? TRUE : FALSE;
+ else
+ return FALSE;
+ }
+ else
+ return VFUNCTIONS (op)->write_all (op, blob);
+ }
else {
glong res;
res = gda_blob_op_write (op, blob, 0);
diff --git a/libgda/gda-blob-op.h b/libgda/gda-blob-op.h
index 6919851..653515f 100644
--- a/libgda/gda-blob-op.h
+++ b/libgda/gda-blob-op.h
@@ -34,8 +34,11 @@ G_BEGIN_DECLS
#define GDA_IS_BLOB_OP(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, GDA_TYPE_BLOB_OP))
#define GDA_IS_BLOB_OP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GDA_TYPE_BLOB_OP))
+typedef struct _GdaBlobOpPrivate GdaBlobOpPrivate;
+
struct _GdaBlobOp {
GObject object;
+ GdaBlobOpPrivate *priv;
/* Padding for future expansion */
gpointer _gda_reserved1;
@@ -43,12 +46,7 @@ struct _GdaBlobOp {
struct _GdaBlobOpClass {
GObjectClass parent_class;
-
- /* Virtual methods */
- glong (* get_length) (GdaBlobOp *op);
- glong (* read) (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size);
- glong (* write) (GdaBlobOp *op, GdaBlob *blob, glong offset);
- gboolean (* write_all) (GdaBlobOp *op, GdaBlob *blob);
+ gpointer functions;
/*< private >*/
/* Padding for future expansion */
diff --git a/libgda/gda-connection-internal.h b/libgda/gda-connection-internal.h
index 66c25fa..9fe1016 100644
--- a/libgda/gda-connection-internal.h
+++ b/libgda/gda-connection-internal.h
@@ -2,7 +2,7 @@
* Copyright (C) 2000 Reinhard Müller <reinhard src gnome org>
* Copyright (C) 2000 - 2002 Rodrigo Moya <rodrigo gnome-db org>
* Copyright (C) 2001 Carlos Perell� Mar�n <carlos gnome-db org>
- * Copyright (C) 2001 - 2011 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2001 - 2013 Vivien Malerba <malerba gnome-db org>
* Copyright (C) 2002 Gonzalo Paniagua Javier <gonzalo src gnome org>
*
* This library is free software; you can redistribute it and/or
@@ -26,7 +26,6 @@
#include <libgda/gda-decl.h>
#include <libgda/gda-server-provider.h>
-#include <libgda/thread-wrapper/gda-thread-wrapper.h>
G_BEGIN_DECLS
@@ -35,49 +34,25 @@ G_BEGIN_DECLS
*/
#ifdef GDA_DEBUG
#define ASSERT_TABLE_NAME(x,y) g_assert (!strcmp ((x), (y)))
-#define WARN_METHOD_NOT_IMPLEMENTED(prov,method) g_warning ("Provider '%s' does not implement the META
method '%s()', please report the error to bugzilla.gnome.org", gda_server_provider_get_name (prov), (method))
#define WARN_META_UPDATE_FAILURE(x,method) if (!(x)) g_print ("%s (meta method => %s) ERROR: %s\n",
__FUNCTION__, (method), error && *error && (*error)->message ? (*error)->message : "???")
#else
#define ASSERT_TABLE_NAME(x,y)
-#define WARN_METHOD_NOT_IMPLEMENTED(prov,method)
#define WARN_META_UPDATE_FAILURE(x,method)
#endif
/*
- * Opens a connection to an SQLite database. This function is intended to be used
- * internally when objects require an SQLite connection, for example for the GdaMetaStore
- * object
+ * Misc.
*/
-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);
+gboolean _gda_connection_close_no_warning (GdaConnection *cnc, GError **error);
+GdaWorker *_gda_connection_get_worker (GdaConnection *cnc);
+guint _gda_connection_get_exec_slowdown (GdaConnection *cnc);
/*
- * Functions dedicated to implementing a GdaConnection which uses a GdaThreadWrapper around
- * another connection to make it thread safe.
+ * Opens a connection to an SQLite database. This function is intended to be used
+ * internally when objects require an SQLite connection, for example for the GdaMetaStore
+ * object
*/
-typedef struct {
- GdaConnection *sub_connection;
- gboolean sub_connection_has_closed;
- 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_thread_connection_set_data (GdaConnection *cnc, ThreadConnectionData *cdata);
-ThreadConnectionData *_gda_thread_connection_get_data (GdaConnection *cnc);
-void _gda_thread_connection_data_free (ThreadConnectionData *cdata);
-void _gda_connection_force_transaction_status (GdaConnection *cnc, GdaConnection
*wrapped_cnc);
-GdaServerProvider *_gda_connection_get_internal_thread_provider (void);
-
-void _gda_connection_define_as_thread_wrapper (GdaConnection *cnc);
+GdaConnection *_gda_open_internal_sqlite_connection (const gchar *cnc_string);
/*
* Used by virtual connections to keep meta data up to date when a table
diff --git a/libgda/gda-connection-private.h b/libgda/gda-connection-private.h
index fcb5650..ce45267 100644
--- a/libgda/gda-connection-private.h
+++ b/libgda/gda-connection-private.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 - 2011 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2006 - 2013 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 Lesser General Public
@@ -22,15 +22,36 @@
#include <libgda/gda-meta-store.h>
#include <providers-support/gda-pstmt.h>
+#include <libgda/thread-wrapper/gda-worker.h>
+#include <libgda/gda-transaction-status.h>
+#include <libgda/gda-connection-event.h>
G_BEGIN_DECLS
/*
* Provider's specific connection data management
*/
-void gda_connection_internal_set_provider_data (GdaConnection *cnc, gpointer data, GDestroyNotify
destroy_func);
-gpointer gda_connection_internal_get_provider_data (GdaConnection *cnc);
-gpointer gda_connection_internal_get_provider_data_error (GdaConnection *cnc, GError **error);
+/**
+ * GdaServerProviderConnectionData:
+ *
+ * Opaque structure extended by database providers to store per-connection information (usually C handles
+ * to the connection as required by the C API they use).
+ *
+ * Note: @worker part is created in _gda_server_provider_open_connection() by the provider itself, which
allows it to
+ * either create a #GdaWorker for each connection, or create only one #GdaWorker for all connections (if the
underlying
+ * for example does not support multi-threading at all)
+ */
+typedef struct {
+ GdaWorker * GSEAL(worker);
+ GDestroyNotify GSEAL(provider_data_destroy_func);
+ gpointer GSEAL(pad1);
+ gpointer GSEAL(pad2);
+} GdaServerProviderConnectionData;
+
+void gda_connection_internal_set_provider_data (GdaConnection *cnc,
+
GdaServerProviderConnectionData *data,
+ GDestroyNotify
destroy_func);
+GdaServerProviderConnectionData *gda_connection_internal_get_provider_data_error (GdaConnection *cnc, GError
**error);
/*
* Connection's events
diff --git a/libgda/gda-connection.c b/libgda/gda-connection.c
index 70f124b..bbe94d2 100644
--- a/libgda/gda-connection.c
+++ b/libgda/gda-connection.c
@@ -39,6 +39,8 @@
*/
#undef GDA_DISABLE_DEPRECATED
+#undef GSEAL_ENABLE
+
#include <stdio.h>
#include <libgda/gda-config.h>
#include <libgda/gda-connection.h>
@@ -49,6 +51,7 @@
#include <libgda/gda-log.h>
#include <libgda/gda-server-provider.h>
#include <libgda/gda-server-provider-extra.h>
+#include <libgda/gda-server-provider-private.h>
#include "gda-marshal.h"
#include <libgda/gda-transaction-status-private.h>
#include <string.h>
@@ -61,7 +64,6 @@
#include <libgda/gda-util.h>
#include <libgda/gda-mutex.h>
#include <libgda/gda-lockable.h>
-#include <libgda/thread-wrapper/gda-thread-provider.h>
#include <libgda/gda-repetitive-statement.h>
#include <gda-statement-priv.h>
#include <sqlite/virtual/gda-vconnection-data-model.h>
@@ -74,8 +76,7 @@
static GMutex parser_mutex;
static GdaSqlParser *internal_parser = NULL;
-
-#define PROV_CLASS(provider) (GDA_SERVER_PROVIDER_CLASS (G_OBJECT_GET_CLASS (provider)))
+static GMainContext *all_context = NULL;
/* number of GdaConnectionEvent kept by each connection. Should be enough to avoid losing any
* event, considering that the events are reseted after each statement execution */
@@ -87,8 +88,8 @@ struct _GdaConnectionPrivate {
gchar *dsn;
gchar *cnc_string;
gchar *auth_string;
- gboolean is_thread_wrapper;
- guint monitor_id;
+
+ GMainContext *context;
GdaMetaStore *meta_store;
@@ -102,52 +103,19 @@ struct _GdaConnectionPrivate {
GdaTransactionStatus *trans_status;
GHashTable *prepared_stmts;
- gpointer provider_data;
- GDestroyNotify provider_data_destroy_func;
+ GdaServerProviderConnectionData *provider_data;
/* multi threading locking */
- GThread *unique_possible_thread; /* non NULL => only that thread can use this connection
*/
- GCond unique_possible_cond;
GMutex object_mutex;
GRecMutex rmutex;
- /* Asynchronous statement execution */
- guint next_task_id; /* starts at 1 as 0 is an error */
- GArray *waiting_tasks; /* array of CncTask pointers to tasks to be executed */
- GArray *completed_tasks; /* array of CncTask pointers to tasks already executed */
/* auto meta data update */
GArray *trans_meta_context; /* Array of GdaMetaContext pointers */
gboolean exec_times;
guint exec_slowdown;
-
- ThreadConnectionData *th_data; /* used if connection is used by the GdaThreadProvider, NULL otherwise
*/
};
-/* represents an asynchronous execution task */
-typedef struct {
- guint task_id; /* ID assigned by GdaConnection object */
- guint prov_task_id; /* ID assigned by GdaServerProvider */
- gboolean being_processed; /* TRUE if currently being processed */
- GRecMutex rmutex;
- GdaStatement *stmt; /* statement to execute */
- GdaStatementModelUsage model_usage;
- GType *col_types;
- GdaSet *params;
- gboolean need_last_insert_row;
- GdaSet *last_insert_row;
- GObject *result;
- GError *error;
- GTimer *exec_timer;
-} CncTask;
-#define CNC_TASK(x) ((CncTask*)(x))
-
-static CncTask *cnc_task_new (guint id, GdaStatement *stmt, GdaStatementModelUsage model_usage,
- GType *col_types, GdaSet *params, gboolean need_last_insert_row);
-static void cnc_task_free (CncTask *task);
-#define cnc_task_lock(task) g_rec_mutex_lock (&((task)->rmutex))
-#define cnc_task_unlock(task) g_rec_mutex_unlock (&((task)->rmutex))
-
static void add_exec_time_to_object (GObject *obj, GTimer *timer);
static void gda_connection_class_init (GdaConnectionClass *klass);
@@ -194,9 +162,6 @@ enum
PROP_AUTH_STRING,
PROP_OPTIONS,
PROP_META_STORE,
- PROP_THREAD_OWNER,
- PROP_IS_THREAD_WRAPPER,
- PROP_MONITOR_WRAPPED_IN_MAINLOOP,
PROP_EVENTS_HISTORY_SIZE,
PROP_EXEC_TIMES,
PROP_EXEC_SLOWDOWN
@@ -204,7 +169,6 @@ enum
static GObjectClass *parent_class = NULL;
extern GdaServerProvider *_gda_config_sqlite_provider; /* defined in gda-config.c */
-static GdaServerProvider *_gda_thread_wrapper_provider = NULL;
static gint debug_level = -1;
static void
@@ -361,46 +325,6 @@ gda_connection_class_init (GdaConnectionClass *klass)
GDA_TYPE_META_STORE,
(G_PARAM_READABLE | G_PARAM_WRITABLE)));
- g_object_class_install_property (object_class, PROP_THREAD_OWNER,
- g_param_spec_pointer ("thread-owner", NULL,
- _("Unique GThread from which the connection
will be available."
- "This should only be modified by the
database providers' implementation"),
- (G_PARAM_READABLE | G_PARAM_WRITABLE)));
-
- /**
- * GdaConnection:is-wrapper:
- *
- * This property, if set to %TRUE, specifies that the connection is not a real connection, but rather
- * a #GdaConnection object which "proxies" all the calls to another connection which executes in a sub
- * thread.
- *
- * Note: this property is used internally by Libgda and should not be directly used by any programs.
Setting
- * this property has no effect, reading it is supported, though.
- *
- * Since: 4.2
- **/
- g_object_class_install_property (object_class, PROP_IS_THREAD_WRAPPER,
- g_param_spec_boolean ("is-wrapper", NULL,
- _("Determines if the connection acts as a
thread wrapper around another connection, making it completely thread safe"),
- FALSE,
- G_PARAM_READABLE | G_PARAM_WRITABLE));
-
- /**
- * GdaConnection:monitor-wrapped-in-mainloop:
- *
- * Useful only when there is a mainloop and when the connection acts as a thread wrapper around
another connection,
- * it sets up a timeout to handle signals coming from the wrapped connection.
- *
- * If the connection is not a thread wrapper, then this property has no effect.
- *
- * Since: 4.2
- **/
- g_object_class_install_property (object_class, PROP_MONITOR_WRAPPED_IN_MAINLOOP,
- g_param_spec_boolean ("monitor-wrapped-in-mainloop", NULL,
- _("Make the connection set up a monitoring
function in the mainloop to monitor the wrapped connection"),
- FALSE,
- (G_PARAM_READABLE | G_PARAM_WRITABLE)));
-
/**
* GdaConnection:events-history-size:
*
@@ -485,14 +409,16 @@ gda_connection_init (GdaConnection *cnc, G_GNUC_UNUSED GdaConnectionClass *klass
g_return_if_fail (GDA_IS_CONNECTION (cnc));
cnc->priv = g_new0 (GdaConnectionPrivate, 1);
- cnc->priv->unique_possible_thread = NULL;
g_mutex_init (&cnc->priv->object_mutex);
g_rec_mutex_init (&cnc->priv->rmutex);
- g_cond_init (& cnc->priv->unique_possible_cond);
cnc->priv->provider_obj = NULL;
cnc->priv->dsn = NULL;
cnc->priv->cnc_string = NULL;
cnc->priv->auth_string = NULL;
+ if (all_context)
+ cnc->priv->context = g_main_context_ref (all_context);
+ else
+ cnc->priv->context = NULL;
cnc->priv->auto_clear_events = TRUE;
cnc->priv->events_array_size = EVENTS_ARRAY_SIZE;
cnc->priv->events_array = g_new0 (GdaConnectionEvent*, EVENTS_ARRAY_SIZE);
@@ -501,13 +427,6 @@ gda_connection_init (GdaConnection *cnc, G_GNUC_UNUSED GdaConnectionClass *klass
cnc->priv->trans_status = NULL; /* no transaction yet */
cnc->priv->prepared_stmts = NULL;
- cnc->priv->is_thread_wrapper = FALSE;
- cnc->priv->monitor_id = 0;
-
- cnc->priv->next_task_id = 1;
- cnc->priv->waiting_tasks = g_array_new (FALSE, FALSE, sizeof (gpointer));
- cnc->priv->completed_tasks = g_array_new (FALSE, FALSE, sizeof (gpointer));
-
cnc->priv->trans_meta_context = NULL;
cnc->priv->provider_data = NULL;
@@ -525,12 +444,11 @@ gda_connection_dispose (GObject *object)
g_return_if_fail (GDA_IS_CONNECTION (cnc));
/* free memory */
- cnc->priv->unique_possible_thread = NULL;
- gda_connection_close_no_warning (cnc);
+ _gda_connection_close_no_warning (cnc, NULL);
- if (cnc->priv->th_data) {
- _gda_thread_connection_data_free (cnc->priv->th_data);
- cnc->priv->th_data = NULL;
+ if (cnc->priv->context) {
+ g_main_context_unref (cnc->priv->context);
+ cnc->priv->context = NULL;
}
/* get rid of prepared statements to avoid problems */
@@ -575,22 +493,6 @@ gda_connection_dispose (GObject *object)
cnc->priv->meta_store = NULL;
}
- if (cnc->priv->waiting_tasks) {
- gint i, len = cnc->priv->waiting_tasks->len;
- for (i = 0; i < len; i++)
- cnc_task_free (CNC_TASK (g_array_index (cnc->priv->waiting_tasks, gpointer, i)));
- g_array_free (cnc->priv->waiting_tasks, TRUE);
- cnc->priv->waiting_tasks = NULL;
- }
-
- if (cnc->priv->completed_tasks) {
- gssize i, len = cnc->priv->completed_tasks->len;
- for (i = 0; i < len; i++)
- cnc_task_free (CNC_TASK (g_array_index (cnc->priv->completed_tasks, gpointer, i)));
- g_array_free (cnc->priv->completed_tasks, TRUE);
- cnc->priv->completed_tasks = NULL;
- }
-
if (cnc->priv->trans_meta_context) {
gsize i;
for (i = 0; i < cnc->priv->trans_meta_context->len; i++) {
@@ -618,7 +520,6 @@ gda_connection_finalize (GObject *object)
g_free (cnc->priv->cnc_string);
g_free (cnc->priv->auth_string);
- g_cond_clear (& cnc->priv->unique_possible_cond);
g_mutex_clear (& cnc->priv->object_mutex);
g_rec_mutex_clear (&cnc->priv->rmutex);
@@ -681,19 +582,6 @@ gda_connection_get_type (void)
return type;
}
-static gboolean
-monitor_wrapped_cnc (GdaThreadWrapper *wrapper)
-{
- gda_thread_wrapper_iterate (wrapper, FALSE);
- return TRUE; /* don't remove the monitoring */
-}
-
-void
-_gda_connection_define_as_thread_wrapper (GdaConnection *cnc)
-{
- cnc->priv->is_thread_wrapper = TRUE;
-}
-
static void
gda_connection_set_property (GObject *object,
guint param_id,
@@ -704,33 +592,14 @@ gda_connection_set_property (GObject *object,
cnc = GDA_CONNECTION (object);
if (cnc->priv) {
- if (cnc->priv->th_data && ! gda_connection_internal_get_provider_data (cnc)) {
- _gda_thread_connection_data_free (cnc->priv->th_data);
- cnc->priv->th_data = NULL;
- }
-
switch (param_id) {
- case PROP_THREAD_OWNER:
- g_mutex_lock (&cnc->priv->object_mutex);
- g_rec_mutex_lock (&cnc->priv->rmutex);
- cnc->priv->unique_possible_thread = g_value_get_pointer (value);
-#ifdef GDA_DEBUG_CNC_LOCK
- g_print ("Unique set to %p\n", cnc->priv->unique_possible_thread);
- g_print ("Signalling on %p\n", cnc->priv->unique_possible_cond);
-#endif
- g_cond_broadcast (& cnc->priv->unique_possible_cond);
-
- g_rec_mutex_unlock (&cnc->priv->rmutex);
- g_mutex_unlock (&cnc->priv->object_mutex);
- break;
case PROP_DSN: {
const gchar *datasource = g_value_get_string (value);
GdaDsnInfo *dsn;
gda_connection_lock ((GdaLockable*) cnc);
- _gda_thread_connection_set_data (cnc, NULL);
if (cnc->priv->provider_data) {
- g_warning (_("Could not set the '%s' property when the connection is opened"),
+ g_warning (_("Can't set the '%s' property when the connection is opened"),
pspec->name);
gda_connection_unlock ((GdaLockable*) cnc);
return;
@@ -757,9 +626,8 @@ gda_connection_set_property (GObject *object,
}
case PROP_CNC_STRING:
gda_connection_lock ((GdaLockable*) cnc);
- _gda_thread_connection_set_data (cnc, NULL);
if (cnc->priv->provider_data) {
- g_warning (_("Could not set the '%s' property when the connection is opened"),
+ g_warning (_("Can't set the '%s' property when the connection is opened"),
pspec->name);
gda_connection_unlock ((GdaLockable*) cnc);
return;
@@ -772,9 +640,8 @@ gda_connection_set_property (GObject *object,
break;
case PROP_PROVIDER_OBJ:
gda_connection_lock ((GdaLockable*) cnc);
- _gda_thread_connection_set_data (cnc, NULL);
if (cnc->priv->provider_data) {
- g_warning (_("Could not set the '%s' property when the connection is opened"),
+ g_warning (_("Can't set the '%s' property when the connection is opened"),
pspec->name);
gda_connection_unlock ((GdaLockable*) cnc);
return;
@@ -788,9 +655,8 @@ gda_connection_set_property (GObject *object,
break;
case PROP_AUTH_STRING:
gda_connection_lock ((GdaLockable*) cnc);
- _gda_thread_connection_set_data (cnc, NULL);
if (cnc->priv->provider_data) {
- g_warning (_("Could not set the '%s' property when the connection is opened"),
+ g_warning (_("Can't set the '%s' property when the connection is opened"),
pspec->name);
gda_connection_unlock ((GdaLockable*) cnc);
return;
@@ -807,22 +673,21 @@ gda_connection_set_property (GObject *object,
case PROP_OPTIONS: {
GdaConnectionOptions flags;
flags = g_value_get_flags (value);
- g_rec_mutex_lock (&cnc->priv->rmutex);
- _gda_thread_connection_set_data (cnc, NULL);
+ gda_connection_lock ((GdaLockable*) cnc);
if (cnc->priv->provider_data &&
((flags & (~GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE)) !=
(cnc->priv->options &
(~GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE)))) {
g_warning (_("Can't set the '%s' property once the connection is opened"),
pspec->name);
- g_rec_mutex_unlock (&cnc->priv->rmutex);
+ gda_connection_unlock ((GdaLockable*) cnc);
return;
}
cnc->priv->options = flags;
- g_rec_mutex_unlock (&cnc->priv->rmutex);
+ gda_connection_unlock ((GdaLockable*) cnc);
break;
}
case PROP_META_STORE:
- g_rec_mutex_lock (&cnc->priv->rmutex);
+ gda_connection_lock ((GdaLockable*) cnc);
if (cnc->priv->meta_store) {
g_object_unref (cnc->priv->meta_store);
cnc->priv->meta_store = NULL;
@@ -830,43 +695,7 @@ gda_connection_set_property (GObject *object,
cnc->priv->meta_store = g_value_get_object (value);
if (cnc->priv->meta_store)
g_object_ref (cnc->priv->meta_store);
- if (cnc->priv->is_thread_wrapper) {
- ThreadConnectionData *cdata;
- cdata = (ThreadConnectionData*) gda_connection_internal_get_provider_data
(cnc);
- if (cdata)
- g_object_set (G_OBJECT (cdata->sub_connection), "meta-store",
- cnc->priv->meta_store, NULL);
- }
- g_rec_mutex_unlock (&cnc->priv->rmutex);
- break;
- case PROP_IS_THREAD_WRAPPER:
- g_warning ("This property should not be modified!");
- break;
- case PROP_MONITOR_WRAPPED_IN_MAINLOOP:
- if (cnc->priv->is_thread_wrapper) {
- /* cancel any existing signal monitoring */
- if (cnc->priv->monitor_id > 0) {
- g_source_remove (cnc->priv->monitor_id);
- cnc->priv->monitor_id = 0;
- }
- if (g_value_get_boolean (value)) {
- /* set up signal monitoring */
- ThreadConnectionData *cdata = NULL;
- cdata = (ThreadConnectionData*)
gda_connection_internal_get_provider_data (cnc);
- if (cdata) {
- cnc->priv->monitor_id = g_timeout_add_seconds (1,
- (GSourceFunc)
monitor_wrapped_cnc,
-
cdata->wrapper);
- /* steal signals for current thread */
- gsize i;
- for (i = 0; i < cdata->handlers_ids->len; i++) {
- gulong id;
- id = g_array_index (cdata->handlers_ids, gulong, i);
- gda_thread_wrapper_steal_signal (cdata->wrapper, id);
- }
- }
- }
- }
+ gda_connection_unlock ((GdaLockable*) cnc);
break;
case PROP_EVENTS_HISTORY_SIZE:
gda_connection_lock ((GdaLockable*) cnc);
@@ -878,13 +707,6 @@ gda_connection_set_property (GObject *object,
break;
case PROP_EXEC_SLOWDOWN:
cnc->priv->exec_slowdown = g_value_get_uint (value);
- if (cnc->priv->is_thread_wrapper) {
- ThreadConnectionData *cdata;
- cdata = (ThreadConnectionData*) gda_connection_internal_get_provider_data
(cnc);
- if (cdata)
- g_object_set (G_OBJECT (cdata->sub_connection), "execution-slowdown",
- cnc->priv->exec_slowdown, NULL);
- }
break;
}
}
@@ -919,13 +741,6 @@ gda_connection_get_property (GObject *object,
case PROP_META_STORE:
g_value_set_object (value, cnc->priv->meta_store);
break;
- case PROP_IS_THREAD_WRAPPER:
- g_value_set_boolean (value, cnc->priv->is_thread_wrapper);
- break;
- case PROP_MONITOR_WRAPPED_IN_MAINLOOP:
- g_value_set_boolean (value, cnc->priv->is_thread_wrapper && (cnc->priv->monitor_id >
0) ?
- TRUE : FALSE);
- break;
case PROP_EVENTS_HISTORY_SIZE:
g_value_set_int (value, cnc->priv->events_array_size);
break;
@@ -942,6 +757,81 @@ gda_connection_get_property (GObject *object,
}
}
+/**
+ * gda_connection_set_main_context:
+ * @cnc: (allow-none): a #GdaConnection, or %NULL
+ * @context: (allow-none): a #GMainContext, or %NULL
+ *
+ * Defines the #GMainContext which will still process events while a potentially blocking operation is
performed.
+ * For exemple if there is a GUI which needs to continue to handle events, then you can use this function to
pass
+ * the default #GMainContext used for the UI refreshing, for example:
+ * <programlisting><![CDATA[GMainContext *context;
+ * cnc = gda_connection_new_...;
+ * context = g_main_context_ref_thread_default ();
+ * gda_connection_set_main_context (cnc, context);
+ * g_main_context_unref (context);
+ * GError *error = NULL;
+ * if (! gda_connection_open (cnc, &error))
+ * ...
+ * ]]></programlisting>
+ *
+ * If @context is %NULL, then potentially blocking operation will actually block any event from being
processed.
+ *
+ * Since: 6.0
+ */
+void
+gda_connection_set_main_context (GdaConnection *cnc, GMainContext *context)
+{
+ if (cnc) {
+ g_return_if_fail (GDA_IS_CONNECTION (cnc));
+ if (cnc->priv->context == context)
+ return;
+
+ gda_connection_lock ((GdaLockable*) cnc);
+ if (cnc->priv->context) {
+ g_main_context_unref (cnc->priv->context);
+ cnc->priv->context = NULL;
+ }
+ if (context)
+ cnc->priv->context = g_main_context_ref (context);
+ gda_connection_unlock ((GdaLockable*) cnc);
+ }
+ else {
+ if (all_context == context)
+ return;
+
+ if (all_context) {
+ g_main_context_unref (all_context);
+ all_context = NULL;
+ }
+ if (context)
+ all_context = g_main_context_ref (context);
+ }
+}
+
+/**
+ * gda_connection_get_main_context:
+ * @cnc: (allow-none): a #GdaConnection, or %NULL
+ *
+ * Get the #GMainContext used while a potentially blocking operation is performed, see
gda_connection_set_main_context().
+ * If no main context has been defined, then some function calls (for example connection opening) may block
until the
+ * operation has finished.
+ *
+ * Returns: (transfer none): a #GMainContext, or %NULL
+ *
+ * Since: 6.0
+ */
+GMainContext *
+gda_connection_get_main_context (GdaConnection *cnc)
+{
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ return cnc->priv->context;
+ }
+ else
+ return all_context;
+}
+
/*
* Returns: a new GType array, free using g_free(), or %NULL if none to compute
*/
@@ -983,105 +873,6 @@ merge_column_types (const GType *struct_types, const GType *user_types)
return retval;
}
-/*
- * helper functions to manage CncTask
- */
-static void task_stmt_reset_cb (GdaStatement *stmt, CncTask *task);
-static CncTask *
-cnc_task_new (guint id, GdaStatement *stmt, GdaStatementModelUsage model_usage, GType *col_types,
- GdaSet *params, gboolean need_last_insert_row)
-{
- CncTask *task;
-
- task = g_new0 (CncTask, 1);
- task->being_processed = FALSE;
- task->task_id = id;
- task->stmt = g_object_ref (stmt);
- task->exec_timer = NULL;
- g_signal_connect (stmt, "reset", /* monitor statement changes */
- G_CALLBACK (task_stmt_reset_cb), task);
- task->model_usage = model_usage;
- GType *req_types;
- req_types = merge_column_types (_gda_statement_get_requested_types (stmt), col_types);
- if (req_types)
- task->col_types = req_types;
- else {
- if (_gda_statement_get_requested_types (stmt))
- col_types = (GType*) _gda_statement_get_requested_types (stmt);
- if (col_types) {
- gint i;
- for (i = 0; ; i++) {
- if (col_types [i] == G_TYPE_NONE)
- break;
- }
- i++;
- task->col_types = g_new (GType, i);
- memcpy (task->col_types, col_types, i * sizeof (GType)); /* Flawfinder: ignore */
- }
- }
- if (params)
- task->params = gda_set_copy (params);
- task->need_last_insert_row = need_last_insert_row;
-
- g_rec_mutex_init (&(task->rmutex));
-
- return task;
-}
-
-static void
-task_stmt_reset_cb (G_GNUC_UNUSED GdaStatement *stmt, CncTask *task)
-{
- g_rec_mutex_lock (&(task->rmutex));
- g_signal_handlers_disconnect_by_func (task->stmt,
- G_CALLBACK (task_stmt_reset_cb), task);
- g_object_unref (task->stmt);
- task->stmt = NULL;
- g_rec_mutex_unlock (&(task->rmutex));
-}
-
-static void
-cnc_task_free (CncTask *task)
-{
- g_rec_mutex_lock (&(task->rmutex));
- if (task->stmt) {
- g_signal_handlers_disconnect_by_func (task->stmt,
- G_CALLBACK (task_stmt_reset_cb), task);
- g_object_unref (task->stmt);
- }
- if (task->params)
- g_object_unref (task->params);
- if (task->col_types)
- g_free (task->col_types);
- if (task->last_insert_row)
- g_object_unref (task->last_insert_row);
- if (task->result)
- g_object_unref (task->result);
- if (task->error)
- g_error_free (task->error);
- if (task->exec_timer)
- g_timer_destroy (task->exec_timer);
-
- g_rec_mutex_unlock (&(task->rmutex));
- g_rec_mutex_clear (&(task->rmutex));
- g_free (task);
-}
-
-/**
- * _gda_connection_get_internal_thread_provider:
- */
-GdaServerProvider *
-_gda_connection_get_internal_thread_provider (void)
-{
- static GMutex mutex;
-
- g_mutex_lock (&mutex);
- if (!_gda_thread_wrapper_provider)
- _gda_thread_wrapper_provider = GDA_SERVER_PROVIDER (g_object_new (GDA_TYPE_THREAD_PROVIDER,
NULL));
- g_mutex_unlock (&mutex);
- return _gda_thread_wrapper_provider;
-}
-
-
/**
* gda_connection_new_from_dsn:
* @dsn: data source name.
@@ -1089,16 +880,37 @@ _gda_connection_get_internal_thread_provider (void)
* @options: options for the connection (see #GdaConnectionOptions).
* @error: a place to store an error, or %NULL
*
- * This function is similar to gda_connection_open_from_dsn(), except it does not actually open the
- * connection, you have to open it using gda_connection_open().
+ * This function creates a new function, using a pre-defined data source (DSN),
+ * see gda_config_define_dsn() for more information about how to define a DSN. If you don't want to define
+ * a DSN, it is possible to use gda_connection_new_from_string() instead of this method.
+ *
+ * The @dsn string must have the following format: "[<username>[:<password>] ]<DSN>"
+ * (if <username> and/or <password> are provided, and @auth_string is %NULL, then these username
+ * and passwords will be used). Note that if provided, <username> and <password>
+ * must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information.
*
- * Returns: (transfer full): a new #GdaConnection if connection opening was successful or %NULL if there was
an error.
+ * The @auth_string can contain the authentication information for the server
+ * to accept the connection. It is a string containing semi-colon seperated named value, usually
+ * like "USERNAME=...;PASSWORD=..." where the ... are replaced by actual values. Note that each
+ * name and value must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information.
+ *
+ * The actual named parameters required depend on the provider being used, and that list is available
+ * as the <parameter>auth_params</parameter> member of the #GdaProviderInfo structure for each installed
+ * provider (use gda_config_get_provider_info() to get it). Also one can use the "gda-sql-5.0 -L" command to
+ * list the possible named parameters.
+ *
+ * This method may fail with a GDA_CONNECTION_ERROR domain error (see the #GdaConnectionError error codes)
+ * or a %GDA_CONFIG_ERROR domain error (see the #GdaConfigError error codes).
+ *
+ * The returned connection is not yet opened, you need to call gda_connection_open() or
gda_connection_open_async().
+ *
+ * Returns: (transfer full): a new #GdaConnection or %NULL if there was an error.
*
* Since: 5.0.2
*/
GdaConnection *
gda_connection_new_from_dsn (const gchar *dsn, const gchar *auth_string,
- GdaConnectionOptions options, GError **error)
+ GdaConnectionOptions options, GError **error)
{
GdaConnection *cnc = NULL;
GdaDsnInfo *dsn_info;
@@ -1107,13 +919,6 @@ gda_connection_new_from_dsn (const gchar *dsn, const gchar *auth_string,
g_return_val_if_fail (dsn && *dsn, NULL);
- if (((options & GDA_CONNECTION_OPTIONS_THREAD_SAFE) || (options &
GDA_CONNECTION_OPTIONS_THREAD_SAFE)) &&
- !g_thread_supported ()) {
- g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_UNSUPPORTED_THREADS_ERROR,
- "%s", _("Multi threading is not supported or enabled"));
- return NULL;
- }
-
gda_dsn_split (dsn, &real_dsn, &user, &pass);
if (!real_dsn) {
g_free (user);
@@ -1153,37 +958,16 @@ gda_connection_new_from_dsn (const gchar *dsn, const gchar *auth_string,
GdaServerProvider *prov = NULL;
pinfo = gda_config_get_provider_info (dsn_info->provider);
- if (pinfo) {
+ if (pinfo)
prov = gda_config_get_provider (dsn_info->provider, error);
- if (((options & GDA_CONNECTION_OPTIONS_THREAD_SAFE) &&
- !gda_server_provider_supports_feature (prov, NULL,
- GDA_CONNECTION_FEATURE_MULTI_THREADING))
||
- (options & GDA_CONNECTION_OPTIONS_THREAD_ISOLATED)) {
- options |= GDA_CONNECTION_OPTIONS_THREAD_ISOLATED;
- prov = _gda_connection_get_internal_thread_provider ();
- }
- }
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)
- g_object_set (G_OBJECT (cnc),
- "provider", prov,
- "dsn", real_dsn,
- "auth-string", auth_string ? auth_string :
real_auth_string,
- "options", options, NULL);
- }
- else
- cnc = g_object_new (GDA_TYPE_CONNECTION,
- "provider", prov,
- "dsn", real_dsn,
- "auth-string", auth_string ? auth_string :
real_auth_string,
- "options", options, NULL);
- }
+ if (prov)
+ cnc = _gda_server_provider_create_connection (prov, real_dsn, NULL,
+ auth_string ? auth_string :
real_auth_string,
+ options);
}
else
g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_PROVIDER_NOT_FOUND_ERROR,
@@ -1203,32 +987,13 @@ gda_connection_new_from_dsn (const gchar *dsn, const gchar *auth_string,
* @options: options for the connection (see #GdaConnectionOptions).
* @error: a place to store an error, or %NULL
*
- * This function is the way of opening database connections with libgda, using a pre-defined data source
(DSN),
- * see gda_config_define_dsn() for more information about how to define a DSN. If you don't want to define
- * a DSN, it is possible to use gda_connection_open_from_string() instead of this method.
- *
- * The @dsn string must have the following format: "[<username>[:<password>] ]<DSN>"
- * (if <username> and/or <password> are provided, and @auth_string is %NULL, then these username
- * and passwords will be used). Note that if provided, <username> and <password>
- * must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information.
- *
- * The @auth_string can contain the authentication information for the server
- * to accept the connection. It is a string containing semi-colon seperated named value, usually
- * like "USERNAME=...;PASSWORD=..." where the ... are replaced by actual values. Note that each
- * name and value must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information.
- *
- * The actual named parameters required depend on the provider being used, and that list is available
- * as the <parameter>auth_params</parameter> member of the #GdaProviderInfo structure for each installed
- * provider (use gda_config_get_provider_info() to get it). Also one can use the "gda-sql-5.0 -L" command to
- * list the possible named parameters.
- *
- * This method may fail with a GDA_CONNECTION_ERROR domain error (see the #GdaConnectionError error codes)
- * or a %GDA_CONFIG_ERROR domain error (see the #GdaConfigError error codes).
+ * This function creates a connection and opens it, using a DSN. If opening fails, then no connection is
created.
+ * See gda_connection_new_from_dsn() for more information.
*
* Returns: (transfer full): a new #GdaConnection if connection opening was successful or %NULL if there was
an error.
*/
GdaConnection *
-gda_connection_open_from_dsn (const gchar *dsn, const gchar *auth_string,
+gda_connection_open_from_dsn (const gchar *dsn, const gchar *auth_string,
GdaConnectionOptions options, GError **error)
{
GdaConnection *cnc;
@@ -1249,10 +1014,47 @@ gda_connection_open_from_dsn (const gchar *dsn, const gchar *auth_string,
* @options: options for the connection (see #GdaConnectionOptions).
* @error: a place to store an error, or %NULL
*
- * This function is similar to gda_connection_open_from_string(), except it does not actually open the
- * connection, you have to open it using gda_connection_open().
+ * Opens a connection given a provider ID and a connection string. This
+ * allows applications to open connections without having to create
+ * a data source (DSN) in the configuration. The format of @cnc_string is
+ * similar to PostgreSQL and MySQL connection strings. It is a semicolumn-separated
+ * series of <key>=<value> pairs, where each key and value are encoded as per RFC 1738,
+ * see gda_rfc1738_encode() for more information.
+ *
+ * The possible keys depend on the provider, the "gda-sql-5.0 -L" command
+ * can be used to list the actual keys for each installed database provider.
*
- * Returns: (transfer full): a new #GdaConnection if connection opening was successful or %NULL if there was
an error.
+ * For example the connection string to open an SQLite connection to a database
+ * file named "my_data.db" in the current directory would be <constant>"DB_DIR=.;DB_NAME=my_data"</constant>.
+ *
+ * The @cnc_string string must have the following format:
+ * "[<provider>://][<username>[:<password>] ]<connection_params>"
+ * (if <username> and/or <password> are provided, and @auth_string is %NULL, then these username
+ * and passwords will be used, and if <provider> is provided and @provider_name is %NULL then this
+ * provider will be used). Note that if provided, <username>, <password> and <provider>
+ * must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information.
+ *
+ * The @auth_string must contain the authentication information for the server
+ * to accept the connection. It is a string containing semi-colon seperated named values, usually
+ * like "USERNAME=...;PASSWORD=..." where the ... are replaced by actual values. Note that each
+ * name and value must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information.
+ *
+ * The actual named parameters required depend on the provider being used, and that list is available
+ * as the <parameter>auth_params</parameter> member of the #GdaProviderInfo structure for each installed
+ * provider (use gda_config_get_provider_info() to get it). Similarly to the format of the connection
+ * string, use the "gda-sql-5.0 -L" command to list the possible named parameters.
+ *
+ * Additionally, it is possible to have the connection string
+ * respect the "<provider_name>://<real cnc string>" format, in which case the provider name
+ * and the real connection string will be extracted from that string (note that if @provider_name
+ * is not %NULL then it will still be used as the provider ID).\
+ *
+ * This method may fail with a GDA_CONNECTION_ERROR domain error (see the #GdaConnectionError error codes)
+ * or a %GDA_CONFIG_ERROR domain error (see the #GdaConfigError error codes).
+ *
+ * The returned connection is not yet opened, you need to call gda_connection_open() or
gda_connection_open_async().
+ *
+ * Returns: (transfer full): a new #GdaConnection or %NULL if there was an error.
*
* Since: 5.0.2
*/
@@ -1266,13 +1068,6 @@ gda_connection_new_from_string (const gchar *provider_name, const gchar *cnc_str
g_return_val_if_fail (cnc_string && *cnc_string, NULL);
- if (options & GDA_CONNECTION_OPTIONS_THREAD_SAFE &&
- !g_thread_supported ()) {
- g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_UNSUPPORTED_THREADS_ERROR,
- "%s", _("Multi threading is not supported or enabled"));
- return NULL;
- }
-
gda_connection_string_split (cnc_string, &real_cnc, &real_provider, &user, &pass);
if (!real_cnc) {
g_free (user);
@@ -1312,41 +1107,15 @@ gda_connection_new_from_string (const gchar *provider_name, const gchar *cnc_str
GdaServerProvider *prov = NULL;
pinfo = gda_config_get_provider_info (provider_name ? provider_name : real_provider);
- if (pinfo) {
+ if (pinfo)
prov = gda_config_get_provider (provider_name ? provider_name : real_provider, error);
- if (((options & GDA_CONNECTION_OPTIONS_THREAD_SAFE) &&
- !gda_server_provider_supports_feature (prov, NULL,
- GDA_CONNECTION_FEATURE_MULTI_THREADING))
||
- (options & GDA_CONNECTION_OPTIONS_THREAD_ISOLATED)) {
- gchar *tmp;
- tmp = g_strdup_printf ("%s;PROVIDER_NAME=%s", real_cnc, pinfo->id);
- g_free (real_cnc);
- real_cnc = tmp;
- options |= GDA_CONNECTION_OPTIONS_THREAD_ISOLATED;
- prov = _gda_connection_get_internal_thread_provider ();
- }
- }
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)
- g_object_set (G_OBJECT (cnc),
- "provider", prov,
- "cnc-string", real_cnc,
- "auth-string", auth_string ? auth_string :
real_auth_string,
- "options", options, NULL);
- }
- else
- cnc = (GdaConnection *) g_object_new (GDA_TYPE_CONNECTION,
- "provider", prov,
- "cnc-string", real_cnc,
- "auth-string", auth_string ?
auth_string : real_auth_string,
- "options", options, NULL);
- }
+ if (prov)
+ cnc = _gda_server_provider_create_connection (prov, NULL, real_cnc,
+ auth_string ? auth_string :
real_auth_string, options);
}
g_free (real_auth_string);
@@ -1366,43 +1135,8 @@ gda_connection_new_from_string (const gchar *provider_name, const gchar *cnc_str
* @options: options for the connection (see #GdaConnectionOptions).
* @error: a place to store an error, or %NULL
*
- * Opens a connection given a provider ID and a connection string. This
- * allows applications to open connections without having to create
- * a data source (DSN) in the configuration. The format of @cnc_string is
- * similar to PostgreSQL and MySQL connection strings. It is a semicolumn-separated
- * series of <key>=<value> pairs, where each key and value are encoded as per RFC 1738,
- * see gda_rfc1738_encode() for more information.
- *
- * The possible keys depend on the provider, the "gda-sql-5.0 -L" command
- * can be used to list the actual keys for each installed database provider.
- *
- * For example the connection string to open an SQLite connection to a database
- * file named "my_data.db" in the current directory would be <constant>"DB_DIR=.;DB_NAME=my_data"</constant>.
- *
- * The @cnc_string string must have the following format:
- * "[<provider>://][<username>[:<password>] ]<connection_params>"
- * (if <username> and/or <password> are provided, and @auth_string is %NULL, then these username
- * and passwords will be used, and if <provider> is provided and @provider_name is %NULL then this
- * provider will be used). Note that if provided, <username>, <password> and <provider>
- * must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information.
- *
- * The @auth_string must contain the authentication information for the server
- * to accept the connection. It is a string containing semi-colon seperated named values, usually
- * like "USERNAME=...;PASSWORD=..." where the ... are replaced by actual values. Note that each
- * name and value must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information.
- *
- * The actual named parameters required depend on the provider being used, and that list is available
- * as the <parameter>auth_params</parameter> member of the #GdaProviderInfo structure for each installed
- * provider (use gda_config_get_provider_info() to get it). Similarly to the format of the connection
- * string, use the "gda-sql-5.0 -L" command to list the possible named parameters.
- *
- * Additionally, it is possible to have the connection string
- * respect the "<provider_name>://<real cnc string>" format, in which case the provider name
- * and the real connection string will be extracted from that string (note that if @provider_name
- * is not %NULL then it will still be used as the provider ID).\
- *
- * This method may fail with a GDA_CONNECTION_ERROR domain error (see the #GdaConnectionError error codes)
- * or a %GDA_CONFIG_ERROR domain error (see the #GdaConfigError error codes).
+ * This function creates a connection and opens it, using a connection string. If opening fails, then no
connection is created.
+ * See gda_connection_new_from_string() for more information.
*
* Returns: (transfer full): a new #GdaConnection if connection opening was successful or %NULL if there was
an error.
*/
@@ -1426,36 +1160,21 @@ gda_connection_open_from_string (const gchar *provider_name, const gchar *cnc_st
GdaConnection *
_gda_open_internal_sqlite_connection (const gchar *cnc_string)
{
- GdaConnection *cnc;
+ GdaConnection *cnc = NULL;
GdaServerProvider *prov = _gda_config_sqlite_provider;
gchar *user, *pass, *real_cnc, *real_provider;
/*g_print ("%s(%s)\n", __FUNCTION__, cnc_string);*/
gda_connection_string_split (cnc_string, &real_cnc, &real_provider, &user, &pass);
- if (!real_cnc) {
- g_free (user);
- g_free (pass);
- g_free (real_provider);
+ g_free (user);
+ g_free (pass);
+ g_free (real_provider);
+
+ if (!real_cnc)
return NULL;
- }
- if (PROV_CLASS (prov)->create_connection) {
- cnc = PROV_CLASS (prov)->create_connection (prov);
- if (cnc)
- g_object_set (G_OBJECT (cnc),
- "provider", prov,
- "cnc-string", real_cnc,
- NULL);
- }
- else
- cnc = (GdaConnection *) g_object_new (GDA_TYPE_CONNECTION,
- "provider", prov,
- "cnc-string", real_cnc,
- NULL);
-
+
+ cnc = _gda_server_provider_create_connection (prov, NULL, real_cnc, NULL,
GDA_CONNECTION_OPTIONS_NONE);
g_free (real_cnc);
- g_free (user);
- g_free (pass);
- g_free (real_provider);
/* open the connection */
if (!gda_connection_open (cnc, NULL)) {
@@ -1532,31 +1251,30 @@ gda_connection_open_sqlite (const gchar *directory, const gchar *filename, gbool
g_free (fname);
return cnc;
}
-
-/**
- * gda_connection_open:
- * @cnc: a #GdaConnection object
- * @error: a place to store errors, or %NULL
- *
- * Tries to open the connection.
+/*
+ * Upon return, @out_params and @out_auth point to new #GdaQuarkList
*
- * Returns: TRUE if the connection is opened, and FALSE otherwise.
+ * Returns: %TRUE if no error occurred
*/
-gboolean
-gda_connection_open (GdaConnection *cnc, GError **error)
+static gboolean
+compute_params_and_auth_quarks (GdaConnection *cnc, GdaQuarkList **out_params, GdaQuarkList **out_auth,
GError **error)
{
GdaDsnInfo *dsn_info = NULL;
GdaQuarkList *params, *auth;
- char *real_auth_string = NULL;
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
-
- /* don't do anything if connection is already opened */
- if (cnc->priv->provider_data)
- return TRUE;
+ *out_params = NULL;
+ *out_auth = NULL;
gda_connection_lock ((GdaLockable*) cnc);
+ /* provider test */
+ if (!cnc->priv->provider_obj) {
+ g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_NO_PROVIDER_SPEC_ERROR,
+ "%s", _("No provider specified"));
+ gda_connection_unlock ((GdaLockable*) cnc);
+ return FALSE;
+ }
+
/* connection string */
if (cnc->priv->dsn) {
/* get the data source info */
@@ -1582,49 +1300,10 @@ gda_connection_open (GdaConnection *cnc, GError **error)
}
/* try to see if connection string has the <provider>://<rest of the string> format */
}
-
- /* provider test */
- if (!cnc->priv->provider_obj) {
- g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_NO_PROVIDER_SPEC_ERROR,
- "%s", _("No provider specified"));
- gda_connection_unlock ((GdaLockable*) cnc);
- return FALSE;
- }
-
- /* if there is a limiting thread but it's not yet set, then initialize it to the current
- * thread */
- if (PROV_CLASS (cnc->priv->provider_obj)->limiting_thread ==
- GDA_SERVER_PROVIDER_UNDEFINED_LIMITING_THREAD)
- PROV_CLASS (cnc->priv->provider_obj)->limiting_thread = g_thread_self ();
-
- if (PROV_CLASS (cnc->priv->provider_obj)->limiting_thread &&
- (PROV_CLASS (cnc->priv->provider_obj)->limiting_thread != g_thread_self ())) {
- /* WARNING:
- * Prior to GLib 2.32, this code used to check if the
- * PROV_CLASS (cnc->priv->provider_obj)->limiting_thread
- * was still active (i.e. not finished) and if so, the
- * PROV_CLASS (cnc->priv->provider_obj)->limiting_thread would
- * become g_thread_self().
- *
- * Now, if PROV_CLASS (cnc->priv->provider_obj)->limiting_thread is set and
- * if it's not equal to g_thread_self() then an error is returned.
- */
- g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_PROVIDER_ERROR,
- "%s", _("Provider does not allow usage from this thread"));
- gda_connection_unlock ((GdaLockable*) cnc);
- return FALSE;
- }
-
- if (!PROV_CLASS (cnc->priv->provider_obj)->open_connection) {
- g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_PROVIDER_ERROR,
- "%s", _("Internal error: provider does not implement the open_connection()
virtual method"));
- gda_connection_unlock ((GdaLockable*) cnc);
- return FALSE;
- }
-
params = gda_quark_list_new_from_string (cnc->priv->cnc_string);
- /* retrieve correct auth_string */
+ /* authentication string */
+ char *real_auth_string;
if (cnc->priv->auth_string)
real_auth_string = g_strdup (cnc->priv->auth_string);
else {
@@ -1634,93 +1313,94 @@ gda_connection_open (GdaConnection *cnc, GError **error)
/* look for authentication parameters in cnc string */
real_auth_string = g_strdup (cnc->priv->cnc_string);
}
-
- /* try to open the connection */
auth = gda_quark_list_new_from_string (real_auth_string);
- gboolean opened;
+ g_free (real_auth_string);
- opened = PROV_CLASS (cnc->priv->provider_obj)->open_connection (cnc->priv->provider_obj, cnc, params,
auth,
- NULL, NULL, NULL);
- gda_quark_list_protect_values (params);
- gda_quark_list_protect_values (auth);
+ gda_connection_unlock ((GdaLockable*) cnc);
- if (opened && !cnc->priv->provider_data) {
- g_warning ("Internal error: connection reported as opened, yet no provider data set");
- opened = FALSE;
- }
+ *out_params = params;
+ *out_auth = auth;
- if (!opened) {
- const GList *events;
-
- events = gda_connection_get_events (cnc);
- if (events) {
- GList *l;
-
- for (l = g_list_last ((GList*) events); l; l = l->prev) {
- GdaConnectionEvent *event;
-
- event = GDA_CONNECTION_EVENT (l->data);
- if (gda_connection_event_get_event_type (event) ==
GDA_CONNECTION_EVENT_ERROR) {
- if (error && !(*error))
- g_set_error (error, GDA_CONNECTION_ERROR,
GDA_CONNECTION_OPEN_ERROR,
- "%s", gda_connection_event_get_description
(event));
- }
- }
- }
- }
+ return TRUE;
+}
- /* free memory */
- gda_quark_list_free (params);
- gda_quark_list_free (auth);
- g_free (real_auth_string);
+/**
+ * gda_connection_open:
+ * @cnc: a #GdaConnection object
+ * @error: a place to store errors, or %NULL
+ *
+ * Tries to open the connection. The function either blocks or, if a #GMaincontext has been specified using
+ * gda_connection_set_main_context(), processes the events for that main context until either the
+ * connection opening has succeeded or failed.
+ *
+ * If the connection is already opened, then this function returns %TRUE immediately.
+ *
+ * Returns: TRUE if the connection is opened, and FALSE otherwise.
+ */
+gboolean
+gda_connection_open (GdaConnection *cnc, GError **error)
+{
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
- if (cnc->priv->provider_data) {
-#ifdef GDA_DEBUG_signal
- g_print (">> 'CONN_OPENED' from %s\n", __FUNCTION__);
-#endif
- g_signal_emit (G_OBJECT (cnc), gda_connection_signals[CONN_OPENED], 0);
-#ifdef GDA_DEBUG_signal
- g_print ("<< 'CONN_OPENED' from %s\n", __FUNCTION__);
-#endif
- }
+ /* don't do anything if connection is already opened */
+ if (gda_connection_is_opened (cnc))
+ return TRUE;
- /* limit connection's usable thread */
- if (PROV_CLASS (cnc->priv->provider_obj)->limiting_thread)
- g_object_set (G_OBJECT (cnc), "thread-owner",
- PROV_CLASS (cnc->priv->provider_obj)->limiting_thread, NULL);
+ GdaQuarkList *params, *auth;
+ if (!compute_params_and_auth_quarks (cnc, ¶ms, &auth, error))
+ return FALSE;
+ /* try to open the connection, with the "active waiting" at this point */
+ gboolean opened;
+ opened = _gda_server_provider_open_connection_sync (cnc->priv->provider_obj, cnc, params, auth,
error);
- gda_connection_unlock ((GdaLockable*) cnc);
- return cnc->priv->provider_data ? TRUE : FALSE;
-}
+ if (opened && !cnc->priv->provider_data) {
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ opened = FALSE;
+ }
+ return opened;
+}
/**
- * gda_connection_close:
- * @cnc: a #GdaConnection object.
+ * gda_connection_open_async:
+ * @cnc: a #GdaConnection object
+ * @callback: (scope notified): a #GdaConnectionOpenFunc which will be called after the connection has been
opened (of failed to open)
+ * @data: (allow-none): data to pass to @callback when called
+ * @error: a place to store errors, or %NULL
*
- * Closes the connection to the underlying data source, but first emits the
- * "conn-to-close" signal.
+ * This function requests that the connection be opened.
+ *
+ * If the connection is already opened, then this function returns an error (with the
%GDA_CONNECTION_ALREADY_OPENED_ERROR code).
+ *
+ * Note: @callback function will be called when processing events from the #GMainContext defined by
+ * gda_connection_set_main_context(), for example when there is a main loop for that main context.
+ *
+ * Returns: a job ID
+ *
+ * Since: 6.0
*/
-void
-gda_connection_close (GdaConnection *cnc)
+guint
+gda_connection_open_async (GdaConnection *cnc, GdaConnectionOpenFunc callback, gpointer data, GError **error)
{
- g_return_if_fail (GDA_IS_CONNECTION (cnc));
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), 0);
- if (! cnc->priv->provider_data)
- return;
+ /* return an error if connection is already opened */
+ if (gda_connection_is_opened (cnc)) {
+ g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_ALREADY_OPENED_ERROR,
+ "%s", _("Connection is alreay opened"));
+ }
- gda_connection_lock ((GdaLockable*) cnc);
-#ifdef GDA_DEBUG_signal
- g_print (">> 'CONN_TO_CLOSE' from %s\n", __FUNCTION__);
-#endif
- g_signal_emit (G_OBJECT (cnc), gda_connection_signals[CONN_TO_CLOSE], 0);
-#ifdef GDA_DEBUG_signal
- g_print ("<< 'CONN_TO_CLOSE' from %s\n", __FUNCTION__);
-#endif
+ GdaQuarkList *params, *auth;
+ if (!compute_params_and_auth_quarks (cnc, ¶ms, &auth, error))
+ return FALSE;
- gda_connection_close_no_warning (cnc);
- gda_connection_unlock ((GdaLockable*) cnc);
+ /* try to open the connection */
+ gboolean submitted;
+ guint job_id;
+ submitted = _gda_server_provider_open_connection_async (cnc->priv->provider_obj, cnc, params, auth,
+ callback, data, &job_id, error);
+ return submitted ? job_id : 0;
}
static void
@@ -1740,28 +1420,50 @@ add_connection_event_from_error (GdaConnection *cnc, GError **error)
}
/**
- * gda_connection_close_no_warning:
+ * gda_connection_close:
+ * @cnc: a #GdaConnection object.
+ *
+ * Closes the connection to the underlying data source, but first emits the
+ * "conn-to-close" signal.
+ */
+gboolean
+gda_connection_close (GdaConnection *cnc, GError **error)
+{
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+
+ if (! cnc->priv->provider_data)
+ return TRUE;
+
+#ifdef GDA_DEBUG_signal
+ g_print (">> 'CONN_TO_CLOSE' from %s\n", __FUNCTION__);
+#endif
+ g_signal_emit (G_OBJECT (cnc), gda_connection_signals[CONN_TO_CLOSE], 0);
+#ifdef GDA_DEBUG_signal
+ g_print ("<< 'CONN_TO_CLOSE' from %s\n", __FUNCTION__);
+#endif
+
+ return _gda_connection_close_no_warning (cnc, error);
+}
+
+/*
+ * _gda_connection_close_no_warning:
* @cnc: a #GdaConnection object.
*
* Closes the connection to the underlying data source, without emiting any warning signal.
*/
-void
-gda_connection_close_no_warning (GdaConnection *cnc)
+gboolean
+_gda_connection_close_no_warning (GdaConnection *cnc, GError **error)
{
- g_return_if_fail (GDA_IS_CONNECTION (cnc));
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_object_ref (cnc);
gda_connection_lock ((GdaLockable*) cnc);
- if (cnc->priv->monitor_id > 0) {
- g_source_remove (cnc->priv->monitor_id);
- cnc->priv->monitor_id = 0;
- }
-
if (! cnc->priv->provider_data) {
+ /* connection already closed */
g_object_unref (cnc);
gda_connection_unlock ((GdaLockable*) cnc);
- return;
+ return TRUE;
}
if (cnc->priv->meta_store &&
@@ -1793,28 +1495,39 @@ gda_connection_close_no_warning (GdaConnection *cnc)
}
/* really close connection */
- if (PROV_CLASS (cnc->priv->provider_obj)->close_connection)
- PROV_CLASS (cnc->priv->provider_obj)->close_connection (cnc->priv->provider_obj,
- cnc);
- if (cnc->priv->provider_data) {
- if (cnc->priv->provider_data_destroy_func)
- cnc->priv->provider_data_destroy_func (cnc->priv->provider_data);
- else if (cnc->priv->provider_data != cnc->priv->th_data)
- g_warning ("Provider did not clean its connection data");
- cnc->priv->provider_data = NULL;
- }
+ gboolean retval;
+ retval = _gda_server_provider_close_connection (cnc->priv->provider_obj, cnc, error);
gda_connection_unlock ((GdaLockable*) cnc);
-#ifdef GDA_DEBUG_signal
- g_print (">> 'CONN_CLOSED' from %s\n", __FUNCTION__);
-#endif
- g_signal_emit (G_OBJECT (cnc), gda_connection_signals[CONN_CLOSED], 0);
-#ifdef GDA_DEBUG_signal
- g_print ("<< 'CONN_CLOSED' from %s\n", __FUNCTION__);
-#endif
g_object_unref (cnc);
+
+ return retval;
}
+/*
+ * _gda_connection_get_worker:
+ *
+ * Returns: (transfer none): the #GdaWorker internally used by @cnc, or %NULL if connection is not yet opened
+ */
+GdaWorker *
+_gda_connection_get_worker (GdaConnection *cnc)
+{
+ if (cnc->priv->provider_data)
+ return cnc->priv->provider_data->worker;
+ else
+ return NULL;
+}
+
+/*
+ * _gda_connection_get_exec_slowdown:
+ *
+ * Returns: the number of milliseconds to wait when executing things, used for testing and debugging
+ */
+guint
+_gda_connection_get_exec_slowdown (GdaConnection *cnc)
+{
+ return cnc->priv->exec_slowdown;
+}
/**
* gda_connection_is_opened:
@@ -2653,7 +2366,7 @@ gda_connection_add_event (GdaConnection *cnc, GdaConnectionEvent *event)
g_return_if_fail (GDA_IS_CONNECTION (cnc));
g_return_if_fail (GDA_IS_CONNECTION_EVENT (event));
- g_rec_mutex_lock (& cnc->priv->rmutex);
+ gda_connection_lock ((GdaLockable*) cnc);
/* clear external list of events */
if (cnc->priv->events_list) {
@@ -2708,7 +2421,7 @@ gda_connection_add_event (GdaConnection *cnc, GdaConnectionEvent *event)
#ifdef GDA_DEBUG_NO
dump_events_array (cnc);
#endif
- g_rec_mutex_unlock (& cnc->priv->rmutex);
+ gda_connection_unlock ((GdaLockable*) cnc);
}
/**
@@ -2962,7 +2675,7 @@ gda_connection_quote_sql_identifier (GdaConnection *cnc, const gchar *id)
/**
* gda_connection_statement_to_sql:
- * @cnc: a #GdaConnection object
+ * @cnc: (allow-none): a #GdaConnection object, or %NULL
* @stmt: a #GdaStatement object
* @params: (allow-none): a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or
%NULL
* @flags: SQL rendering flags, as #GdaStatementSqlFlag OR'ed values
@@ -2977,16 +2690,22 @@ gchar *
gda_connection_statement_to_sql (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params, GdaStatementSqlFlag
flags,
GSList **params_used, GError **error)
{
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- g_return_val_if_fail (cnc->priv->provider_obj, NULL);
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (cnc->priv->provider_obj, NULL);
+ }
g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
- if (PROV_CLASS (cnc->priv->provider_obj)->statement_to_sql)
- return (PROV_CLASS (cnc->priv->provider_obj)->statement_to_sql) (cnc->priv->provider_obj,
- cnc, stmt, params, flags,
- params_used, error);
- else
- return gda_statement_to_sql_extended (stmt, cnc, params, flags, params_used, error);
+ gchar *sql = NULL;
+ if (cnc) {
+ if (gda_connection_is_opened (cnc))
+ sql = _gda_server_provider_statement_to_sql (cnc->priv->provider_obj, cnc, stmt,
params, flags,
+ params_used, error);
+ else
+ sql = _gda_server_provider_statement_to_sql (cnc->priv->provider_obj, NULL, stmt,
params, flags,
+ params_used, error);
+ }
+ return sql ? sql : gda_statement_to_sql_extended (stmt, cnc, params, flags, params_used, error);
}
/**
@@ -3015,14 +2734,7 @@ gda_connection_statement_prepare (GdaConnection *cnc, GdaStatement *stmt, GError
g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE);
- if (PROV_CLASS (cnc->priv->provider_obj)->statement_prepare)
- return (PROV_CLASS (cnc->priv->provider_obj)->statement_prepare)(cnc->priv->provider_obj,
- cnc, stmt, error);
- else {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
- "%s", _("Provider does not support statement preparation"));
- return FALSE;
- }
+ return _gda_server_provider_statement_prepare (cnc->priv->provider_obj, cnc, stmt, error);
}
/*
@@ -3084,421 +2796,14 @@ add_exec_time_to_object (GObject *obj, GTimer *timer)
}
/*
- * No locking is done here must be done before calling
- *
- * Returns: -1 if task not found
- */
-static gint
-get_task_index (GdaConnection *cnc, guint task_id, gboolean *out_completed, gboolean id_is_prov)
-{
- gint i, len;
- CncTask *task;
- len = cnc->priv->completed_tasks->len;
- for (i = 0; i < len; i++) {
- task = CNC_TASK (g_array_index (cnc->priv->completed_tasks, gpointer, i));
- if ((! id_is_prov && (task->task_id == task_id)) ||
- (id_is_prov && (task->prov_task_id == task_id))) {
- *out_completed = TRUE;
- return i;
- }
- }
-
- len = cnc->priv->waiting_tasks->len;
- for (i = 0; i < len; i++) {
- task = CNC_TASK (g_array_index (cnc->priv->waiting_tasks, gpointer, i));
- if ((! id_is_prov && (task->task_id == task_id)) ||
- (id_is_prov && (task->prov_task_id == task_id))) {
- *out_completed = FALSE;
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * This callback is called from the GdaServerProvider object, from the handle_async() method
- */
-static void
-async_stmt_exec_cb (G_GNUC_UNUSED GdaServerProvider *provider, GdaConnection *cnc, guint task_id,
- GObject *result_obj, const GError *error, G_GNUC_UNUSED CncTask *task)
-{
- gint i;
- gboolean is_completed;
-
- g_object_ref ((GObject*) cnc);
- gda_connection_lock (GDA_LOCKABLE (cnc));
-
- i = get_task_index (cnc, task_id, &is_completed, TRUE);
- if (i >= 0) {
- CncTask *task;
- g_assert (!is_completed);
-
- /* complete @task and free some memory */
- task = CNC_TASK (g_array_index (cnc->priv->waiting_tasks, gpointer, i));
- cnc_task_lock (task);
-
- task->being_processed = FALSE;
- if (task->exec_timer)
- g_timer_stop (task->exec_timer);
-
- if (error)
- task->error = g_error_copy (error);
- if (result_obj) {
- task->result = g_object_ref (result_obj);
- if (task->exec_timer)
- add_exec_time_to_object (task->result, task->exec_timer);
- }
- if (task->stmt) {
- g_signal_handlers_disconnect_by_func (task->stmt,
- G_CALLBACK (task_stmt_reset_cb), task);
- g_object_unref (task->stmt);
- task->stmt = NULL;
- }
- if (task->params) {
- g_object_unref (task->params);
- task->params = NULL;
- }
- if (task->col_types) {
- g_free (task->col_types);
- task->col_types = NULL;
- }
-
- g_array_remove_index (cnc->priv->waiting_tasks, i);
- g_array_append_val (cnc->priv->completed_tasks, task);
-
- cnc_task_unlock (task);
-
- /* execute next waiting task if there is one */
- while (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));
- cnc_task_lock (task);
- task->being_processed = TRUE;
- dump_exec_params (cnc, task->stmt, task->params);
- if (cnc->priv->exec_times)
- g_timer_start (task->exec_timer);
- if (cnc->priv->exec_slowdown && !cnc->priv->is_thread_wrapper)
- g_usleep (cnc->priv->exec_slowdown);
-
- PROV_CLASS (cnc->priv->provider_obj)->statement_execute (cnc->priv->provider_obj,
cnc,
- task->stmt,
- task->params,
- task->model_usage,
- task->col_types,
- &(task->last_insert_row),
- &(task->prov_task_id),
-
(GdaServerProviderExecCallback) async_stmt_exec_cb,
- task, &lerror);
- if (lerror) {
- /* task execution failed => move it to completed tasks array */
- task->error = lerror;
- task->being_processed = FALSE;
- if (cnc->priv->exec_times)
- g_timer_stop (task->exec_timer);
- g_array_remove_index (cnc->priv->waiting_tasks, 0);
- g_array_append_val (cnc->priv->completed_tasks, task);
- cnc_task_unlock (task);
- }
- else {
- update_meta_store_after_statement_exec (cnc, task->stmt, task->params);
- cnc_task_unlock (task);
- break;
- }
- }
- }
- else
- g_warning ("Provider called back for the execution of task %u (provider numbering) which does
not exist, "
- "ignored.\n", task_id);
-
- gda_connection_unlock (GDA_LOCKABLE (cnc));
- g_object_unref ((GObject*) cnc);
-}
-
-/**
- * gda_connection_async_statement_execute:
- * @cnc: a #GdaConnection
- * @stmt: a #GdaStatement object
- * @params: (allow-none): a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or
%NULL
- * @model_usage: in the case where @stmt is a SELECT statement, specifies how the returned data model will
be used
- * @col_types: (array) (allow-none): an array of GType to request each returned #GdaDataModel's column's
GType, terminated with the G_TYPE_NONE
- * @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 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 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.
- *
- * The execution failure of any statement has no impact on the execution of other statements except for
example if
- * the connection has a transaction started and the failure invalidates the transaction (as decided by the
database
- * server).
- *
- * Note that for asynchronous calls to succeed, it is gererally necessary to specify the
- * %GDA_CONNECTION_OPTIONS_THREAD_ISOLATED flag when opening the connection to be sure it is opened in a
separate thread
- * in which asynchronous calls are made (failing to use this flag make the asynchronous call dependant on
the database
- * provider implementation and at the moment none support this feature).
- *
- * Returns: a task ID, or 0 if an error occurred (not an error regarding @stmt itself as its execution has
not yet started
- * but any other error)
- *
- * Since: 4.2
- */
-guint
-gda_connection_async_statement_execute (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params,
- GdaStatementModelUsage model_usage, GType *col_types,
- gboolean need_last_insert_row,
- GError **error)
-{
- guint id;
- CncTask *task;
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), 0);
- g_return_val_if_fail (cnc->priv->provider_obj, 0);
- g_return_val_if_fail (GDA_IS_STATEMENT (stmt), 0);
- g_return_val_if_fail (PROV_CLASS (cnc->priv->provider_obj)->statement_execute, 0);
-
-
- g_object_ref ((GObject*) cnc);
- if (! gda_connection_trylock ((GdaLockable*) cnc)) {
- g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CANT_LOCK_ERROR,
- _("Can't obtain connection lock"));
- g_object_unref ((GObject*) cnc);
- return 0;
- }
-
- if (!cnc->priv->provider_data) {
- g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR,
- _("Connection is closed"));
- gda_connection_unlock (GDA_LOCKABLE (cnc));
- g_object_unref ((GObject*) cnc);
- return 0;
- }
-
- if (!PROV_CLASS (cnc->priv->provider_obj)->handle_async) {
- g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_UNSUPPORTED_ASYNC_EXEC_ERROR,
- _("Asynchronous execution is not supported"));
- gda_connection_unlock (GDA_LOCKABLE (cnc));
- g_object_unref ((GObject*) cnc);
- return 0;
- }
-
- id = cnc->priv->next_task_id ++;
- task = cnc_task_new (id, stmt, model_usage, col_types, params, need_last_insert_row);
- g_array_append_val (cnc->priv->waiting_tasks, task);
- if (cnc->priv->exec_times) {
- task->exec_timer = g_timer_new ();
- g_timer_stop (task->exec_timer);
- }
-
- if (cnc->priv->waiting_tasks->len == 1) {
- /* execute statement now as there are no other ones to be executed */
- GError *lerror = NULL;
-
- cnc_task_lock (task);
- task->being_processed = TRUE;
- dump_exec_params (cnc, task->stmt, task->params);
- if (cnc->priv->exec_times)
- g_timer_start (task->exec_timer);
- if (cnc->priv->exec_slowdown && !cnc->priv->is_thread_wrapper)
- g_usleep (cnc->priv->exec_slowdown);
-
- PROV_CLASS (cnc->priv->provider_obj)->statement_execute (cnc->priv->provider_obj, cnc,
- task->stmt,
- task->params,
- task->model_usage,
- task->col_types,
- &(task->last_insert_row),
- &(task->prov_task_id),
- (GdaServerProviderExecCallback)
async_stmt_exec_cb,
- task, &lerror);
- if (lerror) {
- /* task execution failed => move it to completed tasks array */
- gint i;
- gboolean is_completed;
-
- task->error = lerror;
- task->being_processed = FALSE;
- if (cnc->priv->exec_times)
- g_timer_stop (task->exec_timer);
- i = get_task_index (cnc, id, &is_completed, FALSE);
- g_assert ((i >= 0) && !is_completed);
- g_array_remove_index (cnc->priv->waiting_tasks, i);
- g_array_append_val (cnc->priv->completed_tasks, task);
- }
- else
- update_meta_store_after_statement_exec (cnc, task->stmt, task->params);
- cnc_task_unlock (task);
- }
-
- gda_connection_unlock ((GdaLockable*) cnc);
- g_object_unref ((GObject*) cnc);
-
- return id;
-}
-
-/**
- * gda_connection_async_fetch_result:
- * @cnc: a #GdaConnection
- * @task_id: a task ID returned by gda_connection_async_statement_execute()
- * @last_insert_row: (out) (transfer full) (allow-none): a place to store a new #GdaSet object which
contains the values of the last inserted row, or %NULL
- * @error: a place to store errors, or %NULL
- *
- * Use this method to obtain the result of the execution of a statement which has been executed
asynchronously by
- * calling gda_connection_async_statement_execute(). This function is non locking and will return %NULL (and
no
- * error will be set) if the statement has not been executed yet.
- *
- * If the statement has been executed, this method returns the same value as
gda_connection_statement_execute()
- * would have if the statement had been
- * executed synchronously.
- *
- * Returns: (transfer full): a #GObject, or %NULL if an error occurred
- *
- * Since: 4.2
- */
-GObject *
-gda_connection_async_fetch_result (GdaConnection *cnc, guint task_id, GdaSet **last_insert_row, GError
**error)
-{
- gint i;
- gboolean is_completed;
- GObject *obj = NULL;
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- g_return_val_if_fail (cnc->priv->provider_obj, NULL);
-
- if (! gda_connection_trylock ((GdaLockable*) cnc)) {
- g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CANT_LOCK_ERROR,
- _("Can't obtain connection lock"));
- return NULL;
- }
-
- /* if provider needs to be awaken, then do it now */
- if (PROV_CLASS (cnc->priv->provider_obj)->handle_async) {
- if (! (PROV_CLASS (cnc->priv->provider_obj)->handle_async (cnc->priv->provider_obj, cnc,
error))) {
- gda_connection_unlock ((GdaLockable*) cnc);
- return NULL;
- }
- }
-
- i = get_task_index (cnc, task_id, &is_completed, FALSE);
- if (i < 0) {
- g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_TASK_NOT_FOUND_ERROR,
- _("Can't find task %u"), task_id);
- }
- else if (is_completed) {
- /* task completed */
- CncTask *task;
- task = CNC_TASK (g_array_index (cnc->priv->completed_tasks, gpointer, i));
- g_array_remove_index (cnc->priv->completed_tasks, i);
-
- cnc_task_lock (task);
- if (task->result)
- obj = g_object_ref (task->result);
- if (task->error) {
- g_propagate_error (error, task->error);
- task->error = NULL;
- }
- if (last_insert_row) {
- if (task->last_insert_row)
- *last_insert_row = g_object_ref (task->last_insert_row);
- else
- *last_insert_row = NULL;
- }
- cnc_task_unlock (task);
- cnc_task_free (task);
- }
- else {
- /* task not yet completed */
- /* nothing to do */
- }
-
- gda_connection_unlock ((GdaLockable*) cnc);
- return obj;
-}
-
-/**
- * gda_connection_async_cancel:
- * @cnc: a #GdaConnection
- * @task_id: a task ID returned by gda_connection_async_statement_execute()
- * @error: a place to store errors, or %NULL
- *
- * Requests that a task be cancelled. This operation may of may not have any effect
- * depending on the task's status, even if it returns %TRUE. If it returns %FALSE,
- * then the task has not been cancelled.
- *
- * Returns: TRUE if no error occurred
- *
- * Since: 4.2
- */
-gboolean
-gda_connection_async_cancel (GdaConnection *cnc, guint task_id, GError **error)
-{
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
- g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
-
- if (! gda_connection_trylock ((GdaLockable*) cnc)) {
- g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CANT_LOCK_ERROR,
- _("Can't obtain connection lock"));
- return FALSE;
- }
-
- gint i;
- gboolean is_completed;
- gboolean retval = TRUE;
- i = get_task_index (cnc, task_id, &is_completed, FALSE);
- if ((i >= 0) && (!is_completed)) {
- CncTask *task;
- task = CNC_TASK (g_array_index (cnc->priv->waiting_tasks, gpointer, i));
- if (task->being_processed) {
- if (PROV_CLASS (cnc->priv->provider_obj)->cancel) {
- retval = PROV_CLASS (cnc->priv->provider_obj)->cancel
(cnc->priv->provider_obj, cnc,
- task->prov_task_id,
error);
- if (retval) {
- /* cancellation may have succeeded => remove this task from the tasks
to execute */
- g_array_remove_index (cnc->priv->waiting_tasks, i);
- cnc_task_free (task);
- }
- }
- else {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
- "%s", _("Provider does not support asynchronous server
operation"));
- retval = FALSE;
- }
- task->being_processed = FALSE;
- if (cnc->priv->exec_times)
- g_timer_stop (task->exec_timer);
- }
- else {
- /* simply remove this task from the tasks to execute */
- g_array_remove_index (cnc->priv->waiting_tasks, i);
- cnc_task_free (task);
- }
- }
- else if (i < 0) {
- g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_TASK_NOT_FOUND_ERROR,
- _("Can't find task %u"), task_id);
- retval = FALSE;
- }
-
- gda_connection_unlock ((GdaLockable*) cnc);
- return retval;
-}
-
-/*
- * Wrapper which adds @...
+ * Wrapper which adds @... ellipse
*/
static GObject *
gda_connection_statement_execute_v (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params,
GdaStatementModelUsage model_usage, GdaSet **last_inserted_row, GError
**error, ...)
{
va_list ap;
- GObject *obj;
+ GObject *obj = NULL;
GType *types, *req_types;
GTimer *timer = NULL;
va_start (ap, error);
@@ -3506,9 +2811,10 @@ gda_connection_statement_execute_v (GdaConnection *cnc, GdaStatement *stmt, GdaS
va_end (ap);
g_object_ref ((GObject*) cnc);
- gda_connection_lock ((GdaLockable*) cnc);
+ gda_connection_lock ((GdaLockable*) cnc);
_clear_connection_events (cnc);
+ gda_connection_unlock ((GdaLockable*) cnc);
if (last_inserted_row)
*last_inserted_row = NULL;
@@ -3516,7 +2822,6 @@ gda_connection_statement_execute_v (GdaConnection *cnc, GdaStatement *stmt, GdaS
if (!cnc->priv->provider_data) {
g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR,
_("Connection is closed"));
- gda_connection_unlock (GDA_LOCKABLE (cnc));
g_object_unref ((GObject*) cnc);
g_free (types);
return NULL;
@@ -3538,14 +2843,9 @@ gda_connection_statement_execute_v (GdaConnection *cnc, GdaStatement *stmt, GdaS
dump_exec_params (cnc, stmt, params);
if (cnc->priv->exec_times)
timer = g_timer_new ();
- if (cnc->priv->exec_slowdown && !cnc->priv->is_thread_wrapper)
- g_usleep (cnc->priv->exec_slowdown);
-
- obj = PROV_CLASS (cnc->priv->provider_obj)->statement_execute (cnc->priv->provider_obj, cnc, stmt,
params,
- model_usage,
- req_types ? req_types : types,
- last_inserted_row,
- NULL, NULL, NULL, error);
+
+ obj = _gda_server_provider_statement_execute (cnc->priv->provider_obj, cnc, stmt, params, model_usage,
+ req_types ? req_types : types, last_inserted_row,
error);
if (timer)
g_timer_stop (timer);
g_free (types);
@@ -3560,7 +2860,7 @@ gda_connection_statement_execute_v (GdaConnection *cnc, GdaStatement *stmt, GdaS
obj = NULL;
}
}
- gda_connection_unlock ((GdaLockable*) cnc);
+
g_object_unref ((GObject*) cnc);
if (timer)
g_timer_destroy (timer);
@@ -3717,10 +3017,6 @@ gda_connection_statement_execute (GdaConnection *cnc, GdaStatement *stmt, GdaSet
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (cnc->priv->provider_obj, NULL);
g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
- g_return_val_if_fail (PROV_CLASS (cnc->priv->provider_obj)->statement_execute, NULL);
-
- if (last_inserted_row)
- *last_inserted_row = NULL;
return gda_connection_statement_execute_v (cnc, stmt, params, model_usage, last_inserted_row, error,
-1);
}
@@ -3755,7 +3051,6 @@ gda_connection_statement_execute_non_select (GdaConnection *cnc, GdaStatement *s
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), -1);
g_return_val_if_fail (cnc->priv->provider_obj, -1);
g_return_val_if_fail (GDA_IS_STATEMENT (stmt), -1);
- g_return_val_if_fail (PROV_CLASS (cnc->priv->provider_obj)->statement_execute, -1);
if ((gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT) ||
(gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_COMPOUND)) {
@@ -3825,7 +3120,6 @@ gda_connection_statement_execute_select (GdaConnection *cnc, GdaStatement *stmt,
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (cnc->priv->provider_obj, NULL);
g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
- g_return_val_if_fail (PROV_CLASS (cnc->priv->provider_obj)->statement_execute, NULL);
model = (GdaDataModel *) gda_connection_statement_execute_v (cnc, stmt, params,
GDA_STATEMENT_MODEL_RANDOM_ACCESS, NULL,
@@ -3871,10 +3165,9 @@ gda_connection_statement_execute_select_fullv (GdaConnection *cnc, GdaStatement
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (cnc->priv->provider_obj, NULL);
g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
- g_return_val_if_fail (PROV_CLASS (cnc->priv->provider_obj)->statement_execute, NULL);
va_list ap;
- GdaDataModel *model;
+ GdaDataModel *model = NULL;
GType *types, *req_types;
GTimer *timer = NULL;
@@ -3883,14 +3176,14 @@ gda_connection_statement_execute_select_fullv (GdaConnection *cnc, GdaStatement
va_end (ap);
g_object_ref ((GObject*) cnc);
- gda_connection_lock ((GdaLockable*) cnc);
+ gda_connection_lock ((GdaLockable*) cnc);
_clear_connection_events (cnc);
+ gda_connection_unlock ((GdaLockable*) cnc);
if (!cnc->priv->provider_data) {
g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR,
_("Connection is closed"));
- gda_connection_unlock (GDA_LOCKABLE (cnc));
g_object_unref ((GObject*) cnc);
g_free (types);
return NULL;
@@ -3912,17 +3205,12 @@ gda_connection_statement_execute_select_fullv (GdaConnection *cnc, GdaStatement
dump_exec_params (cnc, stmt, params);
if (cnc->priv->exec_times)
timer = g_timer_new ();
- if (cnc->priv->exec_slowdown && !cnc->priv->is_thread_wrapper)
- g_usleep (cnc->priv->exec_slowdown);
-
- model = (GdaDataModel *) PROV_CLASS (cnc->priv->provider_obj)->statement_execute
(cnc->priv->provider_obj,
- cnc, stmt, params,
model_usage,
- req_types ?
req_types : types,
- NULL, NULL,
- NULL, NULL, error);
+
+ model = (GdaDataModel*) _gda_server_provider_statement_execute (cnc->priv->provider_obj, cnc, stmt,
params, model_usage,
+ req_types ? req_types : types, NULL,
error);
if (timer)
g_timer_stop (timer);
- gda_connection_unlock ((GdaLockable*) cnc);
+
g_object_unref ((GObject*) cnc);
g_free (types);
if (model && timer)
@@ -3976,21 +3264,22 @@ gda_connection_statement_execute_select_full (GdaConnection *cnc, GdaStatement *
GdaSet *params, GdaStatementModelUsage model_usage,
GType *col_types, GError **error)
{
- GdaDataModel *model;
+ GdaDataModel *model = NULL;
GTimer *timer = NULL;
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (cnc->priv->provider_obj, NULL);
g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
- g_return_val_if_fail (PROV_CLASS (cnc->priv->provider_obj)->statement_execute, NULL);
g_object_ref ((GObject*) cnc);
+
gda_connection_lock ((GdaLockable*) cnc);
+ _clear_connection_events (cnc);
+ gda_connection_unlock ((GdaLockable*) cnc);
if (!cnc->priv->provider_data) {
g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR,
_("Connection is closed"));
- gda_connection_unlock (GDA_LOCKABLE (cnc));
g_object_unref ((GObject*) cnc);
return NULL;
}
@@ -4007,19 +3296,12 @@ gda_connection_statement_execute_select_full (GdaConnection *cnc, GdaStatement *
dump_exec_params (cnc, stmt, params);
if (cnc->priv->exec_times)
timer = g_timer_new ();
- if (cnc->priv->exec_slowdown && !cnc->priv->is_thread_wrapper)
- g_usleep (cnc->priv->exec_slowdown);
-
- model = (GdaDataModel *) PROV_CLASS (cnc->priv->provider_obj)->statement_execute
(cnc->priv->provider_obj,
- cnc, stmt, params,
- model_usage,
- req_types ?
req_types : col_types,
- NULL,
- NULL, NULL, NULL,
error);
+
+ model = (GdaDataModel*) _gda_server_provider_statement_execute (cnc->priv->provider_obj, cnc, stmt,
params, model_usage,
+ req_types ? req_types : col_types,
NULL, error);
if (timer)
g_timer_stop (timer);
g_free (req_types);
- gda_connection_unlock ((GdaLockable*) cnc);
g_object_unref ((GObject*) cnc);
if (model && timer)
@@ -4075,18 +3357,19 @@ gda_connection_repetitive_statement_execute (GdaConnection *cnc, GdaRepetitiveSt
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (cnc->priv->provider_obj, NULL);
g_return_val_if_fail (GDA_IS_REPETITIVE_STATEMENT (rstmt), NULL);
- g_return_val_if_fail (PROV_CLASS (cnc->priv->provider_obj)->statement_execute, NULL);
g_object_get (rstmt, "statement", &stmt, NULL);
g_return_val_if_fail (stmt, NULL);
g_object_ref ((GObject*) cnc);
+
gda_connection_lock ((GdaLockable*) cnc);
+ _clear_connection_events (cnc);
+ gda_connection_unlock ((GdaLockable*) cnc);
if (!cnc->priv->provider_data) {
g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR,
_("Connection is closed"));
- gda_connection_unlock (GDA_LOCKABLE (cnc));
g_object_unref ((GObject*) cnc);
return NULL;
}
@@ -4102,22 +3385,17 @@ gda_connection_repetitive_statement_execute (GdaConnection *cnc, GdaRepetitiveSt
sets_list = gda_repetitive_statement_get_all_sets (rstmt);
for (list = sets_list; list; list = list->next) {
- GObject *obj;
+ GObject *obj = NULL;
GError *lerror = NULL;
GTimer *timer = NULL;
dump_exec_params (cnc, stmt, (GdaSet*) list->data);
if (cnc->priv->exec_times)
timer = g_timer_new ();
- if (cnc->priv->exec_slowdown && !cnc->priv->is_thread_wrapper)
- g_usleep (cnc->priv->exec_slowdown);
-
- obj = PROV_CLASS (cnc->priv->provider_obj)->statement_execute (cnc->priv->provider_obj, cnc,
stmt,
- GDA_SET (list->data),
- model_usage,
- req_types ? req_types :
col_types,
- NULL,
- NULL, NULL, NULL, &lerror);
+
+ obj = _gda_server_provider_statement_execute (cnc->priv->provider_obj, cnc, stmt, GDA_SET
(list->data),
+ model_usage, req_types ? req_types : col_types,
+ NULL, &lerror);
if (timer)
g_timer_stop (timer);
if (!obj) {
@@ -4154,60 +3432,25 @@ gda_connection_repetitive_statement_execute (GdaConnection *cnc, GdaRepetitiveSt
g_slist_free (sets_list);
g_free (req_types);
- gda_connection_unlock ((GdaLockable*) cnc);
g_object_unref ((GObject*) cnc);
g_object_unref (stmt);
return g_slist_reverse (retlist);
}
-/*
- * Forces the GdaTransactionStatus. This is reserved to connections which are thread wrappers
- *
- * @trans_status may be NULL
- * if @trans_status is not NULL, then its ref count is increased.
- */
-void
-_gda_connection_force_transaction_status (GdaConnection *cnc, GdaConnection *wrapped_cnc)
-{
- g_assert (cnc->priv->is_thread_wrapper);
- if (cnc->priv->trans_status)
- g_object_unref (cnc->priv->trans_status);
-
- cnc->priv->trans_status = wrapped_cnc->priv->trans_status;
- if (cnc->priv->trans_status)
- g_object_ref (cnc->priv->trans_status);
-
-#ifdef GDA_DEBUG_signal
- g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
-#endif
- g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0);
-#ifdef GDA_DEBUG_signal
- g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
-#endif
-
-#ifdef GDA_DEBUG_NO
- if (cnc->priv->trans_status)
- gda_transaction_status_dump (cnc->priv->trans_status, 5);
-#endif
-}
-
/**
* gda_connection_begin_transaction:
* @cnc: a #GdaConnection object.
* @name: (allow-none): the name of the transation to start, or %NULL
- * @level: the requested transaction level (%GDA_TRANSACTION_ISOLATION_UNKNOWN if not specified)
+ * @level: the requested transaction level (use %GDA_TRANSACTION_ISOLATION_SERVER_DEFAULT to apply the
server default)
* @error: a place to store errors, or %NULL
*
- * Starts a transaction on the data source, identified by the
- * @name parameter.
+ * Starts a transaction on the data source, identified by the @name parameter.
*
* Before starting a transaction, you can check whether the underlying
- * provider does support transactions or not by using the
- * gda_connection_supports_feature() function.
+ * provider does support transactions or not by using the gda_connection_supports_feature() function.
*
- * Returns: %TRUE if the transaction was started successfully, %FALSE
- * otherwise.
+ * Returns: %TRUE if the transaction was started successfully with the corresponding isolation level, %FALSE
otherwise.
*/
gboolean
gda_connection_begin_transaction (GdaConnection *cnc, const gchar *name, GdaTransactionIsolation level,
@@ -4216,10 +3459,7 @@ gda_connection_begin_transaction (GdaConnection *cnc, const gchar *name, GdaTran
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
- if (PROV_CLASS (cnc->priv->provider_obj)->begin_transaction)
- return PROV_CLASS (cnc->priv->provider_obj)->begin_transaction (cnc->priv->provider_obj, cnc,
name, level, error);
- else
- return FALSE;
+ return _gda_server_provider_begin_transaction (cnc->priv->provider_obj, cnc, name, level, error);
}
/**
@@ -4240,10 +3480,7 @@ gda_connection_commit_transaction (GdaConnection *cnc, const gchar *name, GError
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
- if (PROV_CLASS (cnc->priv->provider_obj)->commit_transaction)
- return PROV_CLASS (cnc->priv->provider_obj)->commit_transaction (cnc->priv->provider_obj,
cnc, name, error);
- else
- return FALSE;
+ return _gda_server_provider_commit_transaction (cnc->priv->provider_obj, cnc, name, error);
}
/**
@@ -4265,10 +3502,7 @@ gda_connection_rollback_transaction (GdaConnection *cnc, const gchar *name, GErr
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
- if (PROV_CLASS (cnc->priv->provider_obj)->rollback_transaction)
- return PROV_CLASS (cnc->priv->provider_obj)->rollback_transaction (cnc->priv->provider_obj,
cnc, name, error);
- else
- return FALSE;
+ return _gda_server_provider_rollback_transaction (cnc->priv->provider_obj, cnc, name, error);
}
/**
@@ -4286,11 +3520,8 @@ gda_connection_add_savepoint (GdaConnection *cnc, const gchar *name, GError **er
{
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
-
- if (PROV_CLASS (cnc->priv->provider_obj)->add_savepoint)
- return PROV_CLASS (cnc->priv->provider_obj)->add_savepoint (cnc->priv->provider_obj, cnc,
name, error);
- else
- return FALSE;
+
+ return _gda_server_provider_add_savepoint (cnc->priv->provider_obj, cnc, name, error);
}
/**
@@ -4307,12 +3538,9 @@ gboolean
gda_connection_rollback_savepoint (GdaConnection *cnc, const gchar *name, GError **error)
{
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
- g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
+ g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
- if (PROV_CLASS (cnc->priv->provider_obj)->rollback_savepoint)
- return PROV_CLASS (cnc->priv->provider_obj)->rollback_savepoint (cnc->priv->provider_obj,
cnc, name, error);
- else
- return FALSE;
+ return _gda_server_provider_rollback_savepoint (cnc->priv->provider_obj, cnc, name, error);
}
/**
@@ -4331,10 +3559,7 @@ gda_connection_delete_savepoint (GdaConnection *cnc, const gchar *name, GError *
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
- if (PROV_CLASS (cnc->priv->provider_obj)->delete_savepoint)
- return PROV_CLASS (cnc->priv->provider_obj)->delete_savepoint (cnc->priv->provider_obj, cnc,
name, error);
- else
- return FALSE;
+ return _gda_server_provider_delete_savepoint (cnc->priv->provider_obj, cnc, name, error);
}
/**
@@ -4371,8 +3596,6 @@ gda_connection_supports_feature (GdaConnection *cnc, GdaConnectionFeature featur
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
- if (feature == GDA_CONNECTION_FEATURE_ASYNC_EXEC)
- return PROV_CLASS (cnc->priv->provider_obj)->handle_async ? TRUE : FALSE;
return gda_server_provider_supports_feature (cnc->priv->provider_obj, cnc, feature);
}
@@ -4559,7 +3782,6 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
const GValue *name = NULL;
gint i;
-
#ifdef GDA_DEBUG_META_STORE_UPDATE
g_print ("%s() => ", __FUNCTION__);
meta_context_dump (context);
@@ -4576,11 +3798,7 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
* - none
*/
ASSERT_TABLE_NAME (tname, "builtin_data_types");
- if (!PROV_CLASS (provider)->meta_funcs._btypes) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "_btypes");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs._btypes (provider, cnc, store, context, error);
+ retval = _gda_server_provider_meta_0arg (provider, cnc, store, context,
GDA_SERVER_META__BTYPES, error);
WARN_META_UPDATE_FAILURE (retval, "_btypes");
return retval;
}
@@ -4604,12 +3822,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
ASSERT_TABLE_NAME (tname, "columns");
if (i == 0) {
- if (!PROV_CLASS (provider)->meta_funcs.columns) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "columns");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.columns (provider, cnc, store,
context, error,
- catalog, schema, name);
+ retval = _gda_server_provider_meta_3arg (provider, cnc, store, context,
+ GDA_SERVER_META_COLUMNS, catalog,
schema, name, error);
WARN_META_UPDATE_FAILURE (retval, "columns");
return retval;
}
@@ -4633,12 +3847,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
return FALSE;
ASSERT_TABLE_NAME (tname, "collations");
- if (!PROV_CLASS (provider)->meta_funcs.collations) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "collations");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.collations (provider, cnc, store, context,
error,
- catalog, schema, name);
+ retval = _gda_server_provider_meta_3arg (provider, cnc, store, context,
+ GDA_SERVER_META_COLLATIONS, catalog, schema,
name, error);
WARN_META_UPDATE_FAILURE (retval, "collations");
return retval;
}
@@ -4657,12 +3867,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
return FALSE;
ASSERT_TABLE_NAME (tname, "character_sets");
- if (!PROV_CLASS (provider)->meta_funcs.character_sets) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "character_sets");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.character_sets (provider, cnc, store,
context, error,
- catalog, schema, name);
+ retval = _gda_server_provider_meta_3arg (provider, cnc, store, context,
+ GDA_SERVER_META_CHARACTER_SETS, catalog,
schema, name, error);
WARN_META_UPDATE_FAILURE (retval, "character_sets");
return retval;
}
@@ -4685,12 +3891,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
ASSERT_TABLE_NAME (tname, "check_column_usage");
if (i == 0) {
- if (!PROV_CLASS (provider)->meta_funcs.check_columns) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "check_columns");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.check_columns (provider, cnc,
store, context, error,
- catalog, schema,
tabname, cname);
+ retval = _gda_server_provider_meta_4arg (provider, cnc, store, context,
+ GDA_SERVER_META_CHECK_COLUMNS,
catalog, schema, tabname, cname, error);
WARN_META_UPDATE_FAILURE (retval, "check_columns");
return retval;
}
@@ -4715,12 +3917,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
return FALSE;
ASSERT_TABLE_NAME (tname, "domains");
- if (!PROV_CLASS (provider)->meta_funcs.domains) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "domains");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.domains (provider, cnc, store, context,
error,
- catalog, schema);
+ retval = _gda_server_provider_meta_2arg (provider, cnc, store, context,
+ GDA_SERVER_META_DOMAINS, catalog, schema,
error);
WARN_META_UPDATE_FAILURE (retval, "domains");
return retval;
}
@@ -4743,12 +3941,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
return TRUE; /* nothing to do */
ASSERT_TABLE_NAME (tname, "domain_constraints");
- if (!PROV_CLASS (provider)->meta_funcs.constraints_dom) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "constraints_dom");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.constraints_dom (provider, cnc, store,
context, error,
- catalog, schema, domname);
+ retval = _gda_server_provider_meta_3arg (provider, cnc, store, context,
+ GDA_SERVER_META_CONSTRAINTS_DOM, catalog,
schema, domname, error);
WARN_META_UPDATE_FAILURE (retval, "constraints_dom");
return retval;
}
@@ -4768,12 +3962,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
return FALSE;
ASSERT_TABLE_NAME (tname, "enums");
- if (!PROV_CLASS (provider)->meta_funcs.enums) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "enums");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.enums (provider, cnc, store, context,
error,
- catalog, schema, name);
+ retval = _gda_server_provider_meta_3arg (provider, cnc, store, context,
+ GDA_SERVER_META_ENUMS, catalog, schema,
name, error);
WARN_META_UPDATE_FAILURE (retval, "enums");
return retval;
}
@@ -4787,19 +3977,13 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
"specific_name", &name, NULL);
ASSERT_TABLE_NAME (tname, "element_types");
if (i < 0) {
- if (!PROV_CLASS (provider)->meta_funcs._el_types) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "_el_types");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs._el_types (provider, cnc, store,
context, error);
+ retval = _gda_server_provider_meta_0arg (provider, cnc, store, context,
+ GDA_SERVER_META__EL_TYPES, error);
WARN_META_UPDATE_FAILURE (retval, "_el_types");
}
else {
- if (!PROV_CLASS (provider)->meta_funcs.el_types) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "el_types");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.el_types (provider, cnc, store,
context, error, name);
+ retval = _gda_server_provider_meta_1arg (provider, cnc, store, context,
+ GDA_SERVER_META_EL_TYPES, name,
error);
WARN_META_UPDATE_FAILURE (retval, "el_types");
}
return retval;
@@ -4812,11 +3996,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
* - none
*/
ASSERT_TABLE_NAME (tname, "information_schema_catalog_name");
- if (!PROV_CLASS (provider)->meta_funcs._info) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "_info");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs._info (provider, cnc, store, context,
error);
+ retval = _gda_server_provider_meta_0arg (provider, cnc, store, context,
+ GDA_SERVER_META__INFO, error);
WARN_META_UPDATE_FAILURE (retval, "_info");
return retval;
}
@@ -4836,12 +4017,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
return FALSE;
ASSERT_TABLE_NAME (tname, "index_column_usage");
- if (!PROV_CLASS (provider)->meta_funcs.index_cols) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "index_cols");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.index_cols (provider, cnc, store, context,
error,
- catalog, schema, name, iname);
+ retval = _gda_server_provider_meta_4arg (provider, cnc, store, context,
+ GDA_SERVER_META_INDEX_COLS, catalog, schema,
name, iname, error);
WARN_META_UPDATE_FAILURE (retval, "index_cols");
return retval;
}
@@ -4865,12 +4042,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
ASSERT_TABLE_NAME (tname, "key_column_usage");
if (i == 0) {
- if (!PROV_CLASS (provider)->meta_funcs.key_columns) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "key_columns");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.key_columns (provider, cnc, store,
context, error,
- catalog, schema, tabname,
cname);
+ retval = _gda_server_provider_meta_4arg (provider, cnc, store, context,
+ GDA_SERVER_META_KEY_COLUMNS, catalog,
schema, tabname, cname, error);
WARN_META_UPDATE_FAILURE (retval, "key_columns");
return retval;
}
@@ -4894,12 +4067,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
return FALSE;
ASSERT_TABLE_NAME (tname, "parameters");
- if (!PROV_CLASS (provider)->meta_funcs.routine_par) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "routine_par");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.routine_par (provider, cnc, store, context, error,
- catalog, schema, name);
+ retval = _gda_server_provider_meta_3arg (provider, cnc, store, context,
+ GDA_SERVER_META_ROUTINE_PAR, catalog, schema, name,
error);
WARN_META_UPDATE_FAILURE (retval, "routine_par");
return retval;
@@ -4923,12 +4092,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
ASSERT_TABLE_NAME (tname, "referential_constraints");
if (i == 0) {
- if (!PROV_CLASS (provider)->meta_funcs.constraints_ref) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "constraints_ref");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.constraints_ref (provider, cnc,
store, context, error,
- catalog, schema,
tabname, cname);
+ retval = _gda_server_provider_meta_4arg (provider, cnc, store, context,
+ GDA_SERVER_META_CONSTRAINTS_REF,
catalog, schema, tabname, cname, error);
WARN_META_UPDATE_FAILURE (retval, "constraints_ref");
return retval;
}
@@ -4953,12 +4118,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
return FALSE;
ASSERT_TABLE_NAME (tname, "routines");
- if (!PROV_CLASS (provider)->meta_funcs.routines) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "routines");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.routines (provider, cnc, store, context,
error,
- catalog, schema, name);
+ retval = _gda_server_provider_meta_3arg (provider, cnc, store, context,
+ GDA_SERVER_META_ROUTINES, catalog, schema,
name, error);
WARN_META_UPDATE_FAILURE (retval, "routines");
return retval;
}
@@ -4975,12 +4136,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
return FALSE;
ASSERT_TABLE_NAME (tname, "routine_columns");
- if (!PROV_CLASS (provider)->meta_funcs.routine_col) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "routine_col");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.routine_col (provider, cnc, store,
context, error,
- catalog, schema, name);
+ retval = _gda_server_provider_meta_3arg (provider, cnc, store, context,
+ GDA_SERVER_META_ROUTINE_COL, catalog,
schema, name, error);
WARN_META_UPDATE_FAILURE (retval, "routine_col");
return retval;
}
@@ -4999,12 +4156,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
return FALSE;
ASSERT_TABLE_NAME (tname, "schemata");
- if (!PROV_CLASS (provider)->meta_funcs.schemata) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "schemata");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.schemata (provider, cnc, store, context, error,
- catalog, schema);
+ retval = _gda_server_provider_meta_2arg (provider, cnc, store, context,
+ GDA_SERVER_META_SCHEMATA, catalog, schema, error);
WARN_META_UPDATE_FAILURE (retval, "schemata");
return retval;
}
@@ -5024,12 +4177,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
return FALSE;
ASSERT_TABLE_NAME (tname, "tables");
- if (!PROV_CLASS (provider)->meta_funcs.tables_views) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "tables_views");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.tables_views (provider, cnc, store,
context, error,
- catalog, schema, name);
+ retval = _gda_server_provider_meta_3arg (provider, cnc, store, context,
+ GDA_SERVER_META_TABLES_VIEWS, catalog,
schema, name, error);
WARN_META_UPDATE_FAILURE (retval, "tables_views");
return retval;
}
@@ -5053,12 +4202,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
return FALSE;
ASSERT_TABLE_NAME (tname, "table_constraints");
- if (!PROV_CLASS (provider)->meta_funcs.constraints_tab) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "constraints_tab");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.constraints_tab (provider, cnc, store,
context, error,
- catalog, schema, tabname,
cname);
+ retval = _gda_server_provider_meta_4arg (provider, cnc, store, context,
+ GDA_SERVER_META_CONSTRAINTS_TAB, catalog,
schema, tabname, cname, error);
WARN_META_UPDATE_FAILURE (retval, "constraints_tab");
return retval;
}
@@ -5082,12 +4227,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
return FALSE;
ASSERT_TABLE_NAME (tname, "table_indexes");
- if (!PROV_CLASS (provider)->meta_funcs.indexes_tab) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "indexes_tab");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.indexes_tab (provider, cnc, store,
context, error,
- catalog, schema, tabname,
iname);
+ retval = _gda_server_provider_meta_4arg (provider, cnc, store, context,
+ GDA_SERVER_META_INDEXES_TAB, catalog,
schema, tabname, iname, error);
WARN_META_UPDATE_FAILURE (retval, "indexes_tab");
return retval;
}
@@ -5107,12 +4248,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
ASSERT_TABLE_NAME (tname, "triggers");
if (i == 1) {
- if (!PROV_CLASS (provider)->meta_funcs.triggers) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "triggers");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.triggers (provider, cnc, store,
context, error,
- catalog, schema, name);
+ retval = _gda_server_provider_meta_3arg (provider, cnc, store, context,
+ GDA_SERVER_META_TRIGGERS, catalog,
schema, name, error);
WARN_META_UPDATE_FAILURE (retval, "triggers");
return retval;
}
@@ -5136,12 +4273,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
return FALSE;
ASSERT_TABLE_NAME (tname, "udt");
- if (!PROV_CLASS (provider)->meta_funcs.udt) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "udt");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.udt (provider, cnc, store, context, error,
- catalog, schema);
+ retval = _gda_server_provider_meta_2arg (provider, cnc, store, context,
+ GDA_SERVER_META_UDT, catalog, schema, error);
WARN_META_UPDATE_FAILURE (retval, "udt");
return retval;
}
@@ -5158,12 +4291,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
return FALSE;
ASSERT_TABLE_NAME (tname, "udt_columns");
- if (!PROV_CLASS (provider)->meta_funcs.udt_cols) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "udt_cols");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.udt_cols (provider, cnc, store, context,
error,
- catalog, schema, name);
+ retval = _gda_server_provider_meta_3arg (provider, cnc, store, context,
+ GDA_SERVER_META_UDT_COLS, catalog, schema,
name, error);
WARN_META_UPDATE_FAILURE (retval, "udt_cols");
return retval;
}
@@ -5188,12 +4317,8 @@ local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaConte
ASSERT_TABLE_NAME (tname, "view_column_usage");
if (i == 0) {
- if (!PROV_CLASS (provider)->meta_funcs.view_cols) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "view_cols");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs.view_cols (provider, cnc, store, context,
error,
- catalog, schema, name);
+ retval = _gda_server_provider_meta_3arg (provider, cnc, store, context,
+ GDA_SERVER_META_VIEW_COLS, catalog, schema,
name, error);
WARN_META_UPDATE_FAILURE (retval, "view_cols");
return retval;
}
@@ -5374,7 +4499,6 @@ gda_connection_update_meta_store (GdaConnection *cnc, GdaMetaContext *context, G
store = gda_connection_get_meta_store (cnc);
g_assert (store);
- /* unlock connection */
gda_connection_unlock ((GdaLockable*) cnc);
if (context) {
@@ -5467,95 +4591,66 @@ gda_connection_update_meta_store (GdaConnection *cnc, GdaMetaContext *context, G
return retval;
}
else {
- typedef gboolean (*RFunc) (GdaServerProvider *, GdaConnection *, GdaMetaStore *,
- GdaMetaContext *, GError **);
typedef struct {
gchar *table_name;
gchar *func_name;
- RFunc func;
+ GdaServerProviderMetaType func_type;
} RMeta;
GdaMetaContext lcontext;
gint nb = 0, i;
RMeta rmeta[] = {
- {"_information_schema_catalog_name", "_info", NULL},
- {"_builtin_data_types", "_btypes", NULL},
- {"_udt", "_udt", NULL},
- {"_udt_columns", "_udt_cols", NULL},
- {"_enums", "_enums", NULL},
- {"_domains", "_domains", NULL},
- {"_domain_constraints", "_constraints_dom", NULL},
- {"_element_types", "_el_types", NULL},
- {"_collations", "_collations", NULL},
- {"_character_sets", "_character_sets", NULL},
- {"_schemata", "_schemata", NULL},
- {"_tables_views", "_tables_views", NULL},
- {"_columns", "_columns", NULL},
- {"_view_column_usage", "_view_cols", NULL},
- {"_table_constraints", "_constraints_tab", NULL},
- {"_referential_constraints", "_constraints_ref", NULL},
- {"_key_column_usage", "_key_columns", NULL},
- {"_check_column_usage", "_check_columns", NULL},
- {"_triggers", "_triggers", NULL},
- {"_routines", "_routines", NULL},
- {"_routine_columns", "_routine_col", NULL},
- {"_parameters", "_routine_par", NULL},
- {"_table_indexes", "_indexes_tab", NULL},
- {"_index_column_usage", "_index_cols", NULL}
+ {"_information_schema_catalog_name", "_info", GDA_SERVER_META__INFO},
+ {"_builtin_data_types", "_btypes", GDA_SERVER_META__BTYPES},
+ {"_udt", "_udt", GDA_SERVER_META__UDT},
+ {"_udt_columns", "_udt_cols", GDA_SERVER_META__UDT_COLS},
+ {"_enums", "_enums", GDA_SERVER_META__ENUMS},
+ {"_domains", "_domains", GDA_SERVER_META__DOMAINS},
+ {"_domain_constraints", "_constraints_dom", GDA_SERVER_META__CONSTRAINTS_DOM},
+ {"_element_types", "_el_types", GDA_SERVER_META__EL_TYPES},
+ {"_collations", "_collations", GDA_SERVER_META__COLLATIONS},
+ {"_character_sets", "_character_sets", GDA_SERVER_META__CHARACTER_SETS},
+ {"_schemata", "_schemata", GDA_SERVER_META__SCHEMATA},
+ {"_tables_views", "_tables_views", GDA_SERVER_META__TABLES_VIEWS},
+ {"_columns", "_columns", GDA_SERVER_META__COLUMNS},
+ {"_view_column_usage", "_view_cols", GDA_SERVER_META__VIEW_COLS},
+ {"_table_constraints", "_constraints_tab", GDA_SERVER_META__CONSTRAINTS_TAB},
+ {"_referential_constraints", "_constraints_ref", GDA_SERVER_META__CONSTRAINTS_REF},
+ {"_key_column_usage", "_key_columns", GDA_SERVER_META__KEY_COLUMNS},
+ {"_check_column_usage", "_check_columns", GDA_SERVER_META__CHECK_COLUMNS},
+ {"_triggers", "_triggers", GDA_SERVER_META__TRIGGERS},
+ {"_routines", "_routines", GDA_SERVER_META__ROUTINES},
+ {"_routine_columns", "_routine_col", GDA_SERVER_META__ROUTINE_COL},
+ {"_parameters", "_routine_par", GDA_SERVER_META__ROUTINE_PAR},
+ {"_table_indexes", "_indexes_tab", GDA_SERVER_META__INDEXES_TAB},
+ {"_index_column_usage", "_index_cols", GDA_SERVER_META__INDEX_COLS}
};
GdaServerProvider *provider = cnc->priv->provider_obj;
gboolean retval;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._info;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._btypes;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._udt;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._udt_cols;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._enums;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._domains;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._constraints_dom;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._el_types;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._collations;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._character_sets;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._schemata;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._tables_views;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._columns;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._view_cols;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._constraints_tab;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._constraints_ref;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._key_columns;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._check_columns;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._triggers;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._routines;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._routine_col;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._routine_par;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._indexes_tab;
- rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._index_cols;
- g_assert (nb == sizeof (rmeta) / sizeof (RMeta));
if (! _gda_meta_store_begin_data_reset (store, error)) {
return FALSE;
}
lcontext.size = 0;
+ nb = sizeof (rmeta) / sizeof (RMeta);
for (i = 0; i < nb; i++) {
- /*g_print ("TH %p %s(cnc=>%p store=>%p)\n", g_thread_self(), rmeta [i].func_name,
cnc, store);*/
- if (! rmeta [i].func)
- WARN_METHOD_NOT_IMPLEMENTED (provider, rmeta [i].func_name);
- else {
- lcontext.table_name = rmeta [i].table_name;
- if (!rmeta [i].func (provider, cnc, store, &lcontext, error)) {
- /*
- g_print ("TH %p CNC %p ERROR, prov=%p (%s)\n", g_thread_self(), cnc,
- gda_connection_get_provider (cnc),
- gda_connection_get_provider_name (cnc));
- */
- /*if (error && *error)
- g_warning ("%s (Provider %s)\n", (*error)->message,
- gda_connection_get_provider_name (cnc));
- */
-
- WARN_META_UPDATE_FAILURE (FALSE, rmeta [i].func_name);
- goto onerror;
- }
+ /*g_print ("%s() %s(cnc=>%p store=>%p)\n", __FUNCTION__, rmeta [i].func_name, cnc,
store);*/
+ lcontext.table_name = rmeta [i].table_name;
+ if (! _gda_server_provider_meta_0arg (provider, cnc, store, &lcontext,
+ rmeta[i].func_type, error)) {
+ /*
+ g_print ("%s() %p CNC %p ERROR, prov=%p (%s)\n", __FUNCTION__, cnc,
+ gda_connection_get_provider (cnc),
+ gda_connection_get_provider_name (cnc));
+ */
+ /*if (error && *error)
+ g_warning ("%s (Provider %s)\n", (*error)->message,
+ gda_connection_get_provider_name (cnc));
+ */
+
+ WARN_META_UPDATE_FAILURE (FALSE, rmeta [i].func_name);
+ goto onerror;
}
}
retval = _gda_meta_store_finish_data_reset (store, error);
@@ -6415,12 +5510,12 @@ prepared_stms_foreach_func (GdaStatement *gda_stmt, G_GNUC_UNUSED GdaPStmt *prep
static void
statement_weak_notify_cb (GdaConnection *cnc, GdaStatement *stmt)
{
- g_rec_mutex_lock (& cnc->priv->rmutex);
+ gda_connection_lock ((GdaLockable*) cnc);
g_assert (cnc->priv->prepared_stmts);
g_hash_table_remove (cnc->priv->prepared_stmts, stmt);
- g_rec_mutex_unlock (& cnc->priv->rmutex);
+ gda_connection_unlock ((GdaLockable*) cnc);
}
@@ -6511,37 +5606,34 @@ gda_connection_del_prepared_statement (GdaConnection *cnc, GdaStatement *gda_stm
/**
* gda_connection_internal_set_provider_data: (skip)
* @cnc: a #GdaConnection object
- * @data: an opaque structure, known only to the provider for which @cnc is opened
+ * @data: a #GdaServerProviderConnectionData, which can be extended as needed by the provider for which @cnc
is opened
* @destroy_func: function to call when the connection closes and @data needs to be destroyed
*
* Note: calling this function more than once will not make it call @destroy_func on any previously
* set opaque @data, you'll have to do it yourself.
+ *
+ * Note: @destroy_func, needs to free the memory associated to @data, if necessary.
*/
void
-gda_connection_internal_set_provider_data (GdaConnection *cnc, gpointer data, GDestroyNotify destroy_func)
+gda_connection_internal_set_provider_data (GdaConnection *cnc, GdaServerProviderConnectionData *data,
GDestroyNotify destroy_func)
{
g_return_if_fail (GDA_IS_CONNECTION (cnc));
+ g_return_if_fail ((data && destroy_func) || (!data && !destroy_func));
+ if (cnc->priv->provider_data && data) {
+ g_warning ("Changing the provider's data is not allowed during the lifetime of a connection");
+ return;
+ }
+
+ if (!data)
+ gda_connection_lock ((GdaLockable*) cnc);
- gda_connection_lock ((GdaLockable*) cnc);
cnc->priv->provider_data = data;
- cnc->priv->provider_data_destroy_func = destroy_func;
- gda_connection_unlock ((GdaLockable*) cnc);
-}
+ if (data)
+ data->provider_data_destroy_func = destroy_func;
-/**
- * gda_connection_internal_get_provider_data: (skip)
- * @cnc: a #GdaConnection object
- *
- * Get the opaque pointer previously set using gda_connection_internal_set_provider_data().
- * If it's not set, then add a connection event and returns %NULL
- *
- * Returns: (allow-none): the pointer to the opaque structure set using
gda_connection_internal_set_provider_data(), or %NULL
- */
-gpointer
-gda_connection_internal_get_provider_data (GdaConnection *cnc)
-{
- return gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!data)
+ gda_connection_unlock ((GdaLockable*) cnc);
}
/**
@@ -6556,7 +5648,7 @@ gda_connection_internal_get_provider_data (GdaConnection *cnc)
*
* Since: 5.0.2
*/
-gpointer
+GdaServerProviderConnectionData *
gda_connection_internal_get_provider_data_error (GdaConnection *cnc, GError **error)
{
gpointer retval;
@@ -6580,29 +5672,36 @@ gda_connection_internal_get_provider_data_error (GdaConnection *cnc, GError **er
GdaMetaStore *
gda_connection_get_meta_store (GdaConnection *cnc)
{
- GdaMetaStore *store = NULL;
-
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_mutex_lock (& cnc->priv->object_mutex);
if (!cnc->priv->meta_store) {
- ThreadConnectionData *cdata = NULL;
- if (cnc->priv->is_thread_wrapper) {
- cdata = (ThreadConnectionData*) gda_connection_internal_get_provider_data (cnc);
- if (cdata && cdata->sub_connection->priv->meta_store) {
- cnc->priv->meta_store = g_object_ref
(cdata->sub_connection->priv->meta_store);
- store = cnc->priv->meta_store;
- }
- }
- if (!store) {
- cnc->priv->meta_store = gda_meta_store_new (NULL);
- if (cnc->priv->is_thread_wrapper)
- cdata->sub_connection->priv->meta_store =
- g_object_ref (cnc->priv->meta_store);
- }
+ cnc->priv->meta_store = gda_meta_store_new (NULL);
+ GdaConnection *scnc;
+ scnc = gda_meta_store_get_internal_connection (cnc->priv->meta_store);
+ if ((scnc != cnc) &&
+ gda_connection_get_main_context (cnc) &&
+ ! gda_connection_get_main_context (scnc))
+ gda_connection_set_main_context (scnc, gda_connection_get_main_context (cnc));
}
- store = cnc->priv->meta_store;
g_mutex_unlock (& cnc->priv->object_mutex);
- return store;
+
+ return cnc->priv->meta_store;
+}
+
+typedef struct {
+ GdaLockable *lockable;
+ GMainLoop *loop;
+} TryLockData;
+
+static gboolean
+idle_trylock (TryLockData *data)
+{
+ if (gda_connection_trylock (data->lockable)) {
+ g_main_loop_quit (data->loop);
+ return FALSE; /* remove idle source */
+ }
+ else
+ return TRUE; /* keep idle source */
}
/*
@@ -6625,32 +5724,46 @@ static void
gda_connection_lock (GdaLockable *lockable)
{
GdaConnection *cnc = (GdaConnection *) lockable;
-
- g_rec_mutex_lock (& cnc->priv->rmutex);
- if (cnc->priv->unique_possible_thread &&
- (cnc->priv->unique_possible_thread != g_thread_self ())) {
- g_rec_mutex_unlock (& cnc->priv->rmutex);
- g_mutex_lock (& cnc->priv->object_mutex);
-
- while (1) {
- if (cnc->priv->unique_possible_thread &&
- (cnc->priv->unique_possible_thread != g_thread_self ())) {
-#ifdef GDA_DEBUG_CNC_LOCK
- g_print ("Wainting th %p, now %p (cond %p, mutex%p)\n", g_thread_self(),
- cnc->priv->unique_possible_thread, &cnc->priv->unique_possible_cond,
- cnc->priv->object_mutex);
-#endif
- gint64 end_time;
- end_time = g_get_monotonic_time () + 5 * G_TIME_SPAN_SECOND;
- while (! g_cond_wait_until (& cnc->priv->unique_possible_cond,
- & cnc->priv->object_mutex, end_time));
- }
- else if (g_rec_mutex_trylock (& cnc->priv->rmutex)) {
- g_mutex_unlock (& cnc->priv->object_mutex);
- break;
- }
- }
+
+ if (cnc->priv->provider_data) {
+ /* connection is opened */
+ g_assert (cnc->priv->provider_data->worker);
+ if (gda_worker_thread_is_worker (cnc->priv->provider_data->worker))
+ /* the sitation here is that the connection _has been_ locked by the
+ * calling thread of the GdaWorker, and as we are in the worker thread
+ * of the GdaWorker, we don't need to lock it again: it would be useless because
+ * by desing the connection object may be modified but only by the provider code,
which
+ * is Ok, and because it would require a very complex mechanism to "transfer the lock"
+ * from one thread to the other */
+ return;
+ }
+
+ GMainContext *context;
+ context = gda_connection_get_main_context (cnc);
+ if (context) {
+ if (gda_connection_trylock (lockable))
+ return;
+
+ /* we must process events from @context */
+ GMainLoop *loop;
+ loop = g_main_loop_new (context, FALSE);
+
+ TryLockData lockdata;
+ lockdata.lockable = lockable;
+ lockdata.loop = loop;
+
+ GSource *idle;
+ idle = g_idle_source_new ();
+ g_source_set_priority (idle, G_PRIORITY_HIGH);
+ g_source_attach (idle, context);
+ g_source_set_callback (idle, (GSourceFunc) idle_trylock, &lockdata, NULL);
+ g_source_unref (idle);
+
+ g_main_loop_run (loop);
+ g_main_loop_unref (loop);
}
+ else
+ g_rec_mutex_lock (& cnc->priv->rmutex);
}
/*
@@ -6662,16 +5775,17 @@ gda_connection_lock (GdaLockable *lockable)
static gboolean
gda_connection_trylock (GdaLockable *lockable)
{
- gboolean retval;
GdaConnection *cnc = (GdaConnection *) lockable;
- retval = g_rec_mutex_trylock (& cnc->priv->rmutex);
- if (retval && cnc->priv->unique_possible_thread &&
- (cnc->priv->unique_possible_thread != g_thread_self ())) {
- retval = FALSE;
- g_rec_mutex_unlock (& cnc->priv->rmutex);
+ if (cnc->priv->provider_data) {
+ /* connection is opened */
+ g_assert (cnc->priv->provider_data->worker);
+ if (gda_worker_thread_is_worker (cnc->priv->provider_data->worker))
+ /* See gda_connection_lock() for explanations */
+ return TRUE;
}
- return retval;
+
+ return g_rec_mutex_trylock (& cnc->priv->rmutex);
}
/*
@@ -6682,6 +5796,15 @@ static void
gda_connection_unlock (GdaLockable *lockable)
{
GdaConnection *cnc = (GdaConnection *) lockable;
+
+ if (cnc->priv->provider_data) {
+ /* connection is opened */
+ if (cnc->priv->provider_data->worker &&
+ gda_worker_thread_is_worker (cnc->priv->provider_data->worker))
+ /* See gda_connection_lock() for explanations */
+ return;
+ }
+
g_rec_mutex_unlock (& cnc->priv->rmutex);
}
@@ -7108,65 +6231,3 @@ _gda_connection_compute_table_virtual_name (GdaConnection *cnc, const gchar *tab
return ptr;
}
}
-
-/*
- * Free connection's specific data
- */
-static gpointer
-sub_thread_unref_connection (GdaConnection *cnc, G_GNUC_UNUSED GError **error)
-{
- /* WARNING: function executed in sub thread! */
- g_object_unref (cnc);
-#ifdef GDA_DEBUG_NO
- g_print ("/%s()\n", __FUNCTION__);
-#endif
- return NULL;
-}
-
-void
-_gda_thread_connection_data_free (ThreadConnectionData *cdata)
-{
- if (!cdata)
- return;
-
- /* disconnect signals handlers */
- gsize i;
- for (i = 0; i < cdata->handlers_ids->len; i++) {
- gulong hid = g_array_index (cdata->handlers_ids, gulong, i);
- gda_thread_wrapper_disconnect (cdata->wrapper, hid);
- }
-
- /* unref cdata->sub_connection in sub thread */
- guint jid;
- jid = gda_thread_wrapper_execute (cdata->wrapper,
- (GdaThreadWrapperFunc) sub_thread_unref_connection,
- cdata->sub_connection, NULL, NULL);
- gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, 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_object_unref (cdata->cnc_provider);
-
- g_free (cdata);
-}
-
-void
-_gda_thread_connection_set_data (GdaConnection *cnc, ThreadConnectionData *cdata)
-{
- g_rec_mutex_lock (& cnc->priv->rmutex);
- if (cnc->priv->th_data)
- _gda_thread_connection_data_free (cnc->priv->th_data);
- cnc->priv->th_data = cdata;
- g_rec_mutex_unlock (& cnc->priv->rmutex);
-}
-
-ThreadConnectionData *
-_gda_thread_connection_get_data (GdaConnection *cnc)
-{
- return cnc->priv->th_data;
-}
diff --git a/libgda/gda-connection.h b/libgda/gda-connection.h
index 331b52b..dead156 100644
--- a/libgda/gda-connection.h
+++ b/libgda/gda-connection.h
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2000 Reinhard Müller <reinhard src gnome org>
* Copyright (C) 2000 - 2004 Rodrigo Moya <rodrigo gnome-db org>
- * Copyright (C) 2001 - 2011 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2001 - 2013 Vivien Malerba <malerba gnome-db org>
* Copyright (C) 2002 Cleber Rodrigues <cleberrrjr bol com br>
* Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier <gonzalo ximian com>
* Copyright (C) 2003 Filip Van Raemdonck <mechanix debian org>
@@ -58,13 +58,14 @@ typedef enum {
GDA_CONNECTION_NO_CNC_SPEC_ERROR,
GDA_CONNECTION_NO_PROVIDER_SPEC_ERROR,
GDA_CONNECTION_OPEN_ERROR,
+ GDA_CONNECTION_ALREADY_OPENED_ERROR,
GDA_CONNECTION_STATEMENT_TYPE_ERROR,
GDA_CONNECTION_CANT_LOCK_ERROR,
GDA_CONNECTION_TASK_NOT_FOUND_ERROR,
- GDA_CONNECTION_UNSUPPORTED_THREADS_ERROR,
GDA_CONNECTION_CLOSED_ERROR,
GDA_CONNECTION_META_DATA_CONTEXT_ERROR,
- GDA_CONNECTION_UNSUPPORTED_ASYNC_EXEC_ERROR
+ GDA_CONNECTION_UNSUPPORTED_ASYNC_EXEC_ERROR,
+ GDA_CONNECTION_NO_MAIN_CONTEXT_ERROR
} GdaConnectionError;
#define GDA_CONNECTION_NONEXIST_DSN_ERROR GDA_CONNECTION_DSN_NOT_FOUND_ERROR
@@ -75,11 +76,15 @@ typedef enum {
* @title: GdaConnection
* @stability: Stable
*
- * Each connection to a database is represented by a #GdaConnection object. A connection is created (and
opened)
- * using gda_connection_open_from_dsn() if a data source has been defined, or
gda_connection_open_from_string()
+ * Each connection to a database is represented by a #GdaConnection object. A connection is created
+ * using gda_connection_new_from_dsn() if a data source has been defined, or gda_connection_new_from_string()
* otherwise. It is not recommended to create a #GdaConnection object using g_object_new() as the results are
* unpredictable (some parts won't correctly be initialized).
*
+ * Once the connection has been created, it can be opened using gda_connection_open() or
gda_connection_open_async().
+ * By default these functions will block, unless you speficy a #GMainContext from which events will be
processed
+ * while opening the connection using gda_connection_set_main_context().
+ *
* Use the connection object to execute statements, use transactions, get meta data information, ...
*
* If supported by the database provider being used, statements can be executed asynchronously instead of
@@ -98,16 +103,7 @@ typedef enum {
* the execution of a statement</para></listitem>
* </itemizedlist>
*
- * The #GdaConnection object implements its own locking mechanism so it is thread-safe. However ad some
database
- * providers rely on an API which does not support threads or supports it only partially, the connections
- * opened using those providers will only be accessible from the thread which created them (any other thread
will
- * be blocked trying to access the connection, use the
- * <link linkend="gda-lockable-try-lock">gda_lockable_try_lock()</link> method to check it the connection
- * is usable from a thread).
- *
- * If a connection really needs to be accessed by several threads at once, then it is possible to pass the
- * #GDA_CONNECTION_OPTIONS_THREAD_SAFE flag when opening it. This flag requests that the real connection
- * be created and really accessed in a <emphasis>private</emphasis> sub thread.
+ * The #GdaConnection object implements its own locking mechanism so it is thread-safe.
*/
struct _GdaConnection {
@@ -141,11 +137,6 @@ struct _GdaConnectionClass {
* (this policy is not correctly enforced at the moment)
* @GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE: this flag specifies that SQL identifiers
submitted as input
* to Libgda have to keep their case sensitivity.
- * @GDA_CONNECTION_OPTIONS_THREAD_SAFE: this flag specifies that the connection to open will be used
- * by several threads at once so it has to be thread safe
- * @GDA_CONNECTION_OPTIONS_THREAD_ISOLATED: this flag specifies that the connection to open will be used
- * by several threads at once and requests that the real connection be
used
- * only in a sub thread created specifically for it
* @GDA_CONNECTION_OPTIONS_AUTO_META_DATA: this flags specifies that if a #GdaMetaStore has been associated
* to the connection, then it is kept up to date with the evolutions in
the
* database's structure. Be aware however that there are some drawbacks
@@ -166,22 +157,6 @@ struct _GdaConnectionClass {
* has to be conform to the database it will be used with</para></listitem>
* </itemizedlist>
*
- * Additional information about the GDA_CONNECTION_OPTIONS_THREAD_SAFE and
GDA_CONNECTION_OPTIONS_THREAD_ISOLATED flags:
- * The GDA_CONNECTION_OPTIONS_THREAD_SAFE flag specifies that it has to be able to use the returned
connection object from
- * several threads at once (locking is ensured by the #GdaConnection itself). Depending on the database
provider's
- * implementation and on the native libraries it uses, the "normal" connection object might not respect this
requirement,
- * and in this case a specific thread is started and used as the unique thread which will manipulate the
actual connection,
- * while a "wrapper connection" is actually returned and used by the caller (that wrapper connection passes
method calls
- * from the calling thread to the actual connection's specific thread, and gets the results back).
- *
- * The GDA_CONNECTION_OPTIONS_THREAD_ISOLATED forces using a specific thread and a "wrapper connection" even
if the
- * "normal" connection would itself be thread safe; this is useful for example to be sure the asynchronous
API can
- * always be used (see gda_connection_async_statement_execute()).
- *
- * Having a specific thread and a "wrapper connection" definitely has an impact on the performances (because
it involves
- * messages passing between threads for every method call), so using the
- * GDA_CONNECTION_OPTIONS_THREAD_SAFE or GDA_CONNECTION_OPTIONS_THREAD_ISOLATED flags should be carefully
considered.
- *
* Note about the @GDA_CONNECTION_OPTIONS_AUTO_META_DATA flag:
* <itemizedlist>
* <listitem><para>Every time a DDL statement is successfully executed, the associated mate data, if
@@ -194,8 +169,6 @@ typedef enum {
GDA_CONNECTION_OPTIONS_NONE = 0,
GDA_CONNECTION_OPTIONS_READ_ONLY = 1 << 0,
GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE = 1 << 1,
- GDA_CONNECTION_OPTIONS_THREAD_SAFE = 1 << 2,
- GDA_CONNECTION_OPTIONS_THREAD_ISOLATED = 1 << 3,
GDA_CONNECTION_OPTIONS_AUTO_META_DATA = 1 << 4
} GdaConnectionOptions;
@@ -217,9 +190,11 @@ typedef enum {
* @GDA_CONNECTION_FEATURE_UPDATABLE_CURSOR: test for updatable cursors support
* @GDA_CONNECTION_FEATURE_USERS: test for users support
* @GDA_CONNECTION_FEATURE_VIEWS: test for views support
+ * @GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_READ_COMMITTED: test for READ COMMITTED transaction
isolation level
+ * @GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_READ_UNCOMMITTED: test for READ UNCOMMITTED transaction
isolation level
+ * @GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_REPEATABLE_READ: test for REPEATABLE READ transaction
isolation level
+ * @GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_SERIALIZABLE: test for SERIALIZABLE transaction isolation
level
* @GDA_CONNECTION_FEATURE_XA_TRANSACTIONS: test for distributed transactions support
- * @GDA_CONNECTION_FEATURE_MULTI_THREADING: test for native multi-threading support
- * @GDA_CONNECTION_FEATURE_ASYNC_EXEC: test if connection supports asynchronous execution
* @GDA_CONNECTION_FEATURE_LAST: not used
*
* Used in gda_connection_supports_feature() and gda_server_provider_supports_feature() to test if a
connection
@@ -241,11 +216,12 @@ typedef enum {
GDA_CONNECTION_FEATURE_UPDATABLE_CURSOR,
GDA_CONNECTION_FEATURE_USERS,
GDA_CONNECTION_FEATURE_VIEWS,
+ GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_READ_COMMITTED,
+ GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_READ_UNCOMMITTED,
+ GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_REPEATABLE_READ,
+ GDA_CONNECTION_FEATURE_TRANSACTION_ISOLATION_SERIALIZABLE,
GDA_CONNECTION_FEATURE_XA_TRANSACTIONS,
- GDA_CONNECTION_FEATURE_MULTI_THREADING,
- GDA_CONNECTION_FEATURE_ASYNC_EXEC,
-
GDA_CONNECTION_FEATURE_LAST
} GdaConnectionFeature;
@@ -274,7 +250,7 @@ typedef enum {
GType gda_connection_get_type (void) G_GNUC_CONST;
GdaConnection *gda_connection_open_from_dsn (const gchar *dsn, const gchar *auth_string,
GdaConnectionOptions options, GError **error);
-GdaConnection *gda_connection_open_from_string (const gchar *provider_name,
+GdaConnection *gda_connection_open_from_string (const gchar *provider_name,
const gchar *cnc_string, const gchar *auth_string,
GdaConnectionOptions options, GError **error);
GdaConnection *gda_connection_new_from_dsn (const gchar *dsn, const gchar *auth_string,
@@ -282,18 +258,25 @@ GdaConnection *gda_connection_new_from_dsn (const gchar *dsn, cons
GdaConnection *gda_connection_new_from_string (const gchar *provider_name,
const gchar *cnc_string, const gchar *auth_string,
GdaConnectionOptions options, GError **error);
+
gboolean gda_connection_open (GdaConnection *cnc, GError **error);
-void gda_connection_close (GdaConnection *cnc);
-void gda_connection_close_no_warning (GdaConnection *cnc);
+typedef void (*GdaConnectionOpenFunc) (GdaConnection *cnc, guint job_id, gboolean result, GError *error,
gpointer data);
+guint gda_connection_open_async (GdaConnection *cnc, GdaConnectionOpenFunc
callback, gpointer data, GError **error);
+
+gboolean gda_connection_close (GdaConnection *cnc, GError **error);
gboolean gda_connection_is_opened (GdaConnection *cnc);
GdaConnectionOptions gda_connection_get_options (GdaConnection *cnc);
+void gda_connection_set_main_context (GdaConnection *cnc, GMainContext *context);
+GMainContext *gda_connection_get_main_context (GdaConnection *cnc);
+
GdaServerProvider *gda_connection_get_provider (GdaConnection *cnc);
const gchar *gda_connection_get_provider_name (GdaConnection *cnc);
GdaServerOperation *gda_connection_create_operation (GdaConnection *cnc, GdaServerOperationType type,
GdaSet *options, GError **error);
+
gboolean gda_connection_perform_operation (GdaConnection *cnc, GdaServerOperation *op, GError
**error);
const gchar *gda_connection_get_dsn (GdaConnection *cnc);
@@ -304,7 +287,7 @@ gboolean gda_connection_get_date_format (GdaConnection *cnc, GD
GError **error);
GdaStatement *gda_connection_parse_sql_string (GdaConnection *cnc, const gchar *sql, GdaSet
**params,
- GError **error);
+ GError **error);
/*
* Quick commands execution
@@ -317,20 +300,20 @@ gint gda_connection_execute_non_select_command (GdaConnection
*/
gboolean gda_connection_insert_row_into_table (GdaConnection *cnc, const gchar *table,
GError **error, ...);
gboolean gda_connection_insert_row_into_table_v (GdaConnection *cnc, const gchar *table,
- GSList *col_names, GSList *values,
- GError **error);
+ GSList *col_names, GSList *values,
+ GError **error);
gboolean gda_connection_update_row_in_table (GdaConnection *cnc, const gchar *table,
- const gchar *condition_column_name,
- GValue *condition_value, GError **error, ...);
+ const gchar *condition_column_name,
+ GValue *condition_value, GError **error,
...);
gboolean gda_connection_update_row_in_table_v (GdaConnection *cnc, const gchar *table,
- const gchar *condition_column_name,
- GValue *condition_value,
- GSList *col_names, GSList *values,
- GError **error);
+ const gchar *condition_column_name,
+ GValue *condition_value,
+ GSList *col_names, GSList *values,
+ GError **error);
gboolean gda_connection_delete_row_from_table (GdaConnection *cnc, const gchar *table,
- const gchar *condition_column_name,
- GValue *condition_value, GError **error);
+ const gchar *condition_column_name,
+ GValue *condition_value, GError **error);
const GList *gda_connection_get_events (GdaConnection *cnc);
@@ -360,15 +343,6 @@ GdaDataModel *gda_connection_statement_execute_select_full (GdaConnection
gint gda_connection_statement_execute_non_select (GdaConnection *cnc, GdaStatement *stmt,
GdaSet *params, GdaSet **last_insert_row,
GError **error);
-/* asynchronous execution */
-guint gda_connection_async_statement_execute (GdaConnection *cnc, GdaStatement *stmt, GdaSet
*params,
- GdaStatementModelUsage model_usage, GType
*col_types,
- gboolean need_last_insert_row,
- GError **error);
-GObject *gda_connection_async_fetch_result (GdaConnection *cnc, guint task_id, GdaSet
**last_insert_row, GError **error);
-gboolean gda_connection_async_cancel (GdaConnection *cnc, guint task_id, GError
**error);
-
-
/* repetitive statement */
GSList *gda_connection_repetitive_statement_execute (GdaConnection *cnc, GdaRepetitiveStatement
*rstmt,
GdaStatementModelUsage model_usage, GType
*col_types,
diff --git a/libgda/gda-data-model.h b/libgda/gda-data-model.h
index c762177..3dcd90e 100644
--- a/libgda/gda-data-model.h
+++ b/libgda/gda-data-model.h
@@ -182,6 +182,8 @@ struct _GdaDataModelIface {
* </itemizedlist>
*
* Also see the section about <link linkend="gda-data-model-writing">writing your own GdaDataModel</link>
+ *
+ * Finally, the #GdaDataModel object implements its own locking mechanism and can be used simultaneously
from several threads.
*/
GType gda_data_model_get_type (void) G_GNUC_CONST;
diff --git a/libgda/gda-data-pivot.c b/libgda/gda-data-pivot.c
index a8bd70e..f29ddfd 100644
--- a/libgda/gda-data-pivot.c
+++ b/libgda/gda-data-pivot.c
@@ -2108,7 +2108,7 @@ create_vcnc (GdaDataPivot *pivot, GError **error)
virtual_provider = gda_vprovider_data_model_new ();
g_mutex_unlock (&provider_mutex);
- vcnc = gda_virtual_connection_open (virtual_provider, &lerror);
+ vcnc = gda_virtual_connection_open (virtual_provider, GDA_CONNECTION_OPTIONS_NONE, &lerror);
if (! vcnc) {
g_print ("Virtual ERROR: %s\n", lerror && lerror->message ? lerror->message : "No detail");
if (lerror)
diff --git a/libgda/gda-data-proxy.c b/libgda/gda-data-proxy.c
index 4b6179c..a29ecec 100644
--- a/libgda/gda-data-proxy.c
+++ b/libgda/gda-data-proxy.c
@@ -3072,7 +3072,7 @@ apply_filter_statement (GdaDataProxy *proxy, GError **error)
vcnc = proxy->priv->filter_vcnc;
if (!vcnc) {
GError *lerror = NULL;
- vcnc = gda_virtual_connection_open (virtual_provider, &lerror);
+ vcnc = gda_virtual_connection_open (virtual_provider, GDA_CONNECTION_OPTIONS_NONE, &lerror);
if (! vcnc) {
g_print ("Virtual ERROR: %s\n", lerror && lerror->message ? lerror->message : "No
detail");
if (lerror)
@@ -3217,9 +3217,9 @@ gda_data_proxy_set_filter_expr (GdaDataProxy *proxy, const gchar *filter_expr, G
if (proxy->priv->filter_stmt)
g_object_unref (proxy->priv->filter_stmt);
proxy->priv->filter_stmt = NULL;
+ gda_mutex_unlock (proxy->priv->mutex);
gboolean retval = apply_filter_statement (proxy, error);
- gda_mutex_unlock (proxy->priv->mutex);
return retval;
}
@@ -3262,8 +3262,8 @@ gda_data_proxy_set_filter_expr (GdaDataProxy *proxy, const gchar *filter_expr, G
g_object_unref (proxy->priv->filter_stmt);
proxy->priv->filter_stmt = stmt;
- gboolean retval = apply_filter_statement (proxy, error);
gda_mutex_unlock (proxy->priv->mutex);
+ gboolean retval = apply_filter_statement (proxy, error);
return retval;
}
diff --git a/libgda/gda-data-select.c b/libgda/gda-data-select.c
index 29c6343..674129d 100644
--- a/libgda/gda-data-select.c
+++ b/libgda/gda-data-select.c
@@ -37,9 +37,12 @@
#include <libgda/gda-statement.h>
#include <libgda/gda-holder.h>
#include <libgda/gda-connection.h>
+#include <libgda/gda-connection-internal.h>
#include <libgda/gda-util.h>
#include <sql-parser/gda-sql-parser.h>
#include <gda-statement-priv.h>
+#include <thread-wrapper/gda-worker.h>
+#include <libgda/gda-server-provider-private.h> /* for _gda_server_provider_get_real_main_context () */
#define CLASS(x) (GDA_DATA_SELECT_CLASS (G_OBJECT_GET_CLASS (x)))
@@ -98,7 +101,8 @@ typedef struct {
*/
struct _GdaDataSelectPrivate {
GdaConnection *cnc;
- GdaDataModelIter *iter;
+ GdaWorker *worker;
+ GdaDataModelIter *iter;
GArray *exceptions; /* array of #GError pointers */
PrivateShareable *sh;
gulong ext_params_changed_sig_id;
@@ -122,6 +126,14 @@ enum
PROP_EXEC_DELAY
};
+/* API to handle using a GdaWorker */
+static gint _gda_data_select_fetch_nb_rows (GdaDataSelect *model);
+static gboolean _gda_data_select_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownum, GError
**error);
+static gboolean _gda_data_select_store_all (GdaDataSelect *model, GError **error);
+static gboolean _gda_data_select_fetch_next (GdaDataSelect *model, GdaRow **prow, gint rownum, GError
**error);
+static gboolean _gda_data_select_fetch_prev (GdaDataSelect *model, GdaRow **prow, gint rownum, GError
**error);
+static gboolean _gda_data_select_fetch_at (GdaDataSelect *model, GdaRow **prow, gint rownum, GError
**error);
+
/* module error */
GQuark gda_data_select_error_quark (void)
{
@@ -347,6 +359,7 @@ gda_data_select_init (GdaDataSelect *model, G_GNUC_UNUSED GdaDataSelectClass *kl
model->priv = g_new0 (GdaDataSelectPrivate, 1);
model->priv->cnc = NULL;
+ model->priv->worker = NULL;
model->priv->exceptions = NULL;
model->priv->sh = g_new0 (PrivateShareable, 1);
model->priv->sh-> notify_changes = TRUE;
@@ -477,6 +490,10 @@ gda_data_select_dispose (GObject *object)
/* free memory */
if (model->priv) {
+ if (model->priv->worker) {
+ gda_worker_unref (model->priv->worker);
+ model->priv->worker = NULL;
+ }
if (model->priv->cnc) {
g_object_unref (model->priv->cnc);
model->priv->cnc = NULL;
@@ -668,17 +685,21 @@ create_columns (GdaDataSelect *model)
static void
gda_data_select_set_property (GObject *object,
- guint param_id,
- const GValue *value,
- GParamSpec *pspec)
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
GdaDataSelect *model = (GdaDataSelect *) object;
if (model->priv) {
switch (param_id) {
case PROP_CNC:
model->priv->cnc = g_value_get_object (value);
- if (model->priv->cnc)
+ if (model->priv->cnc) {
g_object_ref (model->priv->cnc);
+ model->priv->worker = _gda_connection_get_worker (model->priv->cnc);
+ g_assert (model->priv->worker);
+ gda_worker_ref (model->priv->worker);
+ }
break;
case PROP_PREP_STMT:
if (model->prep_stmt)
@@ -760,9 +781,9 @@ gda_data_select_set_property (GObject *object,
static void
gda_data_select_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec)
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
{
GdaDataSelect *model = (GdaDataSelect *) object;
if (model->priv) {
@@ -781,7 +802,7 @@ gda_data_select_get_property (GObject *object,
g_warning ("Cannot set the 'store-all-rows' property when access mode is
cursor based");
else {
if ((model->advertized_nrows < 0) && CLASS (model)->fetch_nb_rows)
- CLASS (model)->fetch_nb_rows (model);
+ _gda_data_select_fetch_nb_rows (model);
g_value_set_boolean (value, model->nb_stored_rows == model->advertized_nrows);
}
break;
@@ -1757,7 +1778,7 @@ gda_data_select_get_n_rows (GdaDataModel *model)
if ((imodel->advertized_nrows < 0) &&
(imodel->priv->sh->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM) &&
CLASS (model)->fetch_nb_rows)
- retval = CLASS (model)->fetch_nb_rows (imodel);
+ retval = _gda_data_select_fetch_nb_rows (imodel);
if ((retval > 0) && (imodel->priv->sh->del_rows))
retval -= imodel->priv->sh->del_rows->len;
@@ -2021,7 +2042,7 @@ gda_data_select_get_value_at (GdaDataModel *model, gint col, gint row, GError **
else {
prow = gda_data_select_get_stored_row (imodel, int_row);
if (!prow && CLASS (model)->fetch_random)
- CLASS (model)->fetch_random (imodel, &prow, int_row, error);
+ _gda_data_select_fetch_random (imodel, &prow, int_row, error);
}
if (!prow)
return NULL;
@@ -2144,7 +2165,7 @@ gda_data_select_iter_next (GdaDataModel *model, GdaDataModelIter *iter)
int_row = external_to_internal_row (imodel, target_iter_row, NULL);
prow = gda_data_select_get_stored_row (imodel, int_row);
if (!prow)
- CLASS (model)->fetch_next (imodel, &prow, int_row, NULL);
+ _gda_data_select_fetch_next (imodel, &prow, int_row, NULL);
if (prow) {
imodel->priv->sh->iter_row = target_iter_row;
@@ -2193,7 +2214,7 @@ gda_data_select_iter_prev (GdaDataModel *model, GdaDataModelIter *iter)
gda_data_model_iter_invalidate_contents (iter);
return FALSE;
}
- CLASS (model)->fetch_prev (imodel, &prow, int_row, NULL);
+ _gda_data_select_fetch_prev (imodel, &prow, int_row, NULL);
}
if (prow) {
@@ -2238,7 +2259,7 @@ gda_data_select_iter_at_row (GdaDataModel *model, GdaDataModelIter *iter, gint r
}
else {
if (CLASS (model)->fetch_at) {
- CLASS (model)->fetch_at (imodel, &prow, int_row, NULL);
+ _gda_data_select_fetch_at (imodel, &prow, int_row, NULL);
if (prow) {
imodel->priv->sh->iter_row = row;
update_iter (imodel, prow);
@@ -3833,7 +3854,7 @@ gda_data_select_prepare_for_offline (GdaDataSelect *model, GError **error)
/* fetching data */
if (model->advertized_nrows < 0) {
if (CLASS (model)->fetch_nb_rows)
- CLASS (model)->fetch_nb_rows (model);
+ _gda_data_select_fetch_nb_rows (model);
if (model->advertized_nrows < 0) {
g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_ACCESS_ERROR,
"%s", _("Can't get the number of rows of data model"));
@@ -3843,7 +3864,7 @@ gda_data_select_prepare_for_offline (GdaDataSelect *model, GError **error)
if (model->nb_stored_rows != model->advertized_nrows) {
if (CLASS (model)->store_all) {
- if (! CLASS (model)->store_all (model, error))
+ if (! _gda_data_select_store_all (model, error))
return FALSE;
}
}
@@ -3852,7 +3873,7 @@ gda_data_select_prepare_for_offline (GdaDataSelect *model, GError **error)
for (i = 0; i < model->advertized_nrows; i++) {
if (!g_hash_table_lookup (model->priv->sh->index, &i)) {
GdaRow *prow;
- if (! CLASS (model)->fetch_at (model, &prow, i, error))
+ if (! _gda_data_select_fetch_at (model, &prow, i, error))
return FALSE;
g_assert (prow);
gda_data_select_take_row (model, prow, i);
@@ -3860,3 +3881,200 @@ gda_data_select_prepare_for_offline (GdaDataSelect *model, GError **error)
}
return TRUE;
}
+
+
+/*
+ * Implementation using GdaWorker
+ */
+
+static gpointer
+worker_fetch_nb_rows (GdaDataSelect *model, GError **error)
+{
+ gint *nbrows;
+ nbrows = g_slice_new (gint);
+ if (CLASS (model)->fetch_nb_rows)
+ *nbrows = CLASS (model)->fetch_nb_rows (model);
+ else
+ *nbrows = -1;
+
+ return (gpointer) nbrows;
+}
+
+static gint
+_gda_data_select_fetch_nb_rows (GdaDataSelect *model)
+{
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (model->priv->cnc);
+
+ gint nbrows = -1;
+ gint *result;
+ if (gda_worker_do_job (model->priv->worker, context, 0, (gpointer) &result, NULL,
+ (GdaWorkerFunc) worker_fetch_nb_rows, model, NULL, NULL, NULL)) {
+ nbrows = *result;
+ g_slice_free (gint, result);
+ }
+ g_main_context_unref (context);
+
+ return nbrows;
+}
+
+/***********************************************************************************************************/
+
+typedef struct {
+ GdaDataSelect *model;
+ GdaRow **prow;
+ gint rownum;
+} WorkerData;
+
+static gpointer
+worker_fetch_random (WorkerData *data, GError **error)
+{
+ gboolean res;
+ if (CLASS (data->model)->fetch_random)
+ res = CLASS (data->model)->fetch_random (data->model, data->prow, data->rownum, error);
+ else
+ res = FALSE;
+
+ return res ? (gpointer) 0x01 : NULL;
+}
+
+static gboolean
+_gda_data_select_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
+{
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (model->priv->cnc);
+
+ WorkerData jdata;
+ jdata.model = model;
+ jdata.prow = prow;
+ jdata.rownum = rownum;
+
+ gpointer result;
+ gda_worker_do_job (model->priv->worker, context, 0, &result, NULL,
+ (GdaWorkerFunc) worker_fetch_random, &jdata, NULL, NULL, error);
+ g_main_context_unref (context);
+ return result ? TRUE : FALSE;
+}
+
+/***********************************************************************************************************/
+
+static gpointer
+worker_store_all (GdaDataSelect *model, GError **error)
+{
+ gboolean res;
+ if (CLASS (model)->store_all)
+ res = CLASS (model)->store_all (model, error);
+ else
+ res = FALSE;
+
+ return res ? (gpointer) 0x01 : NULL;
+}
+
+static gboolean
+_gda_data_select_store_all (GdaDataSelect *model, GError **error)
+{
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (model->priv->cnc);
+
+ gpointer result;
+ gda_worker_do_job (model->priv->worker, context, 0, (gpointer) &result, NULL,
+ (GdaWorkerFunc) worker_store_all, model, NULL, NULL, NULL);
+ g_main_context_unref (context);
+ return result ? TRUE : FALSE;
+}
+
+/***********************************************************************************************************/
+
+static gpointer
+worker_fetch_next (WorkerData *data, GError **error)
+{
+ gboolean res;
+ if (CLASS (data->model)->fetch_next)
+ res = CLASS (data->model)->fetch_next (data->model, data->prow, data->rownum, error);
+ else
+ res = FALSE;
+
+ return res ? (gpointer) 0x01 : NULL;
+}
+
+static gboolean
+_gda_data_select_fetch_next (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
+{
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (model->priv->cnc);
+
+ WorkerData jdata;
+ jdata.model = model;
+ jdata.prow = prow;
+ jdata.rownum = rownum;
+
+ gpointer result;
+ gda_worker_do_job (model->priv->worker, context, 0, &result, NULL,
+ (GdaWorkerFunc) worker_fetch_next, &jdata, NULL, NULL, error);
+ g_main_context_unref (context);
+ return result ? TRUE : FALSE;
+}
+
+/***********************************************************************************************************/
+
+static gpointer
+worker_fetch_prev (WorkerData *data, GError **error)
+{
+ gboolean res;
+ if (CLASS (data->model)->fetch_prev)
+ res = CLASS (data->model)->fetch_prev (data->model, data->prow, data->rownum, error);
+ else
+ res = FALSE;
+
+ return res ? (gpointer) 0x01 : NULL;
+}
+
+static gboolean
+_gda_data_select_fetch_prev (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
+{
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (model->priv->cnc);
+
+ WorkerData jdata;
+ jdata.model = model;
+ jdata.prow = prow;
+ jdata.rownum = rownum;
+
+ gpointer result;
+ gda_worker_do_job (model->priv->worker, context, 0, &result, NULL,
+ (GdaWorkerFunc) worker_fetch_prev, &jdata, NULL, NULL, error);
+ g_main_context_unref (context);
+ return result ? TRUE : FALSE;
+}
+
+/***********************************************************************************************************/
+
+static gpointer
+worker_fetch_at (WorkerData *data, GError **error)
+{
+ gboolean res;
+ if (CLASS (data->model)->fetch_at)
+ res = CLASS (data->model)->fetch_at (data->model, data->prow, data->rownum, error);
+ else
+ res = FALSE;
+
+ return res ? (gpointer) 0x01 : NULL;
+}
+
+static gboolean
+_gda_data_select_fetch_at (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
+{
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (model->priv->cnc);
+
+ WorkerData jdata;
+ jdata.model = model;
+ jdata.prow = prow;
+ jdata.rownum = rownum;
+
+ gpointer result;
+ gda_worker_do_job (model->priv->worker, context, 0, &result, NULL,
+ (GdaWorkerFunc) worker_fetch_at, &jdata, NULL, NULL, error);
+ g_main_context_unref (context);
+ return result ? TRUE : FALSE;
+}
diff --git a/libgda/gda-enums.h b/libgda/gda-enums.h
index 69e1a86..64dad3a 100644
--- a/libgda/gda-enums.h
+++ b/libgda/gda-enums.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2006 - 2007 Murray Cumming <murrayc murrayc com>
- * Copyright (C) 2006 - 2011 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2006 - 2013 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 Lesser General Public
@@ -21,15 +21,26 @@
#ifndef __GDA_ENUMS__
#define __GDA_ENUMS__
-/* Isolation state of a transaction */
+/**
+ * GdaTransactionIsolation:
+ * @GDA_TRANSACTION_ISOLATION_SERVER_DEFAULT: isolation level defined by the server
+ * @GDA_TRANSACTION_ISOLATION_READ_COMMITTED:
+ * @GDA_TRANSACTION_ISOLATION_READ_UNCOMMITTED:
+ * @GDA_TRANSACTION_ISOLATION_REPEATABLE_READ:
+ * @GDA_TRANSACTION_ISOLATION_SERIALIZABLE:
+ *
+ * Describes transactions' isolation level
+ */
typedef enum {
- GDA_TRANSACTION_ISOLATION_UNKNOWN,
+ GDA_TRANSACTION_ISOLATION_SERVER_DEFAULT,
GDA_TRANSACTION_ISOLATION_READ_COMMITTED,
GDA_TRANSACTION_ISOLATION_READ_UNCOMMITTED,
GDA_TRANSACTION_ISOLATION_REPEATABLE_READ,
GDA_TRANSACTION_ISOLATION_SERIALIZABLE
} GdaTransactionIsolation;
+#define GDA_TRANSACTION_ISOLATION_UNKNOWN GDA_TRANSACTION_ISOLATION_SERVER_DEFAULT
+
/* status of a value */
typedef enum {
GDA_VALUE_ATTR_NONE = 0,
diff --git a/libgda/gda-holder.c b/libgda/gda-holder.c
index 1a3a2f7..0adfa65 100644
--- a/libgda/gda-holder.c
+++ b/libgda/gda-holder.c
@@ -1125,10 +1125,10 @@ real_gda_holder_set_value (GdaHolder *holder, GValue *value, gboolean do_copy, G
gda_value_free (value);
}
+ gda_holder_unlock ((GdaLockable*) holder);
g_signal_emit (holder, gda_holder_signals[CHANGED], 0);
}
- gda_holder_unlock ((GdaLockable*) holder);
return newvalid;
}
@@ -1375,11 +1375,14 @@ gda_holder_force_invalid_e (GdaHolder *holder, GError *error)
}
/* if we are an alias, then we forward the value setting to the master */
- if (holder->priv->full_bind)
+ if (holder->priv->full_bind) {
gda_holder_force_invalid (holder->priv->full_bind);
- else
+ gda_holder_unlock ((GdaLockable*) holder);
+ }
+ else {
+ gda_holder_unlock ((GdaLockable*) holder);
g_signal_emit (holder, gda_holder_signals[CHANGED], 0);
- gda_holder_unlock ((GdaLockable*) holder);
+ }
}
/**
diff --git a/libgda/gda-meta-store.c b/libgda/gda-meta-store.c
index 335028c..2f36201 100644
--- a/libgda/gda-meta-store.c
+++ b/libgda/gda-meta-store.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2008 - 2009 Bas Driessen <bas driessen xobas com>
* Copyright (C) 2008 - 2011 Murray Cumming <murrayc murrayc com>
- * Copyright (C) 2008 - 2013 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2008 - 2014 Vivien Malerba <malerba gnome-db org>
* Copyright (C) 2010 David King <davidk openismus com>
* Copyright (C) 2010 Jonh Wendell <jwendell gnome org>
* Copyright (C) 2011 - 2012 Daniel Espinosa <despinosa src gnome org>
@@ -987,17 +987,30 @@ gda_meta_store_set_property (GObject *object,
cnc_string = g_value_get_string (value);
if (cnc_string) {
GdaConnection *cnc;
- cnc = gda_connection_open_from_string (NULL, cnc_string, NULL,
- GDA_CONNECTION_OPTIONS_NONE,
- NULL);
- if (!cnc) {
+ GError *error = NULL;
+ cnc = gda_connection_new_from_string (NULL, cnc_string, NULL,
+ GDA_CONNECTION_OPTIONS_NONE,
+ &error);
+ if (cnc) {
+ if (!gda_connection_open (cnc, &error)) {
+ g_object_unref (cnc);
+ cnc = NULL;
+ }
+ }
+ else {
if (g_ascii_strcasecmp (cnc_string, "sqlite")) {
/* use _gda_config_sqlite_provider */
-
+ g_clear_error (&error);
cnc = _gda_open_internal_sqlite_connection
(cnc_string);
}
}
store->priv->cnc = cnc;
+ if (!cnc) {
+ g_warning ("Could not create internal GdaMetaStore
connection:%s\n"
+ "GdaMetaStore object will not work as expected",
+ error && error->message ? error->message : _("No
detail"));
+ g_clear_error (&error);
+ }
}
}
break;
diff --git a/libgda/gda-quark-list.c b/libgda/gda-quark-list.c
index 1a8f2d9..e33d4f8 100644
--- a/libgda/gda-quark-list.c
+++ b/libgda/gda-quark-list.c
@@ -279,21 +279,20 @@ gda_quark_list_clear (GdaQuarkList *qlist)
/**
* gda_quark_list_free:
- * @qlist: a #GdaQuarkList.
+ * @qlist: (allow-none): a #GdaQuarkList, or %NULL
*
* Releases all memory occupied by the given #GdaQuarkList.
*/
void
gda_quark_list_free (GdaQuarkList *qlist)
{
- g_return_if_fail (qlist != NULL);
-
- if (qlist->hash_table)
- g_hash_table_destroy (qlist->hash_table);
- if (qlist->hash_protected)
- g_hash_table_destroy (qlist->hash_protected);
-
- g_free (qlist);
+ if (qlist) {
+ if (qlist->hash_table)
+ g_hash_table_destroy (qlist->hash_table);
+ if (qlist->hash_protected)
+ g_hash_table_destroy (qlist->hash_protected);
+ g_free (qlist);
+ }
}
@@ -543,17 +542,16 @@ protect_foreach (G_GNUC_UNUSED gchar *key, ProtectedValue *pvalue, G_GNUC_UNUSED
/**
* gda_quark_list_protect_values:
- * @qlist: a #GdaQuarkList
+ * @qlist: (allow-none): a #GdaQuarkList, or %NULL
*
- * Call this function to get rid of the clear version of the value associated to
- * @name.
+ * Call this function to get rid of the clear version of all the values stored in @qlist. If @qlist is %NULL,
+ * then this function does nothing.
*
* Since: 5.2.0
*/
void
gda_quark_list_protect_values (GdaQuarkList *qlist)
{
- g_return_if_fail (qlist);
- if (qlist->hash_protected)
+ if (qlist && qlist->hash_protected)
g_hash_table_foreach (qlist->hash_protected, (GHFunc) protect_foreach, NULL);
}
diff --git a/libgda/gda-server-provider-extra.h b/libgda/gda-server-provider-extra.h
index e400b10..3b5f73b 100644
--- a/libgda/gda-server-provider-extra.h
+++ b/libgda/gda-server-provider-extra.h
@@ -26,6 +26,7 @@
#include <libgda/gda-decl.h>
#include <libgda/gda-value.h>
#include <libgda/gda-connection.h>
+#include <libgda/thread-wrapper/gda-worker.h>
G_BEGIN_DECLS
diff --git a/libgda/gda-server-provider-impl.h b/libgda/gda-server-provider-impl.h
new file mode 100644
index 0000000..967f36c
--- /dev/null
+++ b/libgda/gda-server-provider-impl.h
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2013 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 Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GDA_SERVER_PROVIDER_IMPL_H__
+#define __GDA_SERVER_PROVIDER_IMPL_H__
+
+#include <libgda/gda-server-operation.h>
+#include <libgda/gda-connection.h>
+#include <libgda/gda-data-model.h>
+#include <libgda/gda-quark-list.h>
+#include <libgda/gda-statement.h>
+#include <libgda/gda-meta-store.h>
+#include <libgda/gda-xa-transaction.h>
+#include <libgda/thread-wrapper/gda-worker.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GdaServerProviderFunctionsType: (skip)
+ *
+ * Represents the different types of sets of virtual functions which can be implemented for each provider
+ */
+typedef enum {
+ GDA_SERVER_PROVIDER_FUNCTIONS_BASE,
+ GDA_SERVER_PROVIDER_FUNCTIONS_META,
+ GDA_SERVER_PROVIDER_FUNCTIONS_XA,
+
+ GDA_SERVER_PROVIDER_FUNCTIONS_MAX
+} GdaServerProviderFunctionsType;
+
+
+/*
+ * May only be called once for each value of @type */
+void gda_server_provider_set_impl_functions (GdaServerProviderClass *klass,
+ GdaServerProviderFunctionsType type, gpointer functions_set);
+gpointer gda_server_provider_get_impl_functions_for_class (GObjectClass *klass,
GdaServerProviderFunctionsType type);
+
+/**
+ * GdaServerProviderBase: (skip)
+ * @get_name:
+ * @get_version:
+ *
+ * Functions implementing basic features.
+ *
+ * A pointer to this structure is returned by _gda_server_provider_get_impl_functions() when requesting
+ * @GDA_SERVER_PROVIDER_FUNCTIONS_BASE functions.
+ */
+typedef struct {
+ /* functions called from any thread */
+ const gchar *(* get_name) (GdaServerProvider *provider);
+ const gchar *(* get_version) (GdaServerProvider *provider);
+ const gchar *(* get_server_version) (GdaServerProvider *provider, GdaConnection *cnc);
+ gboolean (* supports_feature) (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaConnectionFeature feature);
+ GdaWorker *(* create_worker) (GdaServerProvider *provider); /* may be NULL */
+ GdaConnection *(* create_connection) (GdaServerProvider *provider); /* may be NULL */
+ GdaSqlParser *(* create_parser) (GdaServerProvider *provider, GdaConnection *cnc); /*
may be NULL */
+ GdaDataHandler *(* get_data_handler) (GdaServerProvider *provider, GdaConnection *cnc, /*
may be NULL */
+ GType g_type, const gchar *dbms_type);
+ const gchar *(* get_def_dbms_type) (GdaServerProvider *provider, GdaConnection *cnc, GType
g_type); /* may be NULL */
+ gboolean (* supports_operation) (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaServerOperationType type, GdaSet *options);
+ GdaServerOperation *(* create_operation) (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaServerOperationType type, GdaSet *options, GError
**error);
+ gchar *(* render_operation) (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaServerOperation *op, GError **error);
+ /**
+ * statement_to_sql:
+ * @provider: a #GdaServerProvider
+ * @cnc: a #GdaConnection
+ * @stmt: a #GdaStatement
+ * @params: (allow-none): a #GdaSet object (which can be obtained using
gda_statement_get_parameters()), or %NULL
+ * @flags: SQL rendering flags, as #GdaStatementSqlFlag OR'ed values
+ * @params_used: (allow-none) (element-type Gda.Holder) (out) (transfer container): a place to store
the list of individual #GdaHolder objects within @params which have been used
+ * @error: a place to store errors, or %NULL
+ *
+ * Renders @stmt as an SQL statement, adapted to the SQL dialect used by @cnc
+ *
+ * Returns: a new string, or %NULL if an error occurred
+ */
+ gchar *(* statement_to_sql) (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GdaStatementSqlFlag
flags,
+ GSList **params_used, GError **error);
+ /**
+ * identifier_quote:
+ * @provider: a #GdaServerProvider
+ * @cnc: (allow-none): a #GdaConnection, or %NULL
+ * @id: a string
+ * @for_meta_store: if %TRUE, then the result have to respect the #GdaMetaStore convention
+ * @force_quotes: if %TRUE, then quotes have to be added
+ *
+ * Create a new string in which @id can be used in an SQL statement, for example by adding quotes if
+ * it is a reserved keyword, or if it is case sensitive.
+ *
+ * If not %NULL, @cnc can either be opened or closed.
+ *
+ * Returns: (transfer full): a new string
+ */
+ gchar *(* identifier_quote) (GdaServerProvider *provider, GdaConnection *cnc, /* may
be NULL */
+ const gchar *id,
+ gboolean for_meta_store, gboolean force_quotes);
+
+ GdaSqlStatement *(* statement_rewrite) (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error);
+ /**
+ * open_connection:
+ * @provider: a #GdaServerProvider
+ * @cnc: a #GdaConnection
+ * @params: (transfer none): a #GdaQuarkList containing the connection parameters (HOST, DATABASE,
etc.)
+ * @auth: (transfer none) (allow-none): a #GdaQuarkList containing the connection authentification
parameters (USERNAME, PASSWORD, etc.), or %NULL
+ *
+ * Open the connection. @params and @auth must be left unchanged.
+ *
+ * Returns: %TRUE if the connection was opened.
+ */
+ gboolean (* open_connection) (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaQuarkList *params, GdaQuarkList *auth);
+ gboolean (* prepare_connection) (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaQuarkList *params, GdaQuarkList *auth);
+ gboolean (* close_connection) (GdaServerProvider *provider, GdaConnection *cnc);
+ gchar *(* escape_string) (GdaServerProvider *provider, GdaConnection *cnc, const gchar
*str); /* may be NULL */
+ gchar *(* unescape_string) (GdaServerProvider *provider, GdaConnection *cnc, const gchar
*str); /* may be NULL */
+ const gchar *(* get_database) (GdaServerProvider *provider, GdaConnection *cnc);
+ gboolean (* perform_operation) (GdaServerProvider *provider, GdaConnection *cnc, /* may be
NULL */
+ GdaServerOperation *op, GError **error);
+ gboolean (* begin_transaction) (GdaServerProvider *provider, GdaConnection *cnc,
+ const gchar *name, GdaTransactionIsolation level, GError
**error);
+ gboolean (* commit_transaction) (GdaServerProvider *provider, GdaConnection *cnc,
+ const gchar *name, GError **error);
+ gboolean (* rollback_transaction) (GdaServerProvider *provider, GdaConnection *cnc,
+ const gchar *name, GError **error);
+ gboolean (* add_savepoint) (GdaServerProvider *provider, GdaConnection *cnc,
+ const gchar *name, GError **error);
+ gboolean (* rollback_savepoint) (GdaServerProvider *provider, GdaConnection *cnc,
+ const gchar *name, GError **error);
+ gboolean (* delete_savepoint) (GdaServerProvider *provider, GdaConnection *cnc,
+ const gchar *name, GError **error);
+ gboolean (* statement_prepare) (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GError **error);
+ GObject *(* statement_execute) (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params,
+ GdaStatementModelUsage model_usage,
+ GType *col_types, GdaSet **last_inserted_row, GError
**error);
+
+ /*< private >*/
+ /* Padding for future expansion */
+ void (*_gda_reserved11) (void);
+ void (*_gda_reserved12) (void);
+ void (*_gda_reserved13) (void);
+ void (*_gda_reserved14) (void);
+} GdaServerProviderBase;
+
+
+/**
+ * GdaServerProviderMeta: (skip)
+ * @_info:
+ * @_btypes:
+ * @_udt:
+ * @udt:
+ * @_udt_cols:
+ * @udt_cols:
+ * @_enums:
+ * @enums:
+ * @_domains:
+ * @domains:
+ * @_constraints_dom:
+ * @constraints_dom:
+ * @_el_types:
+ * @el_types:
+ * @_collations:
+ * @collations:
+ * @_character_sets:
+ * @character_sets:
+ * @_schemata:
+ * @schemata:
+ * @_tables_views:
+ * @tables_views:
+ * @_columns:
+ * @columns:
+ * @_view_cols:
+ * @view_cols:
+ * @_constraints_tab:
+ * @constraints_tab:
+ * @_constraints_ref:
+ * @constraints_ref:
+ * @_key_columns:
+ * @key_columns:
+ * @_check_columns:
+ * @check_columns:
+ * @_triggers:
+ * @triggers:
+ * @_routines:
+ * @routines:
+ * @_routine_col:
+ * @routine_col:
+ * @_routine_par:
+ * @routine_par:
+ * @_indexes_tab:
+ * @indexes_tab:
+ * @_index_cols:
+ * @index_cols:
+ *
+ * These methods must be implemented by providers to update a connection's associated metadata (in a
+ * #GdaMetaStore object), see the <link linkend="prov-metadata">Virtual methods for providers/Methods -
metadata</link>
+ * for more information.
+ */
+typedef struct {
+ /* _information_schema_catalog_name */
+ gboolean (*_info) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+
+ /* _builtin_data_types */
+ gboolean (*_btypes) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+
+ /* _udt */
+ gboolean (*_udt) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*udt) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *udt_catalog, const GValue *udt_schema);
+
+ /* _udt_columns */
+ gboolean (*_udt_cols) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*udt_cols) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *udt_catalog, const GValue *udt_schema, const GValue
*udt_name);
+
+ /* _enums */
+ gboolean (*_enums) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*enums) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *udt_catalog, const GValue *udt_schema, const GValue
*udt_name);
+
+ /* _domains */
+ gboolean (*_domains) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*domains) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *domain_catalog, const GValue *domain_schema);
+
+ /* _domain_constraints */
+ gboolean (*_constraints_dom) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*constraints_dom) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *domain_catalog, const GValue *domain_schema, const GValue
*domain_name);
+
+ /* _element_types */
+ gboolean (*_el_types) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*el_types) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *specific_name);
+
+ /* _collations */
+ gboolean (*_collations) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*collations) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *collation_catalog, const GValue *collation_schema,
+ const GValue *collation_name_n);
+
+ /* _character_sets */
+ gboolean (*_character_sets) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*character_sets) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *chset_catalog, const GValue *chset_schema, const GValue
*chset_name_n);
+
+ /* _schemata */
+ gboolean (*_schemata) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*schemata) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *catalog_name, const GValue *schema_name_n);
+
+ /* _tables or _views */
+ gboolean (*_tables_views) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*tables_views) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *table_catalog, const GValue *table_schema, const GValue
*table_name_n);
+
+ /* _columns */
+ gboolean (*_columns) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*columns) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *table_catalog, const GValue *table_schema, const GValue
*table_name);
+
+ /* _view_column_usage */
+ gboolean (*_view_cols) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*view_cols) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *view_catalog, const GValue *view_schema, const GValue
*view_name);
+
+ /* _table_constraints */
+ gboolean (*_constraints_tab) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*constraints_tab) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *table_catalog, const GValue *table_schema, const GValue
*table_name,
+ const GValue *constraint_name_n);
+
+ /* _referential_constraints */
+ gboolean (*_constraints_ref) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*constraints_ref) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *table_catalog, const GValue *table_schema, const GValue
*table_name,
+ const GValue *constraint_name);
+
+ /* _key_column_usage */
+ gboolean (*_key_columns) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*key_columns) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *table_catalog, const GValue *table_schema, const GValue
*table_name,
+ const GValue *constraint_name);
+
+ /* _check_column_usage */
+ gboolean (*_check_columns) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*check_columns) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *table_catalog, const GValue *table_schema, const GValue
*table_name,
+ const GValue *constraint_name);
+
+ /* _triggers */
+ gboolean (*_triggers) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*triggers) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *table_catalog, const GValue *table_schema, const GValue
*table_name);
+
+ /* _routines */
+ gboolean (*_routines) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*routines) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *routine_catalog, const GValue *routine_schema,
+ const GValue *routine_name_n);
+
+ /* _routine_columns */
+ gboolean (*_routine_col) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*routine_col) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *rout_catalog, const GValue *rout_schema, const GValue
*rout_name);
+
+ /* _parameters */
+ gboolean (*_routine_par) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*routine_par) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *rout_catalog, const GValue *rout_schema, const GValue
*rout_name);
+ /* _table_indexes */
+ gboolean (*_indexes_tab) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*indexes_tab) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *table_catalog, const GValue *table_schema, const GValue
*table_name,
+ const GValue *index_name_n);
+
+ /* _index_column_usage */
+ gboolean (*_index_cols) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
+ gboolean (*index_cols) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
+ const GValue *table_catalog, const GValue *table_schema, const GValue
*table_name, const GValue *index_name);
+
+ /*< private >*/
+ /* Padding for future expansion */
+ void (*_gda_reserved1) (void);
+ void (*_gda_reserved2) (void);
+ void (*_gda_reserved3) (void);
+ void (*_gda_reserved4) (void);
+ void (*_gda_reserved5) (void);
+ void (*_gda_reserved6) (void);
+ void (*_gda_reserved7) (void);
+ void (*_gda_reserved8) (void);
+ void (*_gda_reserved9) (void);
+ void (*_gda_reserved10) (void);
+ void (*_gda_reserved11) (void);
+ void (*_gda_reserved12) (void);
+} GdaServerProviderMeta;
+
+typedef enum {
+ /* _information_schema_catalog_name */
+ GDA_SERVER_META__INFO = 0,
+
+ /* _builtin_data_types */
+ GDA_SERVER_META__BTYPES = 1,
+
+ /* _udt */
+ GDA_SERVER_META__UDT = 2,
+ GDA_SERVER_META_UDT = 3,
+
+ /* _udt_columns */
+ GDA_SERVER_META__UDT_COLS = 4,
+ GDA_SERVER_META_UDT_COLS = 5,
+
+ /* _enums */
+ GDA_SERVER_META__ENUMS = 6,
+ GDA_SERVER_META_ENUMS = 7,
+
+ /* _domains */
+ GDA_SERVER_META__DOMAINS = 8,
+ GDA_SERVER_META_DOMAINS = 9,
+
+ /* _domain_constraints */
+ GDA_SERVER_META__CONSTRAINTS_DOM = 10,
+ GDA_SERVER_META_CONSTRAINTS_DOM = 11,
+
+ /* _element_types */
+ GDA_SERVER_META__EL_TYPES = 12,
+ GDA_SERVER_META_EL_TYPES = 13,
+
+ /* _collations */
+ GDA_SERVER_META__COLLATIONS = 14,
+ GDA_SERVER_META_COLLATIONS = 15,
+
+ /* _character_sets */
+ GDA_SERVER_META__CHARACTER_SETS = 16,
+ GDA_SERVER_META_CHARACTER_SETS = 17,
+
+ /* _schemata */
+ GDA_SERVER_META__SCHEMATA = 18,
+ GDA_SERVER_META_SCHEMATA = 19,
+
+ /* _tables or _views */
+ GDA_SERVER_META__TABLES_VIEWS = 20,
+ GDA_SERVER_META_TABLES_VIEWS = 21,
+
+ /* _columns */
+ GDA_SERVER_META__COLUMNS = 22,
+ GDA_SERVER_META_COLUMNS = 23,
+
+ /* _view_column_usage */
+ GDA_SERVER_META__VIEW_COLS = 24,
+ GDA_SERVER_META_VIEW_COLS = 25,
+
+ /* _table_constraints */
+ GDA_SERVER_META__CONSTRAINTS_TAB = 26,
+ GDA_SERVER_META_CONSTRAINTS_TAB = 27,
+
+ /* _referential_constraints */
+ GDA_SERVER_META__CONSTRAINTS_REF = 28,
+ GDA_SERVER_META_CONSTRAINTS_REF = 29,
+
+ /* _key_column_usage */
+ GDA_SERVER_META__KEY_COLUMNS = 30,
+ GDA_SERVER_META_KEY_COLUMNS = 31,
+
+ /* _check_column_usage */
+ GDA_SERVER_META__CHECK_COLUMNS = 32,
+ GDA_SERVER_META_CHECK_COLUMNS = 33,
+
+ /* _triggers */
+ GDA_SERVER_META__TRIGGERS = 34,
+ GDA_SERVER_META_TRIGGERS = 35,
+
+ /* _routines */
+ GDA_SERVER_META__ROUTINES = 36,
+ GDA_SERVER_META_ROUTINES = 37,
+
+ /* _routine_columns */
+ GDA_SERVER_META__ROUTINE_COL = 38,
+ GDA_SERVER_META_ROUTINE_COL = 39,
+
+ /* _parameters */
+ GDA_SERVER_META__ROUTINE_PAR = 40,
+ GDA_SERVER_META_ROUTINE_PAR = 41,
+
+ /* _table_indexes */
+ GDA_SERVER_META__INDEXES_TAB = 42,
+ GDA_SERVER_META_INDEXES_TAB = 43,
+
+ /* _index_column_usage */
+ GDA_SERVER_META__INDEX_COLS = 44,
+ GDA_SERVER_META_INDEX_COLS = 45,
+} GdaServerProviderMetaType;
+
+
+/**
+ * GdaServerProviderXa: (skip)
+ * @xa_start:
+ * @xa_end:
+ * @xa_prepare:
+ * @xa_commit:
+ * @xa_rollback:
+ * @xa_recover:
+ *
+ * Functions implementing distributed transactions.
+ */
+typedef struct {
+ gboolean (*xa_start) (GdaServerProvider *prov, GdaConnection *cnc, const GdaXaTransactionId *trx,
GError **error);
+
+ gboolean (*xa_end) (GdaServerProvider *prov, GdaConnection *cnc, const GdaXaTransactionId *trx,
GError **error);
+ gboolean (*xa_prepare) (GdaServerProvider *prov, GdaConnection *cnc, const GdaXaTransactionId *trx,
GError **error);
+
+ gboolean (*xa_commit) (GdaServerProvider *prov, GdaConnection *cnc, const GdaXaTransactionId *trx,
GError **error);
+ gboolean (*xa_rollback) (GdaServerProvider *prov, GdaConnection *cnc, const GdaXaTransactionId *trx,
GError **error);
+
+ GList *(*xa_recover) (GdaServerProvider *prov, GdaConnection *cnc, GError **error);
+
+ /*< private >*/
+ /* Padding for future expansion */
+ void (*_gda_reserved1) (void);
+ void (*_gda_reserved2) (void);
+ void (*_gda_reserved3) (void);
+ void (*_gda_reserved4) (void);
+} GdaServerProviderXa;
+
+G_END_DECLS
+
+#endif
diff --git a/libgda/gda-server-provider-private.h b/libgda/gda-server-provider-private.h
index 7d36f3b..111026a 100644
--- a/libgda/gda-server-provider-private.h
+++ b/libgda/gda-server-provider-private.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2005 Dan Winship <danw src gnome org>
- * Copyright (C) 2005 - 2011 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2005 - 2013 Vivien Malerba <malerba gnome-db org>
* Copyright (C) 2005 �lvaro Pe�a <alvaropg telefonica net>
* Copyright (C) 2007 Murray Cumming <murrayc murrayc com>
*
@@ -24,12 +24,135 @@
#define __GDA_SERVER_PROVIDER_PRIVATE__
#include <libgda/gda-meta-store.h>
+#include <libgda/gda-server-provider-impl.h>
+/*
+ * provider's private information
+ */
struct _GdaServerProviderPrivate {
GHashTable *data_handlers; /* key = a GdaServerProviderHandlerInfo pointer, value = a
GdaDataHandler */
GdaSqlParser *parser;
+
+ GHashTable *jobs_hash; /* key = a job ID, value = a # */
+ GdaWorker *gen_worker; /* worker used when no connection is specified, and yet the provider's
code need
+ * to be executed */
};
+
+/*
+ * Getting the GMainContext to use with the GdaWorker
+ */
+GMainContext *_gda_server_provider_get_real_main_context (GdaConnection *cnc);
+
+/*
+ * GdaServerProvider's virtual functions access
+ */
+gpointer _gda_server_provider_get_impl_functions (GdaServerProvider *provider, GdaWorker *worker,
+ GdaServerProviderFunctionsType type);
+
+/*
+ * private API to access the provider's virtual methods, but only through the GdaWorker's prism
+ */
+GdaConnection *
+_gda_server_provider_create_connection (GdaServerProvider *provider, const gchar *dsn_string, const gchar
*cnc_string,
+ const gchar *auth_string, GdaConnectionOptions options);
+
+#define _gda_server_provider_open_connection_sync(p,c,pa,a,e) \
+ _gda_server_provider_open_connection((p), (c), (pa), (a), NULL, NULL, NULL, (e))
+#define _gda_server_provider_open_connection_async(p,c,pa,a,f,d,ou,e) \
+ _gda_server_provider_open_connection((p), (c), (pa), (a), (f), (d), (ou), (e))
+
+gboolean
+_gda_server_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaQuarkList *params, GdaQuarkList *auth,
+ GdaConnectionOpenFunc cb_func, gpointer data, guint *out_job_id,
+ GError **error);
+gboolean
+_gda_server_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc,
+ GError **error);
+
+gboolean
+_gda_server_provider_statement_prepare (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GError **error);
+
+gchar *
+_gda_server_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GdaStatementSqlFlag flags,
+ GSList **params_used, GError **error);
+
+gchar *
+_gda_server_provider_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
+ const gchar *id, gboolean for_meta_store, gboolean force_quotes);
+
+GObject *
+_gda_server_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params,
+ GdaStatementModelUsage model_usage,
+ GType *col_types, GdaSet **last_inserted_row, GError **error);
+gboolean
+_gda_server_provider_meta_0arg (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaMetaStore *meta, GdaMetaContext *ctx,
+ GdaServerProviderMetaType type, GError **error);
+
+gboolean
+_gda_server_provider_begin_transaction (GdaServerProvider *provider, GdaConnection *cnc, const gchar *name,
GdaTransactionIsolation level, GError **error);
+gboolean
+
+_gda_server_provider_commit_transaction (GdaServerProvider *provider, GdaConnection *cnc, const gchar *name,
GError **error);
+
+gboolean
+_gda_server_provider_rollback_transaction (GdaServerProvider *provider, GdaConnection *cnc, const gchar
*name, GError **error);
+
+gboolean
+_gda_server_provider_add_savepoint (GdaServerProvider *provider, GdaConnection *cnc, const gchar *name,
GError **error);
+
+gboolean
+_gda_server_provider_rollback_savepoint (GdaServerProvider *provider, GdaConnection *cnc, const gchar *name,
GError **error);
+
+gboolean
+_gda_server_provider_delete_savepoint (GdaServerProvider *provider, GdaConnection *cnc, const gchar *name,
GError **error);
+
+typedef enum {
+ GDA_XA_START,
+ GDA_XA_END,
+ GDA_XA_PREPARE,
+ GDA_XA_COMMIT,
+ GDA_XA_ROLLBACK,
+ GDA_XA_RECOVER
+} GdaXaType;
+
+gboolean
+_gda_server_provider_xa (GdaServerProvider *provider, GdaConnection *cnc, const GdaXaTransactionId *trx,
GdaXaType type, GError **error);
+#define _gda_server_provider_xa_start(prov,cnc,trx,error)
_gda_server_provider_xa((prov),(cnc),(trx),GDA_XA_START,(error))
+#define _gda_server_provider_xa_end(prov,cnc,trx,error)
_gda_server_provider_xa((prov),(cnc),(trx),GDA_XA_END,(error))
+#define _gda_server_provider_xa_prepare(prov,cnc,trx,error)
_gda_server_provider_xa((prov),(cnc),(trx),GDA_XA_PREPARE,(error))
+#define _gda_server_provider_xa_commit(prov,cnc,trx,error)
_gda_server_provider_xa((prov),(cnc),(trx),GDA_XA_COMMIT,(error))
+#define _gda_server_provider_xa_rollback(prov,cnc,trx,error)
_gda_server_provider_xa((prov),(cnc),(trx),GDA_XA_ROLLBACK,(error))
+
+GList *
+_gda_server_provider_xa_recover (GdaServerProvider *prov, GdaConnection *cnc, GError **error);
+
+gboolean
+_gda_server_provider_meta_1arg (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaMetaStore *meta, GdaMetaContext *ctx,
+ GdaServerProviderMetaType type, const GValue *value0, GError **error);
+
+gboolean
+_gda_server_provider_meta_2arg (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaMetaStore *meta, GdaMetaContext *ctx,
+ GdaServerProviderMetaType type, const GValue *value0, const GValue *value1,
GError **error);
+
+gboolean
+_gda_server_provider_meta_3arg (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaMetaStore *meta, GdaMetaContext *ctx,
+ GdaServerProviderMetaType type, const GValue *value0, const GValue *value1,
const GValue *value2, GError **error);
+
+gboolean
+_gda_server_provider_meta_4arg (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaMetaStore *meta, GdaMetaContext *ctx,
+ GdaServerProviderMetaType type, const GValue *value0, const GValue *value1,
const GValue *value2, const GValue *value3, GError **error);
+
+
G_END_DECLS
#endif
diff --git a/libgda/gda-server-provider.c b/libgda/gda-server-provider.c
index c70a2d9..85b6b92 100644
--- a/libgda/gda-server-provider.c
+++ b/libgda/gda-server-provider.c
@@ -7,7 +7,7 @@
* Copyright (C) 2004 Dani Baeyens <daniel baeyens hispalinux es>
* Copyright (C) 2004 Julio M. Merino Vidal <jmmv menta net>
* Copyright (C) 2005 - 2006 Bas Driessen <bas driessen xobas com>
- * Copyright (C) 2005 - 2011 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2005 - 2014 Vivien Malerba <malerba gnome-db org>
* Copyright (C) 2005 �lvaro Pe�a <alvaropg telefonica net>
* Copyright (C) 2007 Armin Burgmeier <armin openismus com>
* Copyright (C) 2008 Murray Cumming <murrayc murrayc com>
@@ -32,6 +32,8 @@
* Boston, MA 02110-1301, USA.
*/
+#undef GSEAL_ENABLE
+
#include <glib.h>
#include <libgda/gda-server-provider.h>
#include <libgda/gda-server-provider-extra.h>
@@ -43,13 +45,19 @@
#include <string.h>
#include <glib/gi18n-lib.h>
#include <libgda/gda-lockable.h>
+#include <libgda/gda-connection-private.h>
+#include <libgda/gda-connection-internal.h>
+#include <libgda/gda-debug-macros.h>
#define CLASS(provider) (GDA_SERVER_PROVIDER_CLASS (G_OBJECT_GET_CLASS (provider)))
+#define GDA_DEBUG_VIRTUAL
+#undef GDA_DEBUG_VIRTUAL
static void gda_server_provider_class_init (GdaServerProviderClass *klass);
static void gda_server_provider_init (GdaServerProvider *provider,
GdaServerProviderClass *klass);
static void gda_server_provider_finalize (GObject *object);
+static void gda_server_provider_constructed (GObject *object);
static void gda_server_provider_set_property (GObject *object,
guint param_id,
@@ -88,47 +96,7 @@ gda_server_provider_class_init (GdaServerProviderClass *klass)
parent_class = g_type_class_peek_parent (klass);
object_class->finalize = gda_server_provider_finalize;
-
- klass->get_name = NULL;
- klass->get_version = NULL;
- klass->get_server_version = NULL;
- klass->supports_feature = NULL;
-
- klass->get_data_handler = NULL;
- klass->get_def_dbms_type = NULL;
- klass->escape_string = NULL;
- klass->unescape_string = NULL;
-
- klass->open_connection = NULL;
- klass->close_connection = NULL;
- klass->get_database = NULL;
-
- klass->supports_operation = NULL;
- klass->create_operation = NULL;
- klass->render_operation = NULL;
- klass->perform_operation = NULL;
-
- klass->begin_transaction = NULL;
- klass->commit_transaction = NULL;
- klass->rollback_transaction = NULL;
- klass->add_savepoint = NULL;
- klass->rollback_savepoint = NULL;
- klass->delete_savepoint = NULL;
-
- klass->create_parser = NULL;
- klass->statement_to_sql = NULL;
- klass->statement_prepare = NULL;
- klass->statement_execute = NULL;
-
- klass->is_busy = NULL;
- klass->cancel = NULL;
- klass->handle_async = NULL;
-
- klass->create_connection = NULL;
- memset (&(klass->meta_funcs), 0, sizeof (GdaServerProviderMeta));
- klass->xa_funcs = NULL;
-
- klass->limiting_thread = GDA_SERVER_PROVIDER_UNDEFINED_LIMITING_THREAD;
+ object_class->constructed = gda_server_provider_constructed;
/* Properties */
object_class->set_property = gda_server_provider_set_property;
@@ -166,6 +134,10 @@ gda_server_provider_handler_info_free (GdaServerProviderHandlerInfo *info)
g_free (info);
}
+typedef struct _WorkerData WorkerData;
+static void worker_data_free (WorkerData *wd);
+
+
static void
gda_server_provider_init (GdaServerProvider *provider,
G_GNUC_UNUSED GdaServerProviderClass *klass)
@@ -177,20 +149,25 @@ gda_server_provider_init (GdaServerProvider *provider,
(GEqualFunc)
gda_server_provider_handler_info_equal_func,
(GDestroyNotify)
gda_server_provider_handler_info_free,
(GDestroyNotify) g_object_unref);
+ provider->priv->jobs_hash = NULL;
+ provider->priv->gen_worker = NULL;
}
static void
gda_server_provider_finalize (GObject *object)
{
GdaServerProvider *provider = (GdaServerProvider *) object;
-
g_return_if_fail (GDA_IS_SERVER_PROVIDER (provider));
/* free memory */
if (provider->priv) {
g_hash_table_destroy (provider->priv->data_handlers);
+ if (provider->priv->jobs_hash)
+ g_hash_table_destroy (provider->priv->jobs_hash);
if (provider->priv->parser)
g_object_unref (provider->priv->parser);
+ if (provider->priv->gen_worker)
+ gda_worker_unref (provider->priv->gen_worker);
g_free (provider->priv);
provider->priv = NULL;
@@ -200,6 +177,115 @@ gda_server_provider_finalize (GObject *object)
parent_class->finalize (object);
}
+/*
+ * Check that the database provider is properly implemented
+ */
+static void
+gda_server_provider_constructed (GObject *object)
+{
+ GdaServerProvider *provider = (GdaServerProvider *) object;
+ g_return_if_fail (GDA_IS_SERVER_PROVIDER (provider));
+
+ /*g_print ("Provider %p (%s) constructed\n", provider, G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS
(object)));*/
+ if (!provider->priv)
+ g_warning ("Internal error after creation: provider's private part is missing");
+ else {
+ GdaServerProviderBase *fset;
+ fset = CLASS (provider)->functions_sets [GDA_SERVER_PROVIDER_FUNCTIONS_BASE];
+
+ if (! fset)
+ g_warning ("Internal provider implemenation error: general virtual functions are
missing");
+ else {
+ if (! fset->get_name)
+ g_warning ("Internal error after creation: %s() virtual function missing",
"get_name");
+ if (! fset->get_version)
+ g_warning ("Internal error after creation: %s() virtual function missing",
"get_version");
+ if (! fset->get_server_version)
+ g_warning ("Internal error after creation: %s() virtual function missing",
"get_server_version");
+ if (!fset->supports_feature)
+ g_warning ("Internal error after creation: %s() virtual function missing",
"supports_feature");
+ if (! fset->statement_to_sql)
+ g_warning ("Internal error after creation: %s() virtual function missing",
"statement_to_sql");
+ if (! fset->statement_rewrite)
+ g_warning ("Internal error after creation: %s() virtual function missing",
"statement_rewrite");
+ if (! fset->open_connection)
+ g_warning ("Internal error after creation: %s() virtual function missing",
"open_connection");
+ if (! fset->close_connection)
+ g_warning ("Internal error after creation: %s() virtual function missing",
"close_connection");
+ if (fset->escape_string && !fset->unescape_string)
+ g_warning ("Internal error after creation: virtual method %s implemented and
%s _not_ implemented",
+ "escape_string()", "unescape_string()");
+ else if (!fset->escape_string && fset->unescape_string)
+ g_warning ("Internal error after creation: virtual method %s implemented and
%s _not_ implemented",
+ "unescape_string()", "escape_string()");
+ if (! fset->get_database)
+ g_warning ("Internal error after creation: %s() virtual function missing",
"get_database");
+ if (! fset->statement_prepare)
+ g_warning ("Internal error after creation: %s() virtual function missing",
"statement_prepare");
+ if (! fset->statement_execute)
+ g_warning ("Internal error after creation: %s() virtual function missing",
"statement_execute");
+ if (fset->begin_transaction || fset->commit_transaction ||
fset->rollback_transaction) {
+ if (! fset->begin_transaction)
+ g_warning ("Internal error after creation: %s() virtual function
missing",
+ "begin_transaction");
+ if (! fset->commit_transaction)
+ g_warning ("Internal error after creation: %s() virtual function
missing",
+ "commit_transaction");
+ if (! fset->rollback_transaction)
+ g_warning ("Internal error after creation: %s() virtual function
missing",
+ "rollback_transaction");
+ }
+ if (fset->add_savepoint || fset->rollback_savepoint || fset->delete_savepoint) {
+ if (! fset->add_savepoint)
+ g_warning ("Internal error after creation: %s() virtual function
missing",
+ "add_savepoint");
+ if (! fset->rollback_savepoint)
+ g_warning ("Internal error after creation: %s() virtual function
missing",
+ "rollback_savepoint");
+ if (! fset->delete_savepoint)
+ g_warning ("Internal error after creation: %s() virtual function
missing",
+ "delete_savepoint");
+ }
+ }
+
+ if (GDA_IS_SERVER_PROVIDER_CLASS (parent_class)) {
+ if (! CLASS (provider)->functions_sets [GDA_SERVER_PROVIDER_FUNCTIONS_META])
+ CLASS (provider)->functions_sets [GDA_SERVER_PROVIDER_FUNCTIONS_META] =
+ GDA_SERVER_PROVIDER_CLASS (parent_class)->functions_sets
[GDA_SERVER_PROVIDER_FUNCTIONS_META];
+ if (! CLASS (provider)->functions_sets [GDA_SERVER_PROVIDER_FUNCTIONS_XA])
+ CLASS (provider)->functions_sets [GDA_SERVER_PROVIDER_FUNCTIONS_XA] =
+ GDA_SERVER_PROVIDER_CLASS (parent_class)->functions_sets
[GDA_SERVER_PROVIDER_FUNCTIONS_XA];
+ }
+
+ GdaServerProviderXa *xaset;
+ xaset = CLASS (provider)->functions_sets [GDA_SERVER_PROVIDER_FUNCTIONS_XA];
+ if (xaset && (xaset->xa_start || xaset->xa_end || xaset->xa_prepare || xaset->xa_commit ||
+ xaset->xa_rollback || xaset->xa_recover)) {
+ if (! xaset->xa_start)
+ g_warning ("Internal error after creation: %s() virtual function missing",
+ "xa_start");
+ if (! xaset->xa_end)
+ g_warning ("Internal error after creation: %s() virtual function missing",
+ "xa_end");
+ if (! xaset->xa_prepare)
+ g_warning ("Internal error after creation: %s() virtual function missing",
+ "xa_prepare");
+ if (! xaset->xa_commit)
+ g_warning ("Internal error after creation: %s() virtual function missing",
+ "xa_commit");
+ if (! xaset->xa_rollback)
+ g_warning ("Internal error after creation: %s() virtual function missing",
+ "xa_rollback");
+ if (! xaset->xa_recover)
+ g_warning ("Internal error after creation: %s() virtual function missing",
+ "xa_recover");
+ }
+ }
+
+ /* chain to parent class */
+ parent_class->constructed (object);
+}
+
GType
gda_server_provider_get_type (void)
{
@@ -263,6 +349,199 @@ gda_server_provider_get_property (GObject *object,
}
/**
+ * gda_server_provider_set_impl_functions: (skip)
+ * @klass: a #GdaServerProviderClass object
+ * @type: a #GdaServerProviderFunctionsType type
+ * @functions_set: (allow-none): a pointer to the function set, or %NULL
+ *
+ * Upon creation, used by provider's implementors to set the implementation functions. Passing %NULL
+ * as the @functions_set has no effect.
+ *
+ * If some pointers of @functions_set are %NULL, they are replaced by functions from the parent class of
+ * @provider.
+ *
+ * Warning: this function must only be called once for each different values of @type and for each @klass
+ *
+ * Since: 6.0
+ */
+void
+gda_server_provider_set_impl_functions (GdaServerProviderClass *klass,
+ GdaServerProviderFunctionsType type, gpointer functions_set)
+{
+ g_return_if_fail (GDA_IS_SERVER_PROVIDER_CLASS (klass));
+ g_return_if_fail ((type >= 0) && (type < GDA_SERVER_PROVIDER_FUNCTIONS_MAX));
+
+#ifdef GDA_DEBUG_VIRTUAL
+ static GObjectClass *parent_pclass = NULL;
+ parent_pclass = g_type_class_peek_parent (klass);
+
+ g_print ("[V] %s (klass=>%p, Class=>%s, type=>%d, parent_class=>%p, parent class name=>%s )\n",
__FUNCTION__,
+ klass, G_OBJECT_CLASS_NAME (klass),
+ type, parent_pclass, G_OBJECT_CLASS_NAME (parent_pclass));
+#endif
+
+ if (!functions_set)
+ return;
+
+ guint size;
+ typedef void (*VirtualFunc) (void);
+ switch (type) {
+ case GDA_SERVER_PROVIDER_FUNCTIONS_BASE:
+ size = sizeof (GdaServerProviderBase) / sizeof (VirtualFunc);
+ break;
+ case GDA_SERVER_PROVIDER_FUNCTIONS_META:
+ size = sizeof (GdaServerProviderMeta) / sizeof (VirtualFunc);
+ break;
+ case GDA_SERVER_PROVIDER_FUNCTIONS_XA:
+ size = sizeof (GdaServerProviderXa) / sizeof (VirtualFunc);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ guint i;
+ VirtualFunc *functions;
+ functions = (VirtualFunc*) klass->functions_sets [type];
+ if (functions) {
+ VirtualFunc *new_functions;
+ new_functions = (VirtualFunc*) functions_set;
+ for (i = 0; i < size; i++) {
+ VirtualFunc func;
+ func = new_functions [i];
+ if (!func && functions [i]) {
+ new_functions [i] = functions [i];
+#ifdef GDA_DEBUG_VIRTUAL
+ g_print ("[V] Virtual function @index %u replaced by %p\n", i, new_functions
[i]);
+#endif
+ }
+ }
+ }
+
+ klass->functions_sets [type] = functions_set;
+}
+
+/**
+ * _gda_server_provider_get_impl_functions: (skip)
+ * @provider: a #GdaServerProvider object
+ * @worker: a #GdaWorker
+ * @type: a #GdaServerProviderFunctionsType type
+ *
+ * Retreive the pointer to a functions set, as defined by gda_server_provider_set_impl_functions().
+ *
+ * Note: @worker MUST NOT BE %NULL because this function checks that it is actually called from within its
worker thread.
+ *
+ * Returns: the pointer to the function set, or %NULL
+ *
+ * Since: 6.0
+ */
+gpointer
+_gda_server_provider_get_impl_functions (GdaServerProvider *provider, GdaWorker *worker,
GdaServerProviderFunctionsType type)
+{
+ g_return_if_fail (GDA_IS_SERVER_PROVIDER (provider));
+
+ g_return_if_fail ((type >= 0) && (type < GDA_SERVER_PROVIDER_FUNCTIONS_MAX));
+ g_return_if_fail (worker);
+ g_return_if_fail (gda_worker_thread_is_worker (worker));
+
+ return CLASS (provider)->functions_sets [type];
+}
+
+/*
+ * gda_server_provider_get_impl_functions_for_class:
+ * @provider: a #GdaServerProvider object
+ * @type: a #GdaServerProviderFunctionsType type
+ *
+ * Reserved to database provider's implementation, to get the virtual functions of the parent implementation.
+ *
+ * NB: this function must only be calld from within a GdaWorker's worker thread!
+ */
+gpointer
+gda_server_provider_get_impl_functions_for_class (GObjectClass *klass, GdaServerProviderFunctionsType type)
+{
+ g_return_if_fail (GDA_IS_SERVER_PROVIDER_CLASS (klass));
+ g_return_if_fail ((type >= 0) && (type < GDA_SERVER_PROVIDER_FUNCTIONS_MAX));
+
+#ifdef GDA_DEBUG_VIRTUAL
+ g_print ("[V-klass] %s (klass=>%p, Class=>%s)\n", __FUNCTION__,
+ klass, G_OBJECT_CLASS_NAME (klass));
+#endif
+
+ return GDA_SERVER_PROVIDER_CLASS (klass)->functions_sets [type];
+}
+
+/*
+ * _gda_server_provider_create_worker:
+ * @prov: a #GdaServerProvider
+ * @for_new_cnc: if %FALSE, then we try to reuse a #GdaWorker, otherwise the GdaWorker will be used for a
new connection
+ *
+ * Have @prov create a #GdaWorker. Any connection and C API will only be manipulated by the worker's working
thread,
+ * so if @prov can only be used by 1 thread, then it needs to always return the same object (increasing its
reference count).
+ *
+ * Important Note: that this is the only code from the provider's implementation to be called by any thread.
+ *
+ * Returns: (transfer full): a new #GdaWorker
+ */
+static GdaWorker *
+_gda_server_provider_create_worker (GdaServerProvider *provider, gboolean for_new_cnc)
+{
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
+
+ if (for_new_cnc) {
+ GdaServerProviderBase *fset;
+ fset = CLASS (provider)->functions_sets [GDA_SERVER_PROVIDER_FUNCTIONS_BASE]; /* rem: we
don't use
+ *
_gda_server_provider_get_impl_functions()
+ * because this
would fail if not
+ * called from
the worker thread */
+ if (fset->create_worker)
+ return (fset->create_worker) (provider);
+ else
+ return gda_worker_new ();
+ }
+ else {
+ if (!provider->priv->gen_worker)
+ provider->priv->gen_worker = _gda_server_provider_create_worker (provider, TRUE);
+ return gda_worker_ref (provider->priv->gen_worker);
+ }
+}
+
+/*
+ * Obtain a #GMainContext on which to iterate.
+ * @cnc: (allow-none): a #GdaConnection, or %NULL
+ *
+ * Returns: a #GMainContext. Don't forget to call g_main_context_unref() when done
+ */
+GMainContext *
+_gda_server_provider_get_real_main_context (GdaConnection *cnc)
+{
+ GMainContext *context;
+ context = gda_connection_get_main_context (cnc);
+ if (context)
+ g_main_context_ref (context);
+ else
+ context = g_main_context_new ();
+ return context;
+}
+
+typedef struct {
+ GdaWorker *worker;
+ GdaServerProvider *provider;
+ GdaConnection *cnc;
+} WorkerGetInfoData;
+
+/* code executed in GdaWorker's worker thread */
+static gpointer
+worker_get_version (WorkerGetInfoData *data, G_GNUC_UNUSED GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ if (fset->get_version)
+ return (gpointer) fset->get_version (data->provider);
+ else
+ return NULL;
+}
+
+/**
* gda_server_provider_get_version:
* @provider: a #GdaServerProvider object.
*
@@ -274,9 +553,37 @@ const gchar *
gda_server_provider_get_version (GdaServerProvider *provider)
{
g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
- g_return_val_if_fail (CLASS (provider)->get_version, NULL);
- return CLASS (provider)->get_version (provider);
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (NULL);
+
+ GdaWorker *worker;
+ worker = _gda_server_provider_create_worker (provider, FALSE);
+
+ WorkerGetInfoData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = NULL;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_get_version, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+ gda_worker_unref (worker);
+ return (const gchar*) retval;
+}
+
+/* code executed in GdaWorker's worker thread */
+static gpointer
+worker_get_name (WorkerGetInfoData *data, G_GNUC_UNUSED GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ if (fset->get_name)
+ return (gpointer) fset->get_name (data->provider);
+ else
+ return NULL;
}
/**
@@ -291,9 +598,37 @@ const gchar *
gda_server_provider_get_name (GdaServerProvider *provider)
{
g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
- g_return_val_if_fail (CLASS (provider)->get_name, NULL);
- return CLASS (provider)->get_name (provider);
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (NULL);
+
+ GdaWorker *worker;
+ worker = _gda_server_provider_create_worker (provider, FALSE);
+
+ WorkerGetInfoData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = NULL;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_get_name, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+ gda_worker_unref (worker);
+ return (const gchar*) retval;
+}
+
+/* code executed in GdaWorker's worker thread */
+static gpointer
+worker_get_server_version (WorkerGetInfoData *data, G_GNUC_UNUSED GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ const gchar *retval = NULL;
+ if (fset->get_server_version)
+ retval = fset->get_server_version (data->provider, data->cnc);
+ return (gpointer) retval;
}
/**
@@ -308,16 +643,58 @@ gda_server_provider_get_name (GdaServerProvider *provider)
const gchar *
gda_server_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc)
{
- const gchar *retval;
g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- g_return_val_if_fail (CLASS (provider)->get_server_version != NULL, NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ g_return_val_if_fail (gda_connection_is_opened (cnc), NULL);
- gda_lockable_lock ((GdaLockable*) cnc);
- retval = CLASS (provider)->get_server_version (provider, cnc);
- gda_lockable_unlock ((GdaLockable*) cnc);
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
- return retval;
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerGetInfoData data;
+ data.worker = cdata->worker;
+ data.provider = provider;
+ data.cnc = cnc;
+
+ gpointer retval;
+ gda_worker_do_job (cdata->worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_get_server_version, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ return (const gchar*) retval;
+}
+
+typedef struct {
+ GdaWorker *worker;
+ GdaServerProvider *provider;
+ GdaConnection *cnc;
+ GdaServerOperationType type;
+ GdaSet *options;
+} WorkerSupportsOperationData;
+
+/* code executed in GdaWorker's worker thread */
+static gpointer
+worker_supports_operation (WorkerSupportsOperationData *data, G_GNUC_UNUSED GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ gboolean retval = FALSE;
+ if (fset->supports_operation)
+ retval = fset->supports_operation (data->provider, data->cnc, data->type, data->options);
+ return retval ? (gpointer) 0x01 : NULL;
}
/**
@@ -336,17 +713,47 @@ gboolean
gda_server_provider_supports_operation (GdaServerProvider *provider, GdaConnection *cnc,
GdaServerOperationType type, GdaSet *options)
{
- gboolean retval = FALSE;
+ GdaWorker *worker;
g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
- g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), FALSE);
+ if (cnc) {
+ 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_connection_is_opened (cnc), FALSE);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
+ }
+ else
+ worker = _gda_server_provider_create_worker (provider, FALSE);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerSupportsOperationData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.type = type;
+ data.options = options;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_supports_operation, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+ gda_worker_unref (worker);
if (cnc)
- gda_lockable_lock ((GdaLockable*) cnc);
- if (CLASS (provider)->supports_operation)
- retval = CLASS (provider)->supports_operation (provider, cnc, type, options);
- if (cnc)
- gda_lockable_unlock ((GdaLockable*) cnc);
- return retval;
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ return retval ? TRUE : FALSE;
}
typedef struct {
@@ -448,6 +855,21 @@ static OpReq op_req_CREATE_USER [] = {
{NULL, 0, 0}
};
+typedef WorkerSupportsOperationData WorkerCreateOperationData;
+
+/* code executed in GdaWorker's worker thread */
+static gpointer
+worker_create_operation (WorkerCreateOperationData *data, GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ GdaServerOperation *op = NULL;
+ if (fset->create_operation)
+ op = fset->create_operation (data->provider, data->cnc, data->type, data->options, error);
+ return (gpointer) op;
+}
+
/**
* gda_server_provider_create_operation:
@@ -501,62 +923,109 @@ gda_server_provider_create_operation (GdaServerProvider *provider, GdaConnection
}
g_mutex_unlock (&init_mutex);
+ GdaWorker *worker;
g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
- g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), FALSE);
-
- if (CLASS (provider)->create_operation) {
- GdaServerOperation *op;
-
- if (cnc)
- gda_lockable_lock ((GdaLockable*) cnc);
- op = CLASS (provider)->create_operation (provider, cnc, type, options, error);
- if (op) {
- /* test op's conformance */
- OpReq *opreq = op_req_table [type];
- while (opreq && opreq->path) {
- GdaServerOperationNodeType node_type;
- node_type = gda_server_operation_get_node_type (op, opreq->path, NULL);
- if (node_type == GDA_SERVER_OPERATION_NODE_UNKNOWN)
- g_warning (_("Provider %s created a GdaServerOperation without node
for '%s'"),
- gda_server_provider_get_name (provider), opreq->path);
- else
- if (node_type != opreq->node_type)
- g_warning (_("Provider %s created a GdaServerOperation with
wrong node type for '%s'"),
- gda_server_provider_get_name (provider),
opreq->path);
- opreq += 1;
- }
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ g_return_val_if_fail (gda_connection_is_opened (cnc), NULL);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
+ }
+ else
+ worker = _gda_server_provider_create_worker (provider, FALSE);
- if (options) {
- /* pre-init parameters depending on the @options argument */
- GSList *list;
- xmlNodePtr top, node;
-
- top = xmlNewNode (NULL, BAD_CAST "serv_op_data");
- for (list = options->holders; list; list = list->next) {
- const gchar *id;
- gchar *str = NULL;
- const GValue *value;
-
- id = gda_holder_get_id (GDA_HOLDER (list->data));
- value = gda_holder_get_value (GDA_HOLDER (list->data));
- if (value)
- str = gda_value_stringify (value);
- node = xmlNewTextChild (top, NULL, BAD_CAST "op_data", BAD_CAST str);
- g_free (str);
- xmlSetProp (node, BAD_CAST "path", BAD_CAST id);
- }
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerCreateOperationData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.type = type;
+ data.options = options;
+
+ GdaServerOperation *op;
+ gda_worker_do_job (worker, context, 0, (gpointer) &op, NULL,
+ (GdaWorkerFunc) worker_create_operation, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+ gda_worker_unref (worker);
- if (! gda_server_operation_load_data_from_xml (op, top, error))
- g_warning ("Incorrect options");
- xmlFreeNode (top);
+ if (cnc)
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ if (op) {
+ /* test op's conformance */
+ OpReq *opreq = op_req_table [type];
+ while (opreq && opreq->path) {
+ GdaServerOperationNodeType node_type;
+ node_type = gda_server_operation_get_node_type (op, opreq->path, NULL);
+ if (node_type == GDA_SERVER_OPERATION_NODE_UNKNOWN)
+ g_warning (_("Provider %s created a GdaServerOperation without node for
'%s'"),
+ gda_server_provider_get_name (provider), opreq->path);
+ else
+ if (node_type != opreq->node_type)
+ g_warning (_("Provider %s created a GdaServerOperation with wrong
node type for '%s'"),
+ gda_server_provider_get_name (provider), opreq->path);
+ opreq += 1;
+ }
+
+ if (options) {
+ /* pre-init parameters depending on the @options argument */
+ GSList *list;
+ xmlNodePtr top, node;
+
+ top = xmlNewNode (NULL, BAD_CAST "serv_op_data");
+ for (list = options->holders; list; list = list->next) {
+ const gchar *id;
+ gchar *str = NULL;
+ const GValue *value;
+
+ id = gda_holder_get_id (GDA_HOLDER (list->data));
+ value = gda_holder_get_value (GDA_HOLDER (list->data));
+ if (value)
+ str = gda_value_stringify (value);
+ node = xmlNewTextChild (top, NULL, BAD_CAST "op_data", BAD_CAST str);
+ g_free (str);
+ xmlSetProp (node, BAD_CAST "path", BAD_CAST id);
}
+
+ if (! gda_server_operation_load_data_from_xml (op, top, error))
+ g_warning ("Incorrect options");
+ xmlFreeNode (top);
}
- if (cnc)
- gda_lockable_unlock ((GdaLockable*) cnc);
- return op;
}
- else
- return NULL;
+
+ return op;
+}
+
+typedef struct {
+ GdaWorker *worker;
+ GdaServerProvider *provider;
+ GdaConnection *cnc;
+ GdaServerOperation *op;
+} WorkerRenderOperationData;
+
+/* code executed in GdaWorker's worker thread */
+static gpointer
+worker_render_operation (WorkerRenderOperationData *data, GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ gchar *retval = NULL;
+ if (fset->render_operation)
+ retval = fset->render_operation (data->provider, data->cnc, data->op, error);
+ return (gpointer) retval;
}
/**
@@ -578,20 +1047,70 @@ gchar *
gda_server_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc,
GdaServerOperation *op, GError **error)
{
+ GdaWorker *worker;
g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
- g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
-
- if (CLASS (provider)->render_operation) {
- gchar *retval;
- if (cnc)
- gda_lockable_lock ((GdaLockable*) cnc);
- retval = CLASS (provider)->render_operation (provider, cnc, op, error);
- if (cnc)
- gda_lockable_unlock ((GdaLockable*) cnc);
- return retval;
+ g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL);
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ g_return_val_if_fail (gda_connection_is_opened (cnc), NULL);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
}
else
- return NULL;
+ worker = _gda_server_provider_create_worker (provider, FALSE);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerRenderOperationData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.op = op;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_render_operation, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+
+ if (cnc)
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return (gchar*) retval;
+}
+
+typedef struct {
+ GdaWorker *worker;
+ GdaServerProvider *provider;
+ GdaConnection *cnc;
+ GdaServerOperation *op;
+} WorkerPerformOperationData;
+
+/* code executed in GdaWorker's worker thread */
+static gpointer
+worker_perform_operation (WorkerPerformOperationData *data, GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ gboolean result;
+ if (fset->perform_operation)
+ result = fset->perform_operation (data->provider, data->cnc, data->op, error);
+ else
+ result = gda_server_provider_perform_operation_default (data->provider, data->cnc, data->op,
error);
+ return result ? (gpointer) 0x01 : NULL;
}
/**
@@ -610,9 +1129,36 @@ gboolean
gda_server_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
GdaServerOperation *op, GError **error)
{
- gboolean retval;
- g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
- g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), FALSE);
+ GdaWorker *worker;
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
+ g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL);
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ g_return_val_if_fail (gda_connection_is_opened (cnc), NULL);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
+ }
+ else
+ worker = _gda_server_provider_create_worker (provider, FALSE);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerPerformOperationData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.op = op;
#ifdef GDA_DEBUG_NO
{
@@ -626,15 +1172,47 @@ gda_server_provider_perform_operation (GdaServerProvider *provider, GdaConnectio
xmlFreeDoc (doc);
}
#endif
+
+ gpointer retval = NULL;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_perform_operation, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+
if (cnc)
- gda_lockable_lock ((GdaLockable*) cnc);
- if (CLASS (provider)->perform_operation)
- retval = CLASS (provider)->perform_operation (provider, cnc, op, NULL, NULL, NULL, error);
- else
- retval = gda_server_provider_perform_operation_default (provider, cnc, op, error);
- if (cnc)
- gda_lockable_unlock ((GdaLockable*) cnc);
- return retval;
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return retval ? TRUE : FALSE;
+}
+
+typedef struct {
+ GdaWorker *worker;
+ GdaServerProvider *provider;
+ GdaConnection *cnc;
+ GdaConnectionFeature feature;
+} WorkerSupportsFeatureData;
+
+/* code executed in GdaWorker's worker thread */
+static gpointer
+worker_supports_feature (WorkerSupportsFeatureData *data, G_GNUC_UNUSED GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ gboolean result = FALSE;
+ if (fset->supports_feature) {
+ result = fset->supports_feature (data->provider, data->cnc, data->feature);
+ if (result && (data->feature == GDA_CONNECTION_FEATURE_XA_TRANSACTIONS)) {
+ GdaServerProviderXa *xaset;
+ xaset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
+ GDA_SERVER_PROVIDER_FUNCTIONS_XA);
+ if (!xaset->xa_start || !xaset->xa_end || !xaset->xa_prepare || !xaset->xa_commit ||
+ !xaset->xa_rollback || !xaset->xa_recover)
+ result = FALSE;
+ }
+ }
+ return result ? (gpointer) 0x01 : NULL;
}
/**
@@ -651,43 +1229,68 @@ gboolean
gda_server_provider_supports_feature (GdaServerProvider *provider, GdaConnection *cnc,
GdaConnectionFeature feature)
{
- gboolean retval = FALSE;
+ GdaWorker *worker;
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ g_return_val_if_fail (gda_connection_is_opened (cnc), NULL);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
+ }
+ else
+ worker = _gda_server_provider_create_worker (provider, FALSE);
- g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
- g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), FALSE);
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
- if (feature == GDA_CONNECTION_FEATURE_ASYNC_EXEC)
- return CLASS(provider)->handle_async ? TRUE : FALSE;;
+ WorkerSupportsFeatureData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.feature = feature;
+
+ gpointer retval = NULL;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_supports_feature, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
if (cnc)
- gda_lockable_lock ((GdaLockable*) cnc);
- if (CLASS (provider)->supports_feature)
- retval = CLASS (provider)->supports_feature (provider, cnc, feature);
-
- if (retval) {
- switch (feature) {
- case GDA_CONNECTION_FEATURE_TRANSACTIONS:
- if (!CLASS (provider)->begin_transaction ||
- !CLASS (provider)->commit_transaction ||
- !CLASS (provider)->rollback_transaction)
- retval = FALSE;
- break;
- case GDA_CONNECTION_FEATURE_SAVEPOINTS:
- if (!CLASS (provider)->add_savepoint ||
- !CLASS (provider)->rollback_savepoint)
- retval = FALSE;
- break;
- case GDA_CONNECTION_FEATURE_SAVEPOINTS_REMOVE:
- if (!CLASS (provider)->delete_savepoint)
- retval = FALSE;
- break;
- default:
- break;
- }
- }
- if (cnc)
- gda_lockable_unlock ((GdaLockable*) cnc);
- return retval;
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return retval ? TRUE : FALSE;
+}
+
+typedef struct {
+ GdaWorker *worker;
+ GdaServerProvider *provider;
+ GdaConnection *cnc;
+ GType for_g_type;
+ const gchar *for_dbms_type;
+} WorkerTypeData;
+
+/* code executed in GdaWorker's worker thread */
+static gpointer
+worker_get_data_handler (WorkerTypeData *data, G_GNUC_UNUSED GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ GdaDataHandler *dh = NULL;
+ if (fset->get_data_handler)
+ dh = fset->get_data_handler (data->provider, data->cnc, data->for_g_type,
data->for_dbms_type);
+ return (gpointer) dh;
}
/**
@@ -703,19 +1306,48 @@ gda_server_provider_supports_feature (GdaServerProvider *provider, GdaConnection
GdaDataHandler *
gda_server_provider_get_data_handler_g_type (GdaServerProvider *provider, GdaConnection *cnc, GType for_type)
{
- GdaDataHandler *retval = NULL;
+ GdaWorker *worker;
g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
- g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
-
- if (cnc)
- gda_lockable_lock ((GdaLockable*) cnc);
- if (CLASS (provider)->get_data_handler)
- retval = CLASS (provider)->get_data_handler (provider, cnc, for_type, NULL);
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ g_return_val_if_fail (gda_connection_is_opened (cnc), NULL);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
+ }
else
- retval = gda_server_provider_handler_use_default (provider, for_type);
+ worker = _gda_server_provider_create_worker (provider, FALSE);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerTypeData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.for_g_type = for_type;
+ data.for_dbms_type = NULL;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_get_data_handler, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+
if (cnc)
- gda_lockable_unlock ((GdaLockable*) cnc);
- return retval;
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return (GdaDataHandler*) retval;
}
/**
@@ -733,18 +1365,61 @@ gda_server_provider_get_data_handler_g_type (GdaServerProvider *provider, GdaCon
GdaDataHandler *
gda_server_provider_get_data_handler_dbms (GdaServerProvider *provider, GdaConnection *cnc, const gchar
*for_type)
{
- GdaDataHandler *retval = NULL;
+ GdaWorker *worker;
g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
- g_return_val_if_fail (for_type && *for_type, NULL);
- g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ g_return_val_if_fail (gda_connection_is_opened (cnc), NULL);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
+ }
+ else
+ worker = _gda_server_provider_create_worker (provider, FALSE);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerTypeData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.for_g_type = G_TYPE_INVALID;
+ data.for_dbms_type = for_type;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_get_data_handler, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
if (cnc)
- gda_lockable_lock ((GdaLockable*) cnc);
- if (CLASS (provider)->get_data_handler)
- retval = CLASS (provider)->get_data_handler (provider, cnc, G_TYPE_INVALID, for_type);
- if (cnc)
- gda_lockable_unlock ((GdaLockable*) cnc);
- return retval;
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return (GdaDataHandler*) retval;
+}
+
+/* code executed in GdaWorker's worker thread */
+static gpointer
+worker_get_default_dbms_type (WorkerTypeData *data, G_GNUC_UNUSED GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ const gchar *def = NULL;
+ if (fset->get_def_dbms_type)
+ def = fset->get_def_dbms_type (data->provider, data->cnc, data->for_g_type);
+ return (gpointer) def;
}
/**
@@ -764,19 +1439,48 @@ gda_server_provider_get_data_handler_dbms (GdaServerProvider *provider, GdaConne
const gchar *
gda_server_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConnection *cnc, GType type)
{
- const gchar *retval = NULL;
+ GdaWorker *worker;
g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
- g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
-
- if (CLASS (provider)->get_def_dbms_type) {
- if (cnc)
- gda_lockable_lock ((GdaLockable*) cnc);
- retval = (CLASS (provider)->get_def_dbms_type) (provider, cnc, type);
- if (cnc)
- gda_lockable_unlock ((GdaLockable*) cnc);
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ g_return_val_if_fail (gda_connection_is_opened (cnc), NULL);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
}
+ else
+ worker = _gda_server_provider_create_worker (provider, FALSE);
- return retval;
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerTypeData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.for_g_type = type;
+ data.for_dbms_type = NULL;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_get_default_dbms_type, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+
+ if (cnc)
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return (const gchar*) retval;
}
@@ -806,21 +1510,23 @@ gda_server_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConne
* Returns: (transfer full): a new #GValue, or %NULL
*/
GValue *
-gda_server_provider_string_to_value (GdaServerProvider *provider, GdaConnection *cnc, const gchar *string,
+gda_server_provider_string_to_value (GdaServerProvider *provider, GdaConnection *cnc, const gchar *string,
GType preferred_type, gchar **dbms_type)
{
GValue *retval = NULL;
GdaDataHandler *dh;
gsize i;
- g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
- g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
-
if (dbms_type)
*dbms_type = NULL;
- if (cnc)
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
gda_lockable_lock ((GdaLockable*) cnc);
+ }
+
if (preferred_type != G_TYPE_INVALID) {
dh = gda_server_provider_get_data_handler_g_type (provider, cnc, preferred_type);
if (dh) {
@@ -915,7 +1621,7 @@ gda_server_provider_value_to_sql_string (GdaServerProvider *provider,
GdaDataHandler *dh;
g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
- g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (!cnc || (gda_connection_get_provider (cnc) == provider), NULL);
g_return_val_if_fail (from != NULL, NULL);
if (cnc)
@@ -928,6 +1634,25 @@ gda_server_provider_value_to_sql_string (GdaServerProvider *provider,
return retval;
}
+typedef struct {
+ GdaWorker *worker;
+ GdaServerProvider *provider;
+ GdaConnection *cnc;
+ const gchar *str;
+} WorkerEscapeData;
+
+static gpointer
+worker_escape_string (WorkerEscapeData *data, G_GNUC_UNUSED GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ if (fset->escape_string)
+ return fset->escape_string (data->provider, data->cnc, data->str);
+ else
+ return gda_default_escape_string (data->str);
+}
+
/**
* gda_server_provider_escape_string:
* @provider: a server provider.
@@ -942,25 +1667,60 @@ gda_server_provider_value_to_sql_string (GdaServerProvider *provider,
gchar *
gda_server_provider_escape_string (GdaServerProvider *provider, GdaConnection *cnc, const gchar *str)
{
+ GdaWorker *worker;
g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
- g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
-
- if (CLASS (provider)->escape_string) {
- gchar *retval;
- if (! CLASS (provider)->unescape_string)
- g_warning (_("GdaServerProvider object implements the %s virtual method but "
- "does not implement the %s one, please report this bug to "
- "http://bugzilla.gnome.org/ for the \"libgda\" product."),
- "escape_string()", "unescape_string()");
- if (cnc)
- gda_lockable_lock ((GdaLockable*) cnc);
- retval = (CLASS (provider)->escape_string) (provider, cnc, str);
- if (cnc)
- gda_lockable_unlock ((GdaLockable*) cnc);
- return retval;
+ g_return_val_if_fail (str, NULL);
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ g_return_val_if_fail (gda_connection_is_opened (cnc), NULL);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
}
- else
- return gda_default_escape_string (str);
+ else
+ worker = _gda_server_provider_create_worker (provider, FALSE);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerEscapeData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.str = str;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_escape_string, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+
+ if (cnc)
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return (gchar*) retval;
+}
+
+static gpointer
+worker_unescape_string (WorkerEscapeData *data, G_GNUC_UNUSED GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ if (fset->unescape_string)
+ return fset->unescape_string (data->provider, data->cnc, data->str);
+ else
+ return gda_default_unescape_string (data->str);
}
/**
@@ -976,27 +1736,67 @@ gda_server_provider_escape_string (GdaServerProvider *provider, GdaConnection *c
gchar *
gda_server_provider_unescape_string (GdaServerProvider *provider, GdaConnection *cnc, const gchar *str)
{
+ GdaWorker *worker;
g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
- g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
-
- if (CLASS (provider)->unescape_string) {
- gchar *retval;
- if (! CLASS (provider)->escape_string)
- g_warning (_("GdaServerProvider object implements the %s virtual method but "
- "does not implement the %s one, please report this bug to "
- "http://bugzilla.gnome.org/ for the \"libgda\" product."),
- "unescape_string()", "escape_string()");
- if (cnc)
- gda_lockable_lock ((GdaLockable*) cnc);
- retval = (CLASS (provider)->unescape_string)(provider, cnc, str);
- if (cnc)
- gda_lockable_unlock ((GdaLockable*) cnc);
- return retval;
+ g_return_val_if_fail (str, NULL);
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ g_return_val_if_fail (gda_connection_is_opened (cnc), NULL);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
}
else
- return gda_default_unescape_string (str);
+ worker = _gda_server_provider_create_worker (provider, FALSE);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerEscapeData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.str = str;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_unescape_string, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+
+ if (cnc)
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return (gchar*) retval;
}
+typedef struct {
+ GdaWorker *worker;
+ GdaServerProvider *provider;
+ GdaConnection *cnc;
+} WorkerParserData;
+
+static gpointer
+worker_create_parser (WorkerParserData *data, G_GNUC_UNUSED GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ if (fset->create_parser)
+ return fset->create_parser (data->provider, data->cnc);
+ else
+ return NULL;
+}
/**
* gda_server_provider_create_parser:
@@ -1014,13 +1814,1927 @@ gda_server_provider_unescape_string (GdaServerProvider *provider, GdaConnection
GdaSqlParser *
gda_server_provider_create_parser (GdaServerProvider *provider, GdaConnection *cnc)
{
- GdaSqlParser *parser = NULL;
+ GdaWorker *worker;
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ g_return_val_if_fail (gda_connection_is_opened (cnc), NULL);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
+ }
+ else
+ worker = _gda_server_provider_create_worker (provider, FALSE);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerParserData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_create_parser, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+
+ if (cnc)
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return (GdaSqlParser*) retval;
+}
+
+/*
+ * Possible job types
+ */
+typedef enum {
+ JOB_CREATE_CONNECTION,
+ JOB_OPEN_CONNECTION,
+ JOB_CLOSE_CONNECTION,
+ JOB_PREPARE_STATEMENT,
+ JOB_EXECUTE_STATEMENT,
+ JOB_IDENTIFIER_QUOTE,
+ JOB_META,
+ JOB_BEGIN_TRANSACTION,
+ JOB_COMMIT_TRANSACTION,
+ JOB_ROLLBACK_TRANSACTION,
+ JOB_ADD_SAVEPOINT,
+ JOB_ROLLBACK_SAVEPOINT,
+ JOB_DELETE_SAVEPOINT,
+ JOB_XA_START,
+ JOB_XA_END,
+ JOB_XA_PREPARE,
+ JOB_XA_COMMIT,
+ JOB_XA_ROLLBACK,
+ JOB_XA_RECOVER,
+ JOB_STMT_TO_SQL,
+} WorkerDataType;
+
+/*
+ * Holds information associated with any kind of job
+ */
+struct _WorkerData {
+ guint job_id;
+ WorkerDataType job_type;
+
+ gpointer job_data;
+ GDestroyNotify job_data_destroy_func;
+};
+
+/*
+ * generic function to free the job's associated data
+ */
+static void
+worker_data_free (WorkerData *wd)
+{
+ if (wd->job_data) {
+ g_assert (wd->job_data_destroy_func);
+ wd->job_data_destroy_func (wd->job_data);
+ }
+ g_slice_free (WorkerData, wd);
+}
+
+static void server_provider_job_done_callback (GdaWorker *worker, guint job_id, gpointer result,
+ GError *error, GdaServerProvider *provider);
+
+/***********************************************************************************************************/
+
+/*
+ * JOB_CREATE_CONNECTION
+ */
+
+typedef struct {
+ GdaWorker *worker;
+ GdaServerProvider *provider;
+} WorkerCreateConnectionData;
+
+static gpointer
+worker_create_connection (WorkerCreateConnectionData *data, GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ if (fset->create_connection)
+ return fset->create_connection (data->provider);
+ else
+ return NULL;
+}
+
+GdaConnection *
+_gda_server_provider_create_connection (GdaServerProvider *provider, const gchar *dsn_string, const gchar
*cnc_string,
+ const gchar *auth_string, GdaConnectionOptions options)
+{
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
+ g_return_val_if_fail (!dsn_string || !cnc_string, FALSE);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (NULL);
+
+ GdaWorker *worker;
+ worker = _gda_server_provider_create_worker (provider, FALSE);
+
+ WorkerCreateConnectionData data;
+ data.provider = provider;
+ data.worker = worker;
+
+ gpointer cnc;
+ gda_worker_do_job (worker, context, 0, &cnc, NULL,
+ (GdaWorkerFunc) worker_create_connection, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+ gda_worker_unref (worker);
+
+ if (cnc)
+ g_object_set (G_OBJECT (cnc),
+ "provider", provider,
+ "auth-string", auth_string,
+ "options", options, NULL);
+ else
+ cnc = g_object_new (GDA_TYPE_CONNECTION,
+ "provider", provider,
+ "auth-string", auth_string,
+ "options", options, NULL);
+
+ if (dsn_string)
+ g_object_set (G_OBJECT (cnc),
+ "dsn", dsn_string, NULL);
+ else if (cnc_string)
+ g_object_set (G_OBJECT (cnc),
+ "cnc-string", cnc_string, NULL);
+ return (GdaConnection*) cnc;
+}
+
+/***********************************************************************************************************/
+
+/*
+ * JOB_OPEN_CONNECTION
+ * WorkerOpenConnectionData
+ *
+ */
+typedef struct {
+ GdaWorker *worker;
+ GdaServerProvider *provider;
+ GdaConnection *cnc;
+ GdaQuarkList *params;
+ GdaQuarkList *auth;
+ GdaConnectionOpenFunc callback;
+ gpointer callback_data; /* FIXME: add data destroy func */
+} WorkerOpenConnectionData;
+
+static void
+WorkerOpenConnectionData_free (WorkerOpenConnectionData *data)
+{
+ gda_worker_unref (data->worker);
+ g_object_unref (data->cnc);
+ gda_quark_list_free (data->params);
+ gda_quark_list_free (data->auth);
+ g_slice_free (WorkerOpenConnectionData, data);
+}
+
+static gpointer
+worker_open_connection (WorkerOpenConnectionData *data, GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ guint delay;
+ delay = _gda_connection_get_exec_slowdown (data->cnc);
+ if (delay > 0) {
+ g_print ("Delaying execution for %u ms\n", delay);
+ g_usleep (delay);
+ }
+
+ gboolean result;
+ result = fset->open_connection (data->provider, data->cnc, data->params, data->auth);
+ if (result) {
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (data->cnc, NULL);
+ if (!cdata) {
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ result = FALSE;
+ }
+ else
+ cdata->worker = gda_worker_ref (data->worker);
+ if (fset->prepare_connection) {
+ result = fset->prepare_connection (data->provider, data->cnc, data->params,
data->auth);
+ if (!result) {
+ fset->close_connection (data->provider, data->cnc);
+ gda_connection_internal_set_provider_data (data->cnc, NULL, NULL);
+ if (cdata->worker)
+ gda_worker_unref (cdata->worker);
+ if (cdata->provider_data_destroy_func)
+ cdata->provider_data_destroy_func (cdata);
+ }
+ }
+ }
+ if (data->params)
+ gda_quark_list_protect_values (data->params);
+ if (data->auth)
+ gda_quark_list_protect_values (data->params);
+
+ /* error computing */
+ if (!result) {
+ const GList *events, *l;
+ events = gda_connection_get_events (data->cnc);
+
+ for (l = g_list_last ((GList*) events); l; l = l->prev) {
+ GdaConnectionEvent *event;
+
+ event = GDA_CONNECTION_EVENT (l->data);
+ if (gda_connection_event_get_event_type (event) == GDA_CONNECTION_EVENT_ERROR) {
+ if (error && !(*error))
+ g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_OPEN_ERROR,
+ "%s", gda_connection_event_get_description (event));
+ }
+ }
+ }
+
+ return result ? (gpointer) 0x01 : NULL;
+}
+
+/*
+ * Steals @worker
+ */
+static gboolean
+stage2_open_connection (GdaWorker *worker, GdaConnection *cnc, gpointer result)
+{
+ if (result) {
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ result = NULL;
+ }
+ else {
+#ifdef GDA_DEBUG_signal
+ g_print (">> 'CONN_OPENED' from %s\n", __FUNCTION__);
+#endif
+ g_signal_emit_by_name (G_OBJECT (cnc), "conn-opened");
+#ifdef GDA_DEBUG_signal
+ g_print ("<< 'CONN_OPENED' from %s\n", __FUNCTION__);
+#endif
+ }
+ }
+
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return result ? TRUE : FALSE;
+}
+
+/*
+ * _gda_server_provider_open_connection:
+ * @provider: a #GdaServerProvider
+ * @cnc: a #GdaConnection
+ * @params: (transfer full): parameters specifying the connection's attributes
+ * @auth: (allow-none) (transfer full): authentification parameters, or %NULL
+ * @cb_func: (allow-none): a #GdaConnectionOpenFunc function, or %NULL
+ * @data: (allow-none): data to pass to @cb_func, or %NULL
+ * @out_job_id: (allow-none): a place to store the job ID, or %NULL
+ * @error: (allow-none): a place to store error, or %NULL
+ *
+ * Call the open_connection() in the worker thread.
+ *
+ * 2 modes:
+ * - sync: where @cb_func and @out_job_id are _both_ NULL, and @data is ignored
+ * Returns: %FALSE if an error occurred, and %TRUE if connection is then opened
+ *
+ * - async: where @cb_func and @out_job_id are _both_ NOT NULL, and @error is ignored
+ * Returns: %FALSE if an error occurred submitting the job, and %TRUE if job has been submitted. @error
may contain the
+ * error when submitting the job
+ *
+ */
+gboolean
+_gda_server_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaQuarkList *params, GdaQuarkList *auth,
+ GdaConnectionOpenFunc cb_func, gpointer data, guint *out_job_id,
+ GError **error)
+{
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
+ g_return_val_if_fail (cnc && (gda_connection_get_provider (cnc) == provider), FALSE);
+ g_return_val_if_fail (! gda_connection_is_opened (cnc), TRUE);
+ g_return_val_if_fail (params, FALSE);
+
+ if (out_job_id)
+ *out_job_id = 0;
+ g_return_val_if_fail ((cb_func && out_job_id) || (!cb_func && !out_job_id), FALSE);
+
+ GMainContext *context;
+ context = gda_connection_get_main_context (cnc);
+ if (cb_func && !context) {
+ g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_NO_MAIN_CONTEXT_ERROR,
+ "%s", _("You need to define a GMainContext using
gda_connection_set_main_context()"));
+ return FALSE;
+ }
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaWorker *worker;
+ worker = _gda_server_provider_create_worker (provider, TRUE);
+
+ /* define callback if not yet done */
+ if (cb_func) {
+ if (!gda_worker_set_callback (worker, context,
+ (GdaWorkerCallback) server_provider_job_done_callback,
provider, error)) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ gda_worker_unref (worker);
+ return FALSE;
+ }
+
+ if (!provider->priv->jobs_hash)
+ provider->priv->jobs_hash = g_hash_table_new_full (g_int_hash, g_int_equal,
+ NULL, (GDestroyNotify)
worker_data_free);
+ }
+
+ /* preparing data required to submit job to GdaWorker */
+ WorkerOpenConnectionData *jdata;
+ jdata = g_slice_new (WorkerOpenConnectionData);
+ jdata->worker = gda_worker_ref (worker);
+ jdata->provider = provider;
+ jdata->cnc = g_object_ref (cnc);
+ jdata->params = params;
+ jdata->auth = auth;
+ jdata->callback = cb_func;
+ jdata->callback_data = data;
+
+ if (cb_func) {
+ guint job_id;
+ job_id = gda_worker_submit_job (worker, context,
+ (GdaWorkerFunc) worker_open_connection,
+ jdata, NULL, NULL, error);
+ if (job_id == 0) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ WorkerOpenConnectionData_free (jdata);
+ return FALSE; /* error */
+ }
+ else {
+ WorkerData *wd;
+ wd = g_slice_new0 (WorkerData);
+ wd->job_id = job_id;
+ wd->job_type = JOB_OPEN_CONNECTION;
+ wd->job_data = (gpointer) jdata;
+ wd->job_data_destroy_func = (GDestroyNotify) WorkerOpenConnectionData_free;
+ g_hash_table_insert (provider->priv->jobs_hash, & wd->job_id, wd);
+ *out_job_id = job_id;
+ return TRUE; /* no error, LOCK on CNC is kept */
+ }
+ }
+ else {
+ gpointer result;
+ if (context)
+ g_main_context_ref (context);
+ else
+ context = g_main_context_new ();
+ gda_worker_do_job (worker, context, 0, &result, NULL,
+ (GdaWorkerFunc) worker_open_connection, jdata, (GDestroyNotify)
WorkerOpenConnectionData_free,
+ NULL, error);
+ g_main_context_unref (context);
+
+ gboolean retval;
+ retval = stage2_open_connection (worker, cnc, result); /* steals @worker and unlocks @cnc */
+ return retval;
+ }
+}
+
+/***********************************************************************************************************/
+
+/*
+ * JOB_CLOSE_CONNECTION
+ * WorkerCloseConnectionData
+ *
+ */
+typedef struct {
+ GdaWorker *worker;
+ GdaServerProvider *provider;
+ GdaConnection *cnc;
+} WorkerCloseConnectionData;
+
+static void
+WorkerCloseConnectionData_free (WorkerCloseConnectionData *data)
+{
+ //g_print ("%s() th %p %s\n", __FUNCTION__, g_thread_self(), gda_worker_thread_is_worker
(data->worker) ? "Thread Worker" : "NOT thread worker");
+ gda_worker_unref (data->worker);
+ g_object_unref (data->cnc);
+ g_slice_free (WorkerCloseConnectionData, data);
+}
+
+static gpointer
+worker_close_connection (WorkerCloseConnectionData *data, GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ gboolean result;
+ result = fset->close_connection (data->provider, data->cnc);
+
+ guint delay;
+ delay = _gda_connection_get_exec_slowdown (data->cnc);
+ if (delay > 0) {
+ g_print ("Delaying execution for %u ms\n", delay / 1000);
+ g_usleep (delay);
+ }
+
+ /* error computing */
+ if (!result) {
+ const GList *events, *l;
+ events = gda_connection_get_events (data->cnc);
+
+ for (l = g_list_last ((GList*) events); l; l = l->prev) {
+ GdaConnectionEvent *event;
+
+ event = GDA_CONNECTION_EVENT (l->data);
+ if (gda_connection_event_get_event_type (event) == GDA_CONNECTION_EVENT_ERROR) {
+ if (error && !(*error))
+ g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_OPEN_ERROR,
+ "%s", gda_connection_event_get_description (event));
+ }
+ }
+ }
+
+ return result ? (gpointer) 0x01 : NULL;
+}
+
+static gboolean
+stage2_close_connection (GdaConnection *cnc, gpointer result)
+{
+ if (result) {
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (cdata) {
+ gda_connection_internal_set_provider_data (cnc, NULL, NULL);
+ if (cdata->worker)
+ gda_worker_unref (cdata->worker);
+ if (cdata->provider_data_destroy_func)
+ cdata->provider_data_destroy_func (cdata);
+ }
+
+ g_signal_emit_by_name (G_OBJECT (cnc), "conn-closed");
+ }
+
+ return result ? TRUE : FALSE;
+}
+
+/*
+ * _gda_server_provider_close_connection:
+ * @provider: a #GdaServerProvider
+ * @cnc: a #GdaConnection
+ * @error: (allow-none): a place to store error, or %NULL
+ *
+ * Call the close_connection() in the worker thread.
+ */
+gboolean
+_gda_server_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc, GError **error)
+{
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
+ g_return_val_if_fail (cnc && (gda_connection_get_provider (cnc) == provider), FALSE);
+ g_return_val_if_fail (gda_connection_is_opened (cnc), TRUE);
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerCloseConnectionData *jdata;
+ jdata = g_slice_new (WorkerCloseConnectionData);
+ jdata->worker = gda_worker_ref (cdata->worker);
+ jdata->provider = provider;
+ jdata->cnc = g_object_ref (cnc);
+
+ gpointer result;
+ gda_worker_do_job (cdata->worker, context, 0, &result, NULL,
+ (GdaWorkerFunc) worker_close_connection, jdata, (GDestroyNotify)
WorkerCloseConnectionData_free,
+ NULL, error);
+ g_main_context_unref (context);
+ return stage2_close_connection (cnc, result);
+}
+
+/***********************************************************************************************************/
+
+/*
+ * JOB_PREPARE_STATEMENT
+ * WorkerPrepareStatementData
+ *
+ */
+typedef struct {
+ GdaWorker *worker;
+ GdaServerProvider *provider;
+ GdaConnection *cnc;
+ GdaStatement *stmt;
+} WorkerPrepareStatementData;
+
+/* code executed in GdaWorker's worker thread */
+static gpointer
+worker_statement_prepare (WorkerPrepareStatementData *data, GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ gboolean result;
+ result = fset->statement_prepare (data->provider, data->cnc, data->stmt, error);
+ return result ? (gpointer) 0x01 : NULL;
+}
+
+/*
+ * _gda_server_provider_statement_prepare:
+ * @provider: a #GdaServerProvider
+ * @cnc: (allow-none): a #GdaConnection
+ * @stmt: a #GdaStatement
+ * @error: (allow-none): a place to store error, or %NULL
+ *
+ * Call the prepare_statement() in the worker thread
+ */
+gboolean
+_gda_server_provider_statement_prepare (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GError **error)
+{
+ GdaWorker *worker;
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
+ g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
+
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ g_return_val_if_fail (gda_connection_is_opened (cnc), NULL);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerPrepareStatementData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.stmt = stmt;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_statement_prepare, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return retval ? TRUE : FALSE;
+}
+
+/***********************************************************************************************************/
+
+/*
+ * JOB_EXECUTE_STATEMENT
+ * WorkerExecuteStatementData
+ *
+ */
+typedef struct {
+ GdaWorker *worker;
+ GdaServerProvider *provider;
+ GdaConnection *cnc;
+ GdaStatement *stmt;
+ GdaSet *params;
+ GdaStatementModelUsage model_usage;
+ GType *col_types;
+ GdaSet **last_inserted_row;
+} WorkerExecuteStatementData;
+
+
+static gpointer
+worker_statement_execute (WorkerExecuteStatementData *data, GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ guint delay;
+ delay = _gda_connection_get_exec_slowdown (data->cnc);
+ if (delay > 0) {
+ g_print ("Delaying execution for %u ms\n", delay / 1000);
+ g_usleep (delay);
+ }
+
+ GObject *result;
+ result = fset->statement_execute (data->provider, data->cnc, data->stmt, data->params,
data->model_usage, data->col_types, data->last_inserted_row, error);
+
+ return (gpointer) result;
+}
+
+/*
+ * _gda_server_provider_statement_execute:
+ * @provider: a #GdaServerProvider
+ * @cnc: a #GdaConnection
+ * @stmt: a #GdaStatement
+ * @params: (allow-none): parameters to bind variables in @stmt, or %NULL
+ * @model_usage: the requested usage of the returned #GdaDataModel if @stmt is a SELECT statement
+ * @col_types: (allow-none): requested column types of the returned #GdaDataModel if @stmt is a SELECT
statement, or %NULL
+ * @last_inserted_row: (allow-none): a place to store the last inserted row information, or %NULL
+ * @error: (allow-none): a place to store error, or %NULL
+ *
+ * Call the prepare_statement() in the worker thread
+ */
+GObject *
+_gda_server_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params,
+ GdaStatementModelUsage model_usage,
+ GType *col_types, GdaSet **last_inserted_row, GError **error)
+{
+ if (last_inserted_row)
+ *last_inserted_row = NULL;
+
+ GdaWorker *worker;
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
+ g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
+
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ g_return_val_if_fail (gda_connection_is_opened (cnc), NULL);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerExecuteStatementData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.stmt = stmt;
+ data.params = params;
+ data.model_usage = model_usage;
+ data.col_types = col_types;
+ data.last_inserted_row = last_inserted_row;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_statement_execute, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return retval;
+}
+
+/***********************************************************************************************************/
+
+/*
+ * JOB_STMT_TO_SQL
+ * WorkerStmtToSQLData
+ *
+ */
+typedef struct {
+ GdaWorker *worker;
+ GdaServerProvider *provider;
+ GdaConnection *cnc;
+ GdaStatement *stmt;
+ GdaSet *params;
+ GdaStatementSqlFlag flags;
+ GSList **params_used;
+} WorkerStmtToSQLData;
+
+static gpointer
+worker_stmt_to_sql (WorkerStmtToSQLData *data, GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ if (fset->statement_to_sql)
+ return fset->statement_to_sql (data->provider, data->cnc, data->stmt, data->params,
data->flags,
+ data->params_used, error);
+ else
+ return NULL;
+}
+
+gchar *
+_gda_server_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GdaStatementSqlFlag flags,
+ GSList **params_used, GError **error)
+{
+ GdaWorker *worker;
+ if (params_used)
+ *params_used = NULL;
+
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
+ g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
+ g_return_val_if_fail (!params || GDA_IS_SET (params), NULL);
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ g_return_val_if_fail (gda_connection_is_opened (cnc), NULL);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
+ }
+ else
+ worker = _gda_server_provider_create_worker (provider, FALSE);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerStmtToSQLData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.stmt = stmt;
+ data.params = params;
+ data.flags = flags;
+ data.params_used = params_used;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_stmt_to_sql, (gpointer) &data, NULL, NULL, error);
+ g_main_context_unref (context);
+
+ if (cnc)
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return (gchar *) retval;
+}
+
+/***********************************************************************************************************/
+
+/*
+ * JOB_IDENTIFIER_QUOTE
+ * WorkerIdentifierQuoteData
+ *
+ */
+typedef struct {
+ GdaWorker *worker;
+ GdaServerProvider *provider;
+ GdaConnection *cnc;
+ const gchar *id;
+ gboolean for_meta_store;
+ gboolean force_quotes;
+} WorkerIdentifierQuoteData;
+
+static gpointer
+worker_identifier_quote (WorkerIdentifierQuoteData *data, GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+ if (fset->identifier_quote)
+ return fset->identifier_quote (data->provider, data->cnc, data->id, data->for_meta_store,
data->force_quotes);
+ else
+ return NULL;
+}
+
+gchar *
+_gda_server_provider_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
+ const gchar *id, gboolean for_meta_store, gboolean force_quotes)
+{
+ GdaWorker *worker;
g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
- g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ g_return_val_if_fail (gda_connection_is_opened (cnc), NULL);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
+ }
+ else
+ worker = _gda_server_provider_create_worker (provider, FALSE);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerIdentifierQuoteData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.id = id;
+ data.for_meta_store = for_meta_store;
+ data.force_quotes = force_quotes;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_identifier_quote, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
- if (CLASS (provider)->create_parser)
- parser = (CLASS (provider)->create_parser) (provider, cnc);
- return parser;
+ if (cnc)
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return (gchar *) retval;
}
+/***********************************************************************************************************/
+
+/*
+ * JOB_META
+ * WorkerMetaData
+ *
+ */
+typedef struct {
+ GdaWorker *worker;
+ GdaServerProvider *provider;
+ GdaConnection *cnc;
+ GdaMetaStore *meta;
+ GdaMetaContext *ctx;
+ GdaServerProviderMetaType type;
+ guint nargs;
+ const GValue *values[4]; /* 4 at most */
+} WorkerMetaData;
+
+typedef gboolean (*Meta0Func) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *,
GError **);
+typedef gboolean (*Meta1Func) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *,
GError **, const GValue *);
+typedef gboolean (*Meta2Func) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *,
GError **, const GValue *, const GValue *);
+typedef gboolean (*Meta3Func) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *,
GError **, const GValue *, const GValue *, const GValue *);
+typedef gboolean (*Meta4Func) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *,
GError **, const GValue *, const GValue *, const GValue *, const GValue *);
+
+
+static gpointer
+worker_meta (WorkerMetaData *data, GError **error)
+{
+ Meta0Func *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_META);
+
+ gboolean retval;
+ switch (data->nargs) {
+ case 0: {/* function with no argument */
+ Meta0Func func;
+ func = (Meta0Func) fset [data->type];
+ if (func)
+ retval = func (data->provider, data->cnc, data->meta, data->ctx, error);
+ else {
+ retval = FALSE;
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+ "%s", _("Not supported"));
+ }
+ break;
+ }
+ case 1: {/* function with 1 argument */
+ Meta1Func func;
+ func = (Meta1Func) fset [data->type];
+ if (func)
+ retval = func (data->provider, data->cnc, data->meta, data->ctx, error, data->values
[0]);
+ else {
+ retval = FALSE;
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+ "%s", _("Not supported"));
+ }
+ break;
+ }
+ case 2: {/* function with 2 arguments */
+ Meta2Func func;
+ func = (Meta2Func) fset [data->type];
+ if (func)
+ retval = func (data->provider, data->cnc, data->meta, data->ctx, error, data->values
[0], data->values [1]);
+ else {
+ retval = FALSE;
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+ "%s", _("Not supported"));
+ }
+ break;
+ }
+ case 3: {/* function with 3 arguments */
+ Meta3Func func;
+ func = (Meta3Func) fset [data->type];
+ if (func)
+ retval = func (data->provider, data->cnc, data->meta, data->ctx, error, data->values
[0], data->values [1], data->values [2]);
+ else {
+ retval = FALSE;
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+ "%s", _("Not supported"));
+ }
+ break;
+ }
+ case 4: {/* function with 4 arguments */
+ Meta4Func func;
+ func = (Meta4Func) fset [data->type];
+ if (func)
+ retval = func (data->provider, data->cnc, data->meta, data->ctx, error, data->values
[0], data->values [1], data->values [2], data->values [3]);
+ else {
+ retval = FALSE;
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+ "%s", _("Not supported"));
+ }
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ }
+
+ return retval ? (gpointer) 0x01 : NULL;
+}
+
+static guint
+get_meta_nb_values_args (GdaServerProviderMetaType type)
+{
+ switch (type) {
+ case GDA_SERVER_META__INFO:
+ case GDA_SERVER_META__BTYPES:
+ case GDA_SERVER_META__UDT:
+ case GDA_SERVER_META__UDT_COLS:
+ case GDA_SERVER_META__ENUMS:
+ case GDA_SERVER_META__DOMAINS:
+ case GDA_SERVER_META__CONSTRAINTS_DOM:
+ case GDA_SERVER_META__EL_TYPES:
+ case GDA_SERVER_META__COLLATIONS:
+ case GDA_SERVER_META__CHARACTER_SETS:
+ case GDA_SERVER_META__SCHEMATA:
+ case GDA_SERVER_META__TABLES_VIEWS:
+ case GDA_SERVER_META__COLUMNS:
+ case GDA_SERVER_META__VIEW_COLS:
+ case GDA_SERVER_META__CONSTRAINTS_TAB:
+ case GDA_SERVER_META__CONSTRAINTS_REF:
+ case GDA_SERVER_META__KEY_COLUMNS:
+ case GDA_SERVER_META__CHECK_COLUMNS:
+ case GDA_SERVER_META__TRIGGERS:
+ case GDA_SERVER_META__ROUTINES:
+ case GDA_SERVER_META__ROUTINE_COL:
+ case GDA_SERVER_META__ROUTINE_PAR:
+ case GDA_SERVER_META__INDEXES_TAB:
+ case GDA_SERVER_META__INDEX_COLS:
+ return 0;
+
+ case GDA_SERVER_META_EL_TYPES:
+ return 1;
+
+ case GDA_SERVER_META_UDT:
+ case GDA_SERVER_META_DOMAINS:
+ case GDA_SERVER_META_SCHEMATA:
+ return 2;
+
+ case GDA_SERVER_META_UDT_COLS:
+ case GDA_SERVER_META_ENUMS:
+ case GDA_SERVER_META_CONSTRAINTS_DOM:
+ case GDA_SERVER_META_COLLATIONS:
+ case GDA_SERVER_META_CHARACTER_SETS:
+ case GDA_SERVER_META_TABLES_VIEWS:
+ case GDA_SERVER_META_COLUMNS:
+ case GDA_SERVER_META_VIEW_COLS:
+ case GDA_SERVER_META_TRIGGERS:
+ case GDA_SERVER_META_ROUTINES:
+ case GDA_SERVER_META_ROUTINE_COL:
+ case GDA_SERVER_META_ROUTINE_PAR:
+ return 3;
+
+ case GDA_SERVER_META_CONSTRAINTS_TAB:
+ case GDA_SERVER_META_CONSTRAINTS_REF:
+ case GDA_SERVER_META_KEY_COLUMNS:
+ case GDA_SERVER_META_CHECK_COLUMNS:
+ case GDA_SERVER_META_INDEXES_TAB:
+ case GDA_SERVER_META_INDEX_COLS:
+ return 4;
+
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+gboolean
+_gda_server_provider_meta_0arg (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaMetaStore *meta, GdaMetaContext *ctx,
+ GdaServerProviderMetaType type, GError **error)
+{
+ GdaWorker *worker;
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
+
+ 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_connection_is_opened (cnc), FALSE);
+
+ /* check that function at index @type has 0 value argument */
+ if (get_meta_nb_values_args (type) != 0) {
+ g_warning ("Internal error: function %s() is only for meta data with no value argument",
__FUNCTION__);
+ return FALSE;
+ }
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+
+ worker = gda_worker_ref (cdata->worker);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerMetaData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.meta = meta;
+ data.ctx = ctx;
+ data.type = type;
+ data.nargs = 0;
+ data.values[0] = NULL;
+ data.values[1] = NULL;
+ data.values[2] = NULL;
+ data.values[3] = NULL;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_meta, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+
+ if (cnc)
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return retval ? TRUE : FALSE;
+}
+
+gboolean
+_gda_server_provider_meta_1arg (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaMetaStore *meta, GdaMetaContext *ctx,
+ GdaServerProviderMetaType type, const GValue *value0, GError **error)
+{
+ GdaWorker *worker;
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
+
+ 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_connection_is_opened (cnc), FALSE);
+
+ /* check that function at index @type has 1 value argument */
+ if (get_meta_nb_values_args (type) != 1) {
+ g_warning ("Internal error: function %s() is only for meta data with 1 value argument",
__FUNCTION__);
+ return FALSE;
+ }
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+
+ worker = gda_worker_ref (cdata->worker);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerMetaData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.meta = meta;
+ data.ctx = ctx;
+ data.type = type;
+ data.nargs = 1;
+ data.values[0] = value0;
+ data.values[1] = NULL;
+ data.values[2] = NULL;
+ data.values[3] = NULL;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_meta, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+
+ if (cnc)
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return retval ? TRUE : FALSE;
+}
+
+gboolean
+_gda_server_provider_meta_2arg (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaMetaStore *meta, GdaMetaContext *ctx,
+ GdaServerProviderMetaType type, const GValue *value0, const GValue *value1,
GError **error)
+{
+ GdaWorker *worker;
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
+
+ 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_connection_is_opened (cnc), FALSE);
+
+ /* check that function at index @type has 2 values arguments */
+ if (get_meta_nb_values_args (type) != 2) {
+ g_warning ("Internal error: function %s() is only for meta data with 2 values arguments",
__FUNCTION__);
+ return FALSE;
+ }
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+
+ worker = gda_worker_ref (cdata->worker);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerMetaData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.meta = meta;
+ data.ctx = ctx;
+ data.type = type;
+ data.nargs = 2;
+ data.values[0] = value0;
+ data.values[1] = value1;
+ data.values[2] = NULL;
+ data.values[3] = NULL;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_meta, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+
+ if (cnc)
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return retval ? TRUE : FALSE;
+}
+
+gboolean
+_gda_server_provider_meta_3arg (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaMetaStore *meta, GdaMetaContext *ctx,
+ GdaServerProviderMetaType type, const GValue *value0, const GValue *value1,
+ const GValue *value2, GError **error)
+{
+ GdaWorker *worker;
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
+
+ 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_connection_is_opened (cnc), FALSE);
+
+ /* check that function at index @type has 3 values arguments */
+ if (get_meta_nb_values_args (type) != 3) {
+ g_warning ("Internal error: function %s() is only for meta data with 3 values arguments",
__FUNCTION__);
+ return FALSE;
+ }
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+
+ worker = gda_worker_ref (cdata->worker);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerMetaData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.meta = meta;
+ data.ctx = ctx;
+ data.type = type;
+ data.nargs = 3;
+ data.values[0] = value0;
+ data.values[1] = value1;
+ data.values[2] = value2;
+ data.values[3] = NULL;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_meta, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+
+ if (cnc)
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return retval ? TRUE : FALSE;
+}
+
+gboolean
+_gda_server_provider_meta_4arg (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaMetaStore *meta, GdaMetaContext *ctx,
+ GdaServerProviderMetaType type, const GValue *value0, const GValue *value1,
+ const GValue *value2, const GValue *value3, GError **error)
+{
+ GdaWorker *worker;
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
+
+ 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_connection_is_opened (cnc), FALSE);
+
+ /* check that function at index @type has 4 values arguments */
+ if (get_meta_nb_values_args (type) != 4) {
+ g_warning ("Internal error: function %s() is only for meta data with 4 values arguments",
__FUNCTION__);
+ return FALSE;
+ }
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+
+ worker = gda_worker_ref (cdata->worker);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerMetaData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.meta = meta;
+ data.ctx = ctx;
+ data.type = type;
+ data.nargs = 4;
+ data.values[0] = value0;
+ data.values[1] = value1;
+ data.values[2] = value2;
+ data.values[3] = value3;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_meta, (gpointer) &data, NULL, NULL, NULL);
+ g_main_context_unref (context);
+
+ if (cnc)
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return retval ? TRUE : FALSE;
+}
+
+/***********************************************************************************************************/
+
+/*
+ * JOB_BEGIN_TRANSACTION
+ * JOB_COMMIT_TRANSACTION
+ * JOB_ROLLBACK_TRANSACTION
+ * WorkerTransactionData
+ */
+typedef struct {
+ GdaWorker *worker;
+ GdaServerProvider *provider;
+ GdaConnection *cnc;
+ const gchar *name;
+ GdaTransactionIsolation level;
+} WorkerTransactionData;
+
+static gpointer
+worker_begin_transaction (WorkerTransactionData *data, GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ guint delay;
+ delay = _gda_connection_get_exec_slowdown (data->cnc);
+ if (delay > 0) {
+ g_print ("Delaying execution for %u ms\n", delay / 1000);
+ g_usleep (delay);
+ }
+
+ gboolean retval;
+ if (fset->begin_transaction)
+ retval = fset->begin_transaction (data->provider, data->cnc, data->name, data->level, error);
+ else {
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+ "%s", _("Database provider does not support transactions"));
+ retval = FALSE;
+ }
+ return retval ? (gpointer) 0x01: NULL;
+}
+
+gboolean
+_gda_server_provider_begin_transaction (GdaServerProvider *provider, GdaConnection *cnc,
+ const gchar *name, GdaTransactionIsolation level, GError **error)
+{
+ GdaWorker *worker;
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
+ 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_connection_is_opened (cnc), FALSE);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, FALSE);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerTransactionData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.name = name;
+ data.level = level;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_begin_transaction, (gpointer) &data, NULL, NULL, error);
+ g_main_context_unref (context);
+
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return retval ? TRUE : FALSE;
+}
+
+static gpointer
+worker_commit_transaction (WorkerTransactionData *data, GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ guint delay;
+ delay = _gda_connection_get_exec_slowdown (data->cnc);
+ if (delay > 0) {
+ g_print ("Delaying execution for %u ms\n", delay / 1000);
+ g_usleep (delay);
+ }
+
+ gboolean retval;
+ if (fset->commit_transaction)
+ retval = fset->commit_transaction (data->provider, data->cnc, data->name, error);
+ else {
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+ "%s", _("Database provider does not support transactions"));
+ retval = FALSE;
+ }
+ return retval ? (gpointer) 0x01: NULL;
+}
+
+gboolean
+_gda_server_provider_commit_transaction (GdaServerProvider *provider, GdaConnection *cnc,
+ const gchar *name, GError **error)
+{
+ GdaWorker *worker;
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
+ 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_connection_is_opened (cnc), FALSE);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, FALSE);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerTransactionData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.name = name;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_commit_transaction, (gpointer) &data, NULL, NULL, error);
+ g_main_context_unref (context);
+
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return retval ? TRUE : FALSE;
+}
+
+static gpointer
+worker_rollback_transaction (WorkerTransactionData *data, GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ guint delay;
+ delay = _gda_connection_get_exec_slowdown (data->cnc);
+ if (delay > 0) {
+ g_print ("Delaying execution for %u ms\n", delay / 1000);
+ g_usleep (delay);
+ }
+
+ gboolean retval;
+ if (fset->rollback_transaction)
+ retval = fset->rollback_transaction (data->provider, data->cnc, data->name, error);
+ else {
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+ "%s", _("Database provider does not support transactions"));
+ retval = FALSE;
+ }
+ return retval ? (gpointer) 0x01: NULL;
+}
+
+gboolean
+_gda_server_provider_rollback_transaction (GdaServerProvider *provider, GdaConnection *cnc,
+ const gchar *name, GError **error)
+{
+ GdaWorker *worker;
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
+ 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_connection_is_opened (cnc), FALSE);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, FALSE);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerTransactionData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.name = name;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_rollback_transaction, (gpointer) &data, NULL, NULL, error);
+ g_main_context_unref (context);
+
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return retval ? TRUE : FALSE;
+}
+
+static gpointer
+worker_add_savepoint (WorkerTransactionData *data, GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ gboolean retval;
+ if (fset->add_savepoint)
+ retval = fset->add_savepoint (data->provider, data->cnc, data->name, error);
+ else {
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+ "%s", _("Database provider does not support savepoints"));
+ retval = FALSE;
+ }
+ return retval ? (gpointer) 0x01: NULL;
+}
+
+gboolean
+_gda_server_provider_add_savepoint (GdaServerProvider *provider, GdaConnection *cnc, const gchar *name,
GError **error)
+{
+ GdaWorker *worker;
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
+ 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_connection_is_opened (cnc), FALSE);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, FALSE);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerTransactionData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.name = name;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_add_savepoint, (gpointer) &data, NULL, NULL, error);
+ g_main_context_unref (context);
+
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return retval ? TRUE : FALSE;
+}
+
+static gpointer
+worker_rollback_savepoint (WorkerTransactionData *data, GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ gboolean retval;
+ if (fset->rollback_savepoint)
+ retval = fset->rollback_savepoint (data->provider, data->cnc, data->name, error);
+ else {
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+ "%s", _("Database provider does not support savepoints"));
+ retval = FALSE;
+ }
+ return retval ? (gpointer) 0x01: NULL;
+}
+
+gboolean
+_gda_server_provider_rollback_savepoint (GdaServerProvider *provider, GdaConnection *cnc, const gchar *name,
GError **error)
+{
+ GdaWorker *worker;
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
+ 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_connection_is_opened (cnc), FALSE);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, FALSE);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerTransactionData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.name = name;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_rollback_savepoint, (gpointer) &data, NULL, NULL, error);
+ g_main_context_unref (context);
+
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return retval ? TRUE : FALSE;
+}
+
+static gpointer
+worker_delete_savepoint (WorkerTransactionData *data, GError **error)
+{
+ GdaServerProviderBase *fset;
+ fset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ gboolean retval;
+ if (fset->delete_savepoint)
+ retval = fset->delete_savepoint (data->provider, data->cnc, data->name, error);
+ else {
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+ "%s", _("Database provider does not support savepoints"));
+ retval = FALSE;
+ }
+ return retval ? (gpointer) 0x01: NULL;
+}
+
+gboolean
+_gda_server_provider_delete_savepoint (GdaServerProvider *provider, GdaConnection *cnc, const gchar *name,
GError **error)
+{
+ GdaWorker *worker;
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
+ 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_connection_is_opened (cnc), FALSE);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, FALSE);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerTransactionData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.name = name;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_delete_savepoint, (gpointer) &data, NULL, NULL, error);
+ g_main_context_unref (context);
+
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return retval ? TRUE : FALSE;
+}
+
+/***********************************************************************************************************/
+
+/*
+ * JOB_XA_START
+ * JOB_XA_END
+ * JOB_XA_PREPARE
+ * JOB_XA_COMMIT
+ * JOB_XA_ROLLBACK
+ * JOB_XA_RECOVER
+ */
+
+typedef struct {
+ GdaWorker *worker;
+ GdaServerProvider *provider;
+ GdaConnection *cnc;
+ const GdaXaTransactionId *trx;
+ GdaXaType type;
+} WorkerXAData;
+
+static gpointer
+worker_xa (WorkerXAData *data, GError **error)
+{
+ GdaServerProviderXa *xaset;
+ xaset = _gda_server_provider_get_impl_functions (data->provider, data->worker,
GDA_SERVER_PROVIDER_FUNCTIONS_XA);
+
+ guint delay;
+ delay = _gda_connection_get_exec_slowdown (data->cnc);
+ if (delay > 0) {
+ g_print ("Delaying execution for %u ms\n", delay / 1000);
+ g_usleep (delay);
+ }
+
+ switch (data->type) {
+ case GDA_XA_START: {
+ gboolean retval;
+ if (xaset->xa_start)
+ retval = xaset->xa_start (data->provider, data->cnc, data->trx, error);
+ else {
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+ "%s", _("Database provider does not support distributed transactions"));
+ retval = FALSE;
+ }
+ return retval ? (gpointer) 0x01: NULL;
+ }
+ case GDA_XA_END: {
+ gboolean retval;
+ if (xaset->xa_end)
+ retval = xaset->xa_end (data->provider, data->cnc, data->trx, error);
+ else {
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+ "%s", _("Database provider does not support distributed transactions"));
+ retval = FALSE;
+ }
+ return retval ? (gpointer) 0x01: NULL;
+ }
+ case GDA_XA_PREPARE: {
+ gboolean retval;
+ if (xaset->xa_prepare)
+ retval = xaset->xa_prepare (data->provider, data->cnc, data->trx, error);
+ else {
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+ "%s", _("Database provider does not support distributed transactions"));
+ retval = FALSE;
+ }
+ return retval ? (gpointer) 0x01: NULL;
+ }
+ case GDA_XA_COMMIT: {
+ gboolean retval;
+ if (xaset->xa_commit)
+ retval = xaset->xa_commit (data->provider, data->cnc, data->trx, error);
+ else {
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+ "%s", _("Database provider does not support distributed transactions"));
+ retval = FALSE;
+ }
+ return retval ? (gpointer) 0x01: NULL;
+ }
+ case GDA_XA_ROLLBACK: {
+ gboolean retval;
+ if (xaset->xa_rollback)
+ retval = xaset->xa_rollback (data->provider, data->cnc, data->trx, error);
+ else {
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+ "%s", _("Database provider does not support distributed transactions"));
+ retval = FALSE;
+ }
+ return retval ? (gpointer) 0x01: NULL;
+ }
+ case GDA_XA_RECOVER: {
+ GList *retval;
+ if (xaset->xa_recover)
+ retval = xaset->xa_recover (data->provider, data->cnc, error);
+ else {
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+ "%s", _("Database provider does not support distributed transactions"));
+ retval = NULL;
+ }
+ return retval;
+ }
+ default:
+ g_assert_not_reached ();
+ }
+ return NULL; /* never reached */
+}
+
+gboolean
+_gda_server_provider_xa (GdaServerProvider *provider, GdaConnection *cnc, const GdaXaTransactionId *trx,
+ GdaXaType type, GError **error)
+{
+ GdaWorker *worker;
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
+ 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_connection_is_opened (cnc), FALSE);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, FALSE);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerXAData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.trx = trx;
+ data.type = type;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_xa, (gpointer) &data, NULL, NULL, error);
+ g_main_context_unref (context);
+
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return retval ? TRUE : FALSE;
+}
+
+GList *
+_gda_server_provider_xa_recover (GdaServerProvider *provider, GdaConnection *cnc, GError **error)
+{
+ GdaWorker *worker;
+ g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
+ 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_connection_is_opened (cnc), FALSE);
+
+ gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+ GdaServerProviderConnectionData *cdata;
+ cdata = gda_connection_internal_get_provider_data_error (cnc, FALSE);
+ if (!cdata) {
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+ g_warning ("Internal error: connection reported as opened, yet no provider data set");
+ return FALSE;
+ }
+ worker = gda_worker_ref (cdata->worker);
+
+ GMainContext *context;
+ context = _gda_server_provider_get_real_main_context (cnc);
+
+ WorkerXAData data;
+ data.worker = worker;
+ data.provider = provider;
+ data.cnc = cnc;
+ data.trx = NULL;
+ data.type = GDA_XA_RECOVER;
+
+ gpointer retval;
+ gda_worker_do_job (worker, context, 0, &retval, NULL,
+ (GdaWorkerFunc) worker_xa, (gpointer) &data, NULL, NULL, error);
+ g_main_context_unref (context);
+
+ gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+ gda_worker_unref (worker);
+
+ return (GList*) retval;
+}
+
+/***********************************************************************************************************/
+
+/*
+ * server_provider_job_done_callback:
+ *
+ * Generic function called whenever a job submitted by a connection's internal GdaWorker has finished,
+ * with the exception of jobs submitted using gda_worker_do_job()
+ */
+static void
+server_provider_job_done_callback (GdaWorker *worker, guint job_id, gpointer result, GError *error,
GdaServerProvider *provider)
+{
+ WorkerData *wd = NULL;
+ if (provider->priv->jobs_hash)
+ wd = g_hash_table_lookup (provider->priv->jobs_hash, &job_id);
+ g_assert (wd);
+
+ switch (wd->job_type) {
+ case JOB_OPEN_CONNECTION: {
+ WorkerOpenConnectionData *sdata = (WorkerOpenConnectionData*) wd->job_data;
+ sdata->callback (sdata->cnc, wd->job_id,
+ stage2_open_connection (worker, sdata->cnc, result),
+ error, sdata->callback_data);
+ break;
+ }
+ default:
+ /* should not be reached because there is no ASYNC version of the close connection call */
+ g_assert_not_reached ();
+ }
+
+ g_hash_table_remove (provider->priv->jobs_hash, &job_id); /* will call worker_data_free() */
+}
diff --git a/libgda/gda-server-provider.h b/libgda/gda-server-provider.h
index f03d435..26a8d16 100644
--- a/libgda/gda-server-provider.h
+++ b/libgda/gda-server-provider.h
@@ -3,7 +3,7 @@
* Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier <gonzalo ximian com>
* Copyright (C) 2004 - 2005 Alan Knowles <alank src gnome org>
* Copyright (C) 2005 Bas Driessen <bas driessen xobas com>
- * Copyright (C) 2005 - 2011 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2005 - 2013 Vivien Malerba <malerba gnome-db org>
* Copyright (C) 2006 - 2008 Murray Cumming <murrayc murrayc com>
* Copyright (C) 2007 Armin Burgmeier <armin openismus com>
*
@@ -33,6 +33,7 @@
#include <libgda/gda-statement.h>
#include <libgda/gda-meta-store.h>
#include <libgda/gda-xa-transaction.h>
+#include <libgda/thread-wrapper/gda-worker.h>
G_BEGIN_DECLS
@@ -69,354 +70,10 @@ struct _GdaServerProvider {
GdaServerProviderPrivate *priv;
};
-
-/**
- * GdaServerProviderMeta:
- * @_info:
- * @_btypes:
- * @_udt:
- * @udt:
- * @_udt_cols:
- * @udt_cols:
- * @_enums:
- * @enums:
- * @_domains:
- * @domains:
- * @_constraints_dom:
- * @constraints_dom:
- * @_el_types:
- * @el_types:
- * @_collations:
- * @collations:
- * @_character_sets:
- * @character_sets:
- * @_schemata:
- * @schemata:
- * @_tables_views:
- * @tables_views:
- * @_columns:
- * @columns:
- * @_view_cols:
- * @view_cols:
- * @_constraints_tab:
- * @constraints_tab:
- * @_constraints_ref:
- * @constraints_ref:
- * @_key_columns:
- * @key_columns:
- * @_check_columns:
- * @check_columns:
- * @_triggers:
- * @triggers:
- * @_routines:
- * @routines:
- * @_routine_col:
- * @routine_col:
- * @_routine_par:
- * @routine_par:
- * @_indexes_tab:
- * @indexes_tab:
- * @_index_cols:
- * @index_cols:
- *
- * These methods must be implemented by providers to update a connection's associated metadata (in a
- * #GdaMetaStore object), see the <link linkend="prov-metadata">Virtual methods for providers/Methods -
metadata</link>
- * for more information.
- */
-typedef struct {
- /* _information_schema_catalog_name */
- gboolean (*_info) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
-
- /* _builtin_data_types */
- gboolean (*_btypes) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
-
- /* _udt */
- gboolean (*_udt) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*udt) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *udt_catalog, const GValue *udt_schema);
-
- /* _udt_columns */
- gboolean (*_udt_cols) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*udt_cols) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *udt_catalog, const GValue *udt_schema, const GValue
*udt_name);
-
- /* _enums */
- gboolean (*_enums) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*enums) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *udt_catalog, const GValue *udt_schema, const GValue
*udt_name);
-
- /* _domains */
- gboolean (*_domains) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*domains) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *domain_catalog, const GValue *domain_schema);
-
- /* _domain_constraints */
- gboolean (*_constraints_dom) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*constraints_dom) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *domain_catalog, const GValue *domain_schema, const GValue
*domain_name);
-
- /* _element_types */
- gboolean (*_el_types) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*el_types) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *specific_name);
-
- /* _collations */
- gboolean (*_collations) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*collations) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *collation_catalog, const GValue *collation_schema,
- const GValue *collation_name_n);
-
- /* _character_sets */
- gboolean (*_character_sets) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*character_sets) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *chset_catalog, const GValue *chset_schema, const GValue
*chset_name_n);
-
- /* _schemata */
- gboolean (*_schemata) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*schemata) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *catalog_name, const GValue *schema_name_n);
-
- /* _tables or _views */
- gboolean (*_tables_views) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*tables_views) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *table_catalog, const GValue *table_schema, const GValue
*table_name_n);
-
- /* _columns */
- gboolean (*_columns) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*columns) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *table_catalog, const GValue *table_schema, const GValue
*table_name);
-
- /* _view_column_usage */
- gboolean (*_view_cols) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*view_cols) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *view_catalog, const GValue *view_schema, const GValue
*view_name);
-
- /* _table_constraints */
- gboolean (*_constraints_tab) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*constraints_tab) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *table_catalog, const GValue *table_schema, const GValue
*table_name,
- const GValue *constraint_name_n);
-
- /* _referential_constraints */
- gboolean (*_constraints_ref) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*constraints_ref) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *table_catalog, const GValue *table_schema, const GValue
*table_name,
- const GValue *constraint_name);
-
- /* _key_column_usage */
- gboolean (*_key_columns) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*key_columns) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *table_catalog, const GValue *table_schema, const GValue
*table_name,
- const GValue *constraint_name);
-
- /* _check_column_usage */
- gboolean (*_check_columns) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*check_columns) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *table_catalog, const GValue *table_schema, const GValue
*table_name,
- const GValue *constraint_name);
-
- /* _triggers */
- gboolean (*_triggers) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*triggers) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *table_catalog, const GValue *table_schema, const GValue
*table_name);
-
- /* _routines */
- gboolean (*_routines) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*routines) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *routine_catalog, const GValue *routine_schema,
- const GValue *routine_name_n);
-
- /* _routine_columns */
- gboolean (*_routine_col) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*routine_col) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *rout_catalog, const GValue *rout_schema, const GValue
*rout_name);
-
- /* _parameters */
- gboolean (*_routine_par) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*routine_par) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *rout_catalog, const GValue *rout_schema, const GValue
*rout_name);
- /* _table_indexes */
- gboolean (*_indexes_tab) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*indexes_tab) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *table_catalog, const GValue *table_schema, const GValue
*table_name,
- const GValue *index_name_n);
-
- /* _index_column_usage */
- gboolean (*_index_cols) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error);
- gboolean (*index_cols) (GdaServerProvider *prov, GdaConnection *cnc, GdaMetaStore *meta,
GdaMetaContext *ctx, GError **error,
- const GValue *table_catalog, const GValue *table_schema, const GValue
*table_name, const GValue *index_name);
-
- /*< private >*/
- /* Padding for future expansion */
- void (*_gda_reserved5) (void);
- void (*_gda_reserved6) (void);
- void (*_gda_reserved7) (void);
- void (*_gda_reserved8) (void);
- void (*_gda_reserved9) (void);
- void (*_gda_reserved10) (void);
- void (*_gda_reserved11) (void);
- void (*_gda_reserved12) (void);
- void (*_gda_reserved13) (void);
- void (*_gda_reserved14) (void);
- void (*_gda_reserved15) (void);
- void (*_gda_reserved16) (void);
-
-} GdaServerProviderMeta;
-
-/* distributed transaction support */
-typedef struct {
- gboolean (*xa_start) (GdaServerProvider *prov, GdaConnection *cnc, const GdaXaTransactionId *trx,
GError **error);
-
- gboolean (*xa_end) (GdaServerProvider *prov, GdaConnection *cnc, const GdaXaTransactionId *trx,
GError **error);
- gboolean (*xa_prepare) (GdaServerProvider *prov, GdaConnection *cnc, const GdaXaTransactionId *trx,
GError **error);
-
- gboolean (*xa_commit) (GdaServerProvider *prov, GdaConnection *cnc, const GdaXaTransactionId *trx,
GError **error);
- gboolean (*xa_rollback) (GdaServerProvider *prov, GdaConnection *cnc, const GdaXaTransactionId *trx,
GError **error);
-
- GList *(*xa_recover) (GdaServerProvider *prov, GdaConnection *cnc, GError **error);
-} GdaServerProviderXa;
-
-/**
- * GdaServerProviderAsyncCallback:
- * @provider:
- * @cnc:
- * @task_id:
- * @result_status:
- * @error:
- * @data:
- *
- * Function to be called by Libgda when the associated asynchronous method invoked finishes.
- */
-typedef void (*GdaServerProviderAsyncCallback) (GdaServerProvider *provider, GdaConnection *cnc, guint
task_id,
- gboolean result_status, const GError *error, gpointer data);
-/**
- * GdaServerProviderExecCallback:
- * @provider:
- * @cnc:
- * @task_id:
- * @result_obj:
- * @error:
- * @data:
- *
- * Function to be called by Libgda when the associated asynchronous method invoked finishes
- */
-typedef void (*GdaServerProviderExecCallback) (GdaServerProvider *provider, GdaConnection *cnc, guint
task_id,
- GObject *result_obj, const GError *error, gpointer data);
-
-/**
- * GDA_SERVER_PROVIDER_UNDEFINED_LIMITING_THREAD: (skip)
- */
-#define GDA_SERVER_PROVIDER_UNDEFINED_LIMITING_THREAD ((gpointer)0x1)
+typedef struct _GdaServerProviderClassPrivate GdaServerProviderClassPrivate;
struct _GdaServerProviderClass {
GObjectClass parent_class;
-
- /* provider information */
- GThread * limiting_thread; /* if not NULL, then using the provider will be limited to
this thread */
- const gchar *(* get_name) (GdaServerProvider *provider);
- const gchar *(* get_version) (GdaServerProvider *provider);
- const gchar *(* get_server_version) (GdaServerProvider *provider, GdaConnection *cnc);
- gboolean (* supports_feature) (GdaServerProvider *provider, GdaConnection *cnc,
- GdaConnectionFeature feature);
- /* types and values manipulation */
- GdaDataHandler *(* get_data_handler) (GdaServerProvider *provider, GdaConnection *cnc,
- GType g_type, const gchar *dbms_type);
- const gchar *(*get_def_dbms_type) (GdaServerProvider *provider, GdaConnection *cnc,
GType g_type);
- gchar *(*escape_string) (GdaServerProvider *provider, GdaConnection *cnc,
const gchar *str);
- gchar *(*unescape_string) (GdaServerProvider *provider, GdaConnection *cnc,
const gchar *str);
-
- /* connections management */
- gboolean (* open_connection) (GdaServerProvider *provider, GdaConnection *cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- guint *task_id, GdaServerProviderAsyncCallback
async_cb,
- gpointer cb_data);
- gboolean (* close_connection) (GdaServerProvider *provider, GdaConnection *cnc);
-
- const gchar *(* get_database) (GdaServerProvider *provider, GdaConnection *cnc);
-
- /* operations */
- gboolean (* supports_operation) (GdaServerProvider *provider, GdaConnection *cnc,
- GdaServerOperationType type, GdaSet *options);
- GdaServerOperation *(* create_operation) (GdaServerProvider *provider, GdaConnection *cnc,
- GdaServerOperationType type, GdaSet *options,
GError **error);
- gchar *(* render_operation) (GdaServerProvider *provider, GdaConnection *cnc,
- GdaServerOperation *op, GError **error);
- gboolean (* perform_operation) (GdaServerProvider *provider, GdaConnection *cnc,
- GdaServerOperation *op,
- guint *task_id, GdaServerProviderAsyncCallback
async_cb,
- gpointer cb_data, GError **error);
-
- /* transactions */
- gboolean (* begin_transaction) (GdaServerProvider *provider, GdaConnection *cnc,
- const gchar *name, GdaTransactionIsolation level,
GError **error);
- gboolean (* commit_transaction) (GdaServerProvider *provider, GdaConnection *cnc,
- const gchar *name, GError **error);
- gboolean (* rollback_transaction) (GdaServerProvider *provider, GdaConnection *cnc,
- const gchar *name, GError **error);
- gboolean (* add_savepoint) (GdaServerProvider *provider, GdaConnection *cnc,
- const gchar *name, GError **error);
- gboolean (* rollback_savepoint) (GdaServerProvider *provider, GdaConnection *cnc,
- const gchar *name, GError **error);
- gboolean (* delete_savepoint) (GdaServerProvider *provider, GdaConnection *cnc,
- const gchar *name, GError **error);
-
- /* GdaStatement */
- GdaSqlParser *(* create_parser) (GdaServerProvider *provider, GdaConnection *cnc);
-
- /**
- * statement_to_sql:
- * @cnc: a #GdaConnection object
- * @stmt: a #GdaStatement object
- * @params: (allow-none): a #GdaSet object (which can be obtained using
gda_statement_get_parameters()), or %NULL
- * @flags: SQL rendering flags, as #GdaStatementSqlFlag OR'ed values
- * @params_used: (allow-none) (element-type Gda.Holder) (out) (transfer container): a place to store
the list of individual #GdaHolder objects within @params which have been used
- * @error: a place to store errors, or %NULL
- *
- * Renders @stmt as an SQL statement, adapted to the SQL dialect used by @cnc
- *
- * Returns: a new string, or %NULL if an error occurred
- */
- gchar *(* statement_to_sql) (GdaServerProvider *provider, GdaConnection *cnc,
- GdaStatement *stmt, GdaSet *params,
GdaStatementSqlFlag flags,
- GSList **params_used, GError **error);
- gboolean (* statement_prepare) (GdaServerProvider *provider, GdaConnection *cnc,
- GdaStatement *stmt, GError **error);
- GObject *(* statement_execute) (GdaServerProvider *provider, GdaConnection *cnc,
- GdaStatement *stmt, GdaSet *params,
- GdaStatementModelUsage model_usage,
- GType *col_types, GdaSet **last_inserted_row,
- guint *task_id, GdaServerProviderExecCallback
exec_cb,
- gpointer cb_data, GError **error);
-
- /* Misc */
- gboolean (* is_busy) (GdaServerProvider *provider, GdaConnection *cnc,
GError **error);
- gboolean (* cancel) (GdaServerProvider *provider, GdaConnection *cnc,
- guint task_id, GError **error);
- GdaConnection *(* create_connection) (GdaServerProvider *provider);
-
- /* meta data reporting */
- GdaServerProviderMeta meta_funcs;
-
- /* distributed transaction */
- GdaServerProviderXa *xa_funcs; /* it is a pointer! => set to %NULL if unsupported by provider */
-
- /* SQL identifiers quoting */
- gchar *(* identifier_quote) (GdaServerProvider *provider, GdaConnection *cnc,
- const gchar *id,
- gboolean for_meta_store, gboolean force_quotes);
-
- /* Async. handling */
- gboolean (*handle_async) (GdaServerProvider *provider, GdaConnection *cnc,
GError **error);
-
- GdaSqlStatement *(*statement_rewrite) (GdaServerProvider *provider, GdaConnection *cnc,
- GdaStatement *stmt, GdaSet *params, GError **error);
- /*< private >*/
- /* Padding for future expansion */
- void (*_gda_reserved1) (void);
- void (*_gda_reserved2) (void);
- void (*_gda_reserved3) (void);
- void (*_gda_reserved4) (void);
- void (*_gda_reserved5) (void);
- void (*_gda_reserved6) (void);
+ gpointer functions_sets[8];
};
/**
diff --git a/libgda/gda-statement.c b/libgda/gda-statement.c
index 08bea9b..0701f68 100644
--- a/libgda/gda-statement.c
+++ b/libgda/gda-statement.c
@@ -36,7 +36,7 @@
#include <libgda/sql-parser/gda-statement-struct-select.h>
#include <libgda/gda-marshal.h>
#include <libgda/gda-data-handler.h>
-#include <libgda/gda-server-provider.h>
+#include <libgda/gda-server-provider-private.h>
#include <libgda/gda-statement-extra.h>
#include <libgda/gda-holder.h>
#include <libgda/gda-set.h>
@@ -147,6 +147,8 @@ gda_statement_class_init (GdaStatementClass * klass)
/**
* GdaStatement::checked:
* @stmt: the #GdaStatement object
+ * @cnc: a #GdaConnection
+ * @checked: whether @stmt have been verified
*
* Gets emitted whenever the structure and contents
* of @stmt have been verified (emitted after gda_statement_check_validity()).
@@ -871,15 +873,12 @@ gda_statement_to_sql_extended (GdaStatement *stmt, GdaConnection *cnc, GdaSet *p
context.params = params;
context.flags = flags;
if (cnc) {
- GdaServerProvider *prov;
- prov = gda_connection_get_provider (cnc);
-#define PROV_CLASS(provider) (GDA_SERVER_PROVIDER_CLASS (G_OBJECT_GET_CLASS (provider)))
- if (prov && PROV_CLASS (prov)->statement_to_sql)
- return (PROV_CLASS (prov)->statement_to_sql) (prov,
- cnc, stmt, params, flags,
+ if (gda_connection_is_opened (cnc))
+ return _gda_server_provider_statement_to_sql (gda_connection_get_provider (cnc), cnc,
+ stmt, params, flags,
params_used, error);
- context.cnc = cnc;
- context.provider = gda_connection_get_provider (cnc);
+ else
+ context.provider = gda_connection_get_provider (cnc);
}
str = gda_statement_to_sql_real (stmt, &context, error);
diff --git a/libgda/gda-util.c b/libgda/gda-util.c
index 4121999..9859d43 100644
--- a/libgda/gda-util.c
+++ b/libgda/gda-util.c
@@ -42,6 +42,7 @@
#include <libgda/gda-log.h>
#include <libgda/gda-util.h>
#include <libgda/gda-server-provider.h>
+#include <libgda/gda-server-provider-private.h>
#include <libgda/gda-column.h>
#include <libgda/gda-data-model-iter.h>
#ifdef HAVE_LOCALE_H
@@ -62,8 +63,6 @@
extern gchar *gda_lang_locale;
extern GdaAttributesManager *gda_holder_attributes_manager;
-#define PROV_CLASS(provider) (GDA_SERVER_PROVIDER_CLASS (G_OBJECT_GET_CLASS (provider)))
-
/**
* gda_g_type_to_string:
* @type: Type to convert from.
@@ -2592,9 +2591,12 @@ gda_sql_identifier_quote (const gchar *id, GdaConnection *cnc, GdaServerProvider
if ((*id == '*') && (! id [1]))
return g_strdup (id);
- if (prov && PROV_CLASS (prov)->identifier_quote)
- return PROV_CLASS (prov)->identifier_quote (prov, cnc, id,
- for_meta_store, force_quotes);
+ if (prov) {
+ gchar *quoted;
+ quoted = _gda_server_provider_identifier_quote (prov, cnc, id, for_meta_store, force_quotes);
+ if (quoted)
+ return quoted;
+ }
if (for_meta_store) {
gchar *tmp, *ptr;
diff --git a/libgda/gda-xa-transaction.c b/libgda/gda-xa-transaction.c
index 31a1e55..adab816 100644
--- a/libgda/gda-xa-transaction.c
+++ b/libgda/gda-xa-transaction.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2008 Murray Cumming <murrayc murrayc com>
- * Copyright (C) 2008 - 2011 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2008 - 2013 Vivien Malerba <malerba gnome-db org>
* Copyright (C) 2009 Bas Driessen <bas driessen xobas com>
* Copyright (C) 2009 Og B. Maciel <ogmaciel gnome org>
* Copyright (C) 2010 David King <davidk openismus com>
@@ -26,9 +26,11 @@
#include <libgda/gda-xa-transaction.h>
#include <libgda/gda-connection.h>
#include <libgda/gda-server-provider.h>
+#include <libgda/gda-server-provider-private.h>
#include <libgda/gda-value.h>
#include <string.h>
#include <libgda/gda-decl.h>
+#include <libgda/gda-debug-macros.h>
static void gda_xa_transaction_class_init (GdaXaTransactionClass *klass);
static void gda_xa_transaction_init (GdaXaTransaction *xa_trans, GdaXaTransactionClass *klass);
@@ -45,7 +47,6 @@ static void gda_xa_transaction_get_property (GObject *object,
static GObjectClass* parent_class = NULL;
-#define PROV_CLASS(provider) (GDA_SERVER_PROVIDER_CLASS (G_OBJECT_GET_CLASS (provider)))
struct _GdaXaTransactionPrivate {
GdaXaTransactionId xid;
@@ -311,7 +312,8 @@ gda_xa_transaction_register_connection (GdaXaTransaction *xa_trans, GdaConnecti
* to not support them */
GdaServerProvider *prov;
prov = gda_connection_get_provider (cnc);
- if (! PROV_CLASS (prov)->xa_funcs) {
+
+ 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,
@@ -323,7 +325,6 @@ gda_xa_transaction_register_connection (GdaXaTransaction *xa_trans, GdaConnecti
xa_trans->priv->non_xa_cnc = cnc;
}
-
bin = g_new0 (GdaBinary, 1);
bin->data = (guchar*) g_strdup (branch);
bin->binary_length = strlen (branch) + 1;
@@ -384,19 +385,12 @@ gda_xa_transaction_begin (GdaXaTransaction *xa_trans, GError **error)
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));
+ 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 (! _gda_server_provider_xa_start (prov, cnc, &(xa_trans->priv->xid), error))
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 */
@@ -415,16 +409,11 @@ gda_xa_transaction_begin (GdaXaTransaction *xa_trans, GError **error)
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);
- }
+ 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);
+ _gda_server_provider_xa_rollback (prov, cnc, &(xa_trans->priv->xid), NULL);
}
else {
/* do a simple ROLLBACK */
@@ -482,22 +471,10 @@ gda_xa_transaction_commit (GdaXaTransaction *xa_trans, GSList **cnc_to_recover,
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));
+ if (!_gda_server_provider_xa_end (prov, cnc, &(xa_trans->priv->xid), error))
break;
- }
- if (!PROV_CLASS (prov)->xa_funcs->xa_prepare (prov, cnc, &(xa_trans->priv->xid), error))
+ if (!_gda_server_provider_xa_prepare (prov, cnc, &(xa_trans->priv->xid), error))
break;
}
if (list) {
@@ -515,12 +492,7 @@ gda_xa_transaction_commit (GdaXaTransaction *xa_trans, GSList **cnc_to_recover,
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));
+ _gda_server_provider_xa_rollback (prov, cnc, &(xa_trans->priv->xid), NULL);
}
}
return FALSE;
@@ -545,12 +517,7 @@ gda_xa_transaction_commit (GdaXaTransaction *xa_trans, GSList **cnc_to_recover,
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));
+ _gda_server_provider_xa_rollback (prov, cnc, &(xa_trans->priv->xid), NULL);
}
}
return FALSE;
@@ -569,7 +536,7 @@ gda_xa_transaction_commit (GdaXaTransaction *xa_trans, GSList **cnc_to_recover,
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) &&
+ if (! _gda_server_provider_xa_commit (prov, cnc, &(xa_trans->priv->xid), error) &&
cnc_to_recover)
*cnc_to_recover = g_slist_prepend (*cnc_to_recover, cnc);
}
@@ -606,11 +573,12 @@ gda_xa_transaction_rollback (GdaXaTransaction *xa_trans, GError **error)
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));
+ GError *lerror = NULL;
+ _gda_server_provider_xa_rollback (prov, cnc, &(xa_trans->priv->xid), &lerror);
+ if (error && !*error)
+ g_propagate_error (error, lerror);
else
- PROV_CLASS (prov)->xa_funcs->xa_rollback (prov, cnc, &(xa_trans->priv->xid),
error);
+ g_clear_error (&lerror);
}
}
return TRUE;
@@ -650,55 +618,40 @@ gda_xa_transaction_commit_recovered (GdaXaTransaction *xa_trans, GSList **cnc_to
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;
+ 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)
+ recov_xid_list = _gda_server_provider_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;
- 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);
- }
- }
+ 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) {
+ retval = _gda_server_provider_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);
}
}
}
diff --git a/libgda/libgda.h.in b/libgda/libgda.h.in
index 2880a27..980a08b 100644
--- a/libgda/libgda.h.in
+++ b/libgda/libgda.h.in
@@ -34,7 +34,6 @@
#include <libgda/gda-config.h>
#include <libgda/gda-connection-event.h>
#include <libgda/gda-connection.h>
-#include <libgda/gda-connection-private.h>
#include <libgda/gda-data-comparator.h>
#include <libgda/gda-data-model-array.h>
@LIBGDA_BDB_INC@
diff --git a/libgda/libgda.symbols b/libgda/libgda.symbols
index 2d84342..e6ef9f5 100644
--- a/libgda/libgda.symbols
+++ b/libgda/libgda.symbols
@@ -74,7 +74,6 @@
gda_config_can_modify_system_config
gda_config_define_dsn
gda_config_dsn_needs_authentication
- gda_config_error_get_type
gda_config_error_quark
gda_config_get
gda_config_get_dsn_info
@@ -91,14 +90,10 @@
gda_connection_add_event_string
gda_connection_add_prepared_statement
gda_connection_add_savepoint
- gda_connection_async_cancel
- gda_connection_async_fetch_result
- gda_connection_async_statement_execute
gda_connection_batch_execute
gda_connection_begin_transaction
gda_connection_clear_events_list
gda_connection_close
- gda_connection_close_no_warning
gda_connection_commit_transaction
gda_connection_create_operation
gda_connection_create_parser
@@ -107,7 +102,6 @@
gda_connection_delete_row_from_table
gda_connection_error_get_type
gda_connection_error_quark
- gda_connection_event_code_get_type
gda_connection_event_get_code
gda_connection_event_get_description
gda_connection_event_get_event_type
@@ -121,7 +115,6 @@
gda_connection_event_set_gda_code
gda_connection_event_set_source
gda_connection_event_set_sqlstate
- gda_connection_event_type_get_type
gda_connection_execute_non_select_command
gda_connection_execute_select_command
gda_connection_feature_get_type
@@ -130,6 +123,7 @@
gda_connection_get_date_format
gda_connection_get_dsn
gda_connection_get_events
+ gda_connection_get_main_context
gda_connection_get_meta_store
gda_connection_get_meta_store_data
gda_connection_get_meta_store_data_v
@@ -142,7 +136,6 @@
gda_connection_insert_row_into_table
gda_connection_insert_row_into_table_v
gda_connection_internal_change_transaction_state
- gda_connection_internal_get_provider_data
gda_connection_internal_get_provider_data_error
gda_connection_internal_reset_transaction_status
gda_connection_internal_savepoint_added
@@ -158,6 +151,7 @@
gda_connection_new_from_dsn
gda_connection_new_from_string
gda_connection_open
+ gda_connection_open_async
gda_connection_open_from_dsn
gda_connection_open_from_string
gda_connection_open_sqlite
@@ -169,6 +163,7 @@
gda_connection_repetitive_statement_execute
gda_connection_rollback_savepoint
gda_connection_rollback_transaction
+ gda_connection_set_main_context
gda_connection_statement_execute
gda_connection_statement_execute_non_select
gda_connection_statement_execute_select
@@ -186,7 +181,6 @@
gda_data_access_wrapper_new
gda_data_access_wrapper_set_mapping
gda_data_comparator_compute_diff
- gda_data_comparator_error_get_type
gda_data_comparator_error_quark
gda_data_comparator_get_diff
gda_data_comparator_get_n_diffs
@@ -202,7 +196,6 @@
gda_data_handler_get_type
gda_data_handler_get_value_from_sql
gda_data_handler_get_value_from_str
- gda_data_model_access_flags_get_type
gda_data_model_add_data_from_xml_node
gda_data_model_append_row
gda_data_model_append_values
@@ -229,7 +222,6 @@
gda_data_model_dir_new
gda_data_model_dump
gda_data_model_dump_as_string
- gda_data_model_error_get_type
gda_data_model_error_quark
gda_data_model_export_to_file
gda_data_model_export_to_string
@@ -246,7 +238,6 @@
gda_data_model_get_type
gda_data_model_get_typed_value_at
gda_data_model_get_value_at
- gda_data_model_hint_get_type
gda_data_model_import_clean_errors
gda_data_model_import_from_file
gda_data_model_import_from_model
@@ -256,8 +247,6 @@
gda_data_model_import_new_file
gda_data_model_import_new_mem
gda_data_model_import_new_xml_node
- gda_data_model_io_format_get_type
- gda_data_model_iter_error_get_type
gda_data_model_iter_error_quark
gda_data_model_iter_get_column_for_param
gda_data_model_iter_get_holder_for_field
@@ -303,7 +292,6 @@
gda_data_proxy_cancel_all_changes
gda_data_proxy_cancel_row_changes
gda_data_proxy_delete
- gda_data_proxy_error_get_type
gda_data_proxy_error_quark
gda_data_proxy_get_filtered_n_rows
gda_data_proxy_get_filter_expr
@@ -351,7 +339,6 @@
gda_default_escape_string
gda_default_get_type
gda_default_unescape_string
- gda_diff_type_get_type
gda_dsn_info_copy
gda_dsn_info_free
gda_dsn_info_get_type
@@ -385,7 +372,6 @@
gda_handler_type_new
gda_holder_attributes_manager
gda_holder_copy
- gda_holder_error_get_type
gda_holder_error_quark
gda_holder_force_invalid
gda_holder_force_invalid_e
@@ -459,13 +445,8 @@
gda_meta_context_set_column
gda_meta_context_set_columns
gda_meta_context_free
- gda_meta_db_object_type_get_type
- gda_meta_graph_info_get_type
- gda_meta_sort_type_get_type
- gda_meta_store_change_type_get_type
gda_meta_store_create_modify_data_model
gda_meta_store_declare_foreign_key
- gda_meta_store_error_get_type
gda_meta_store_error_quark
gda_meta_store_extract
gda_meta_store_extract_v
@@ -494,9 +475,7 @@
gda_meta_struct_complement_depend
gda_meta_struct_complement_schema
gda_meta_struct_dump_as_graph
- gda_meta_struct_error_get_type
gda_meta_struct_error_quark
- gda_meta_struct_feature_get_type
gda_meta_struct_get_all_db_objects
gda_meta_struct_get_db_object
gda_meta_struct_get_table_column
@@ -588,8 +567,6 @@
gda_server_operation_is_valid
gda_server_operation_load_data_from_xml
gda_server_operation_new
- gda_server_operation_node_status_get_type
- gda_server_operation_node_type_get_type
gda_server_operation_op_type_to_string
gda_server_operation_perform_create_database
gda_server_operation_perform_create_table
@@ -603,10 +580,8 @@
gda_server_operation_set_value_at
gda_server_operation_set_value_at_path
gda_server_operation_string_to_op_type
- gda_server_operation_type_get_type
gda_server_provider_create_operation
gda_server_provider_create_parser
- gda_server_provider_error_get_type
gda_server_provider_error_quark
gda_server_provider_escape_string
gda_server_provider_find_file
@@ -614,6 +589,7 @@
gda_server_provider_get_data_handler_default
gda_server_provider_get_data_handler_g_type
gda_server_provider_get_default_dbms_type
+ gda_server_provider_get_impl_functions_for_class
gda_server_provider_get_name
gda_server_provider_get_server_version
gda_server_provider_get_type
@@ -626,6 +602,7 @@
gda_server_provider_perform_operation
gda_server_provider_perform_operation_default
gda_server_provider_render_operation
+ gda_server_provider_set_impl_functions
gda_server_provider_string_to_value
gda_server_provider_supports_feature
gda_server_provider_supports_operation
@@ -633,7 +610,6 @@
gda_server_provider_value_to_sql_string
gda_set_add_holder
gda_set_copy
- gda_set_error_get_type
gda_set_error_quark
gda_set_get_group
gda_set_get_holder
@@ -703,7 +679,6 @@
gda_sql_builder_add_sub_select
gda_sql_builder_compound_add_sub_select
gda_sql_builder_compound_set_type
- gda_sql_builder_error_get_type
gda_sql_builder_error_quark
gda_sql_builder_export_expression
gda_sql_builder_get_sql_statement
@@ -858,37 +833,20 @@
gda_statement_check_structure
gda_statement_check_validity
gda_statement_copy
- gda_statement_error_get_type
gda_statement_error_quark
gda_statement_get_parameters
gda_statement_get_statement_type
gda_statement_get_type
gda_statement_is_useless
- gda_statement_model_usage_get_type
gda_statement_new
gda_statement_normalize
gda_statement_rewrite_for_default_values
gda_statement_serialize
- gda_statement_sql_flag_get_type
gda_statement_to_sql_extended
gda_statement_to_sql_real
gda_string_to_binary
gda_string_to_blob
gda_text_to_alphanum
- gda_thread_wrapper_cancel
- gda_thread_wrapper_connect_raw
- gda_thread_wrapper_disconnect
- gda_thread_wrapper_error_quark
- gda_thread_wrapper_execute
- gda_thread_wrapper_execute_void
- gda_thread_wrapper_fetch_result
- gda_thread_wrapper_get_io_channel
- gda_thread_wrapper_get_type
- gda_thread_wrapper_get_waiting_size
- gda_thread_wrapper_iterate
- gda_thread_wrapper_new
- gda_thread_wrapper_steal_signal
- gda_thread_wrapper_unset_io_channel
gda_time_copy
gda_time_change_timezone
gda_time_free
@@ -903,17 +861,14 @@
gda_transaction_status_add_event_sql
gda_transaction_status_add_event_sub
gda_transaction_status_add_event_svp
- gda_transaction_status_event_type_get_type
gda_transaction_status_find
gda_transaction_status_find_current
gda_transaction_status_free_events
gda_transaction_status_get_type
gda_transaction_status_new
- gda_transaction_status_state_get_type
gda_tree_add_manager
gda_tree_clean
gda_tree_dump
- gda_tree_error_get_type
gda_tree_error_quark
gda_tree_get_node
gda_tree_get_node_manager
@@ -923,7 +878,6 @@
gda_tree_manager_add_manager
gda_tree_manager_add_new_node_attribute
gda_tree_manager_create_node
- gda_tree_manager_error_get_type
gda_tree_manager_error_quark
gda_tree_manager_get_managers
gda_tree_manager_get_node_create_func
@@ -945,7 +899,6 @@
gda_tree_mgr_tables_get_type
gda_tree_mgr_tables_new
gda_tree_new
- gda_tree_node_error_get_type
gda_tree_node_error_quark
gda_tree_node_fetch_attribute
gda_tree_node_get_child_index
@@ -1022,16 +975,26 @@
gda_virtual_connection_internal_get_provider_data
gda_virtual_connection_internal_set_provider_data
gda_virtual_connection_open
- gda_virtual_connection_open_extended
gda_virtual_provider_get_type
gda_vprovider_data_model_get_type
gda_vprovider_data_model_new
gda_vprovider_hub_get_type
gda_vprovider_hub_new
+ gda_worker_cancel_job
+ gda_worker_do_job
+ gda_worker_fetch_job_result
+ gda_worker_forget_job
+ gda_worker_kill
+ gda_worker_new
+ gda_worker_ref
+ gda_worker_set_callback
+ gda_worker_submit_job
+ gda_worker_thread_is_worker
+ gda_worker_unref
+ gda_worker_wait_job
gda_xa_transaction_begin
gda_xa_transaction_commit
gda_xa_transaction_commit_recovered
- gda_xa_transaction_error_get_type
gda_xa_transaction_error_quark
gda_xa_transaction_get_type
gda_xa_transaction_id_to_string
diff --git a/libgda/providers-support/gda-pstmt.c b/libgda/providers-support/gda-pstmt.c
index 0c43c3b..924db12 100644
--- a/libgda/providers-support/gda-pstmt.c
+++ b/libgda/providers-support/gda-pstmt.c
@@ -97,6 +97,7 @@ gda_stmt_reset_cb (GdaStatement *stmt, GdaPStmt *pstmt)
{
g_signal_handlers_disconnect_by_func (G_OBJECT (stmt),
G_CALLBACK (gda_stmt_reset_cb), pstmt);
+ /*g_print ("g_object_remove_weak_pointer (%p, %p)\n", pstmt->priv->gda_stmt,
&(pstmt->priv->gda_stmt));*/
g_object_remove_weak_pointer ((GObject*) pstmt->priv->gda_stmt, (gpointer*) &(pstmt->priv->gda_stmt));
pstmt->priv->gda_stmt = NULL;
}
@@ -164,6 +165,7 @@ gda_pstmt_set_gda_statement (GdaPStmt *pstmt, GdaStatement *stmt)
pstmt->priv->gda_stmt = stmt;
if (stmt) {
g_object_add_weak_pointer ((GObject*) stmt, (gpointer*) &(pstmt->priv->gda_stmt));
+ /*g_print ("g_object_add_weak_pointer (%p, %p)\n", stmt, &(pstmt->priv->gda_stmt));*/
g_signal_connect (G_OBJECT (stmt), "reset", G_CALLBACK (gda_stmt_reset_cb), pstmt);
}
}
diff --git a/libgda/sql-parser/Makefile.am b/libgda/sql-parser/Makefile.am
index 6daca95..7b5f3bc 100644
--- a/libgda/sql-parser/Makefile.am
+++ b/libgda/sql-parser/Makefile.am
@@ -42,7 +42,7 @@ gda-sql-parser-enum-types.h: s-enum-types-h
@true
s-enum-types-h: @REBUILD@ $(libgda_sql_parser_headers) Makefile
- ( cd $(srcdir) && glib-mkenums \
+ ( cd $(srcdir) && $(GLIB_MKENUMS) \
--fhead "#ifndef __LIBGDA_SQL_PARSER_ENUM_TYPES_H__\n#define
__LIBGDA_SQL_PARSER_ENUM_TYPES_H__\n\n#include <glib-object.h>\n\nG_BEGIN_DECLS\n" \
--vhead "GType @enum_name _get_type (void);\n#define GDA_TYPE_ ENUMSHORT@ (@enum_name
_get_type())\n" \
--ftail "G_END_DECLS\n\n#endif /* __LIBGDA_ENUM_TYPES_H__ */" \
@@ -55,7 +55,7 @@ gda-sql-parser-enum-types.c: s-enum-types-c
@true
s-enum-types-c: @REBUILD@ $(libgda_sql_parser_headers) Makefile
- ( cd $(srcdir) && glib-mkenums \
+ ( cd $(srcdir) && $(GLIB_MKENUMS) \
--fhead "#include <sql-parser/gda-sql-parser.h>\n" \
--fhead "#include <sql-parser/gda-sql-statement.h>\n" \
--fhead "#include <glib-object.h>" \
diff --git a/libgda/sqlite/gda-sqlite-blob-op.c b/libgda/sqlite/gda-sqlite-blob-op.c
index 9c41a81..d973253 100644
--- a/libgda/sqlite/gda-sqlite-blob-op.c
+++ b/libgda/sqlite/gda-sqlite-blob-op.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 - 2011 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2009 - 2014 Vivien Malerba <malerba gnome-db org>
* Copyright (C) 2010 David King <davidk openismus com>
*
* This library is free software; you can redistribute it and/or
@@ -23,6 +23,7 @@
#include <libgda/libgda.h>
#include "gda-sqlite.h"
#include "gda-sqlite-blob-op.h"
+#include <libgda/gda-blob-op-impl.h>
#include "gda-sqlite-util.h"
#include <sql-parser/gda-sql-parser.h>
@@ -89,9 +90,9 @@ gda_sqlite_blob_op_class_init (GdaSqliteBlobOpClass *klass)
parent_class = g_type_class_peek_parent (klass);
object_class->finalize = gda_sqlite_blob_op_finalize;
- blob_class->get_length = gda_sqlite_blob_op_get_length;
- blob_class->read = gda_sqlite_blob_op_read;
- blob_class->write = gda_sqlite_blob_op_write;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->get_length = gda_sqlite_blob_op_get_length;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->read = gda_sqlite_blob_op_read;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->write = gda_sqlite_blob_op_write;
}
static void
@@ -115,7 +116,7 @@ gda_sqlite_blob_op_finalize (GObject * object)
}
GdaBlobOp *
-_gda_sqlite_blob_op_new (SqliteConnectionData *cdata,
+_gda_sqlite_blob_op_new (GdaConnection *cnc,
const gchar *db_name, const gchar *table_name,
const gchar *column_name, sqlite3_int64 rowid)
{
@@ -126,6 +127,7 @@ _gda_sqlite_blob_op_new (SqliteConnectionData *cdata,
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);
@@ -137,7 +139,10 @@ _gda_sqlite_blob_op_new (SqliteConnectionData *cdata,
else if (! _split_identifier_string (g_strdup (table_name), &db, &table))
return NULL;
- if (! _gda_sqlite_check_transaction_started (cdata->gdacnc, &transaction_started, NULL))
+ SqliteConnectionData *cdata;
+ cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata ||
+ ! _gda_sqlite_check_transaction_started (cdata->gdacnc, &transaction_started, NULL))
return NULL;
rc = SQLITE3_CALL (sqlite3_blob_open) (cdata->connection, db ? db : "main",
@@ -153,7 +158,7 @@ _gda_sqlite_blob_op_new (SqliteConnectionData *cdata,
goto out;
}
- bop = g_object_new (GDA_TYPE_SQLITE_BLOB_OP, NULL);
+ bop = g_object_new (GDA_TYPE_SQLITE_BLOB_OP, "connection", cnc, NULL);
bop->priv->sblob = sblob;
#ifdef GDA_DEBUG_NO
g_print ("OPENED blob %p\n", bop);
diff --git a/libgda/sqlite/gda-sqlite-blob-op.h b/libgda/sqlite/gda-sqlite-blob-op.h
index 284492e..a09acf7 100644
--- a/libgda/sqlite/gda-sqlite-blob-op.h
+++ b/libgda/sqlite/gda-sqlite-blob-op.h
@@ -44,7 +44,7 @@ struct _GdaSqliteBlobOpClass {
};
GType _gda_sqlite_blob_op_get_type (void) G_GNUC_CONST;
-GdaBlobOp *_gda_sqlite_blob_op_new (SqliteConnectionData *cdata,
+GdaBlobOp *_gda_sqlite_blob_op_new (GdaConnection *cnc,
const gchar *db_name, const gchar *table_name,
const gchar *column_name, sqlite3_int64 rowid);
diff --git a/libgda/sqlite/gda-sqlite-provider.c b/libgda/sqlite/gda-sqlite-provider.c
index da031af..6889b40 100644
--- a/libgda/sqlite/gda-sqlite-provider.c
+++ b/libgda/sqlite/gda-sqlite-provider.c
@@ -43,6 +43,7 @@
#include <libgda/gda-data-model-private.h>
#include <libgda/gda-util.h>
#include <libgda/gda-server-provider-extra.h>
+#include <libgda/gda-server-provider-impl.h>
#include <libgda/gda-server-operation-private.h>
#include "gda-sqlite.h"
#include "gda-sqlite-provider.h"
@@ -243,8 +244,6 @@ pending_blobs_free_list (GSList *blist)
g_slist_free (blist);
}
-/* TMP */
-
/*
* GObject methods
*/
@@ -258,9 +257,9 @@ static GObjectClass *parent_class = NULL;
*/
/* connection management */
static gboolean gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
*cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- guint *task_id,
- GdaServerProviderAsyncCallback async_cb,
gpointer cb_data);
+ GdaQuarkList *params, GdaQuarkList *auth);
+static gboolean gda_sqlite_provider_prepare_connection (GdaServerProvider *provider,
+ GdaConnection *cnc, GdaQuarkList *params,
GdaQuarkList *auth);
static gboolean gda_sqlite_provider_close_connection (GdaServerProvider *provider, GdaConnection
*cnc);
static const gchar *gda_sqlite_provider_get_server_version (GdaServerProvider *provider,
GdaConnection *cnc);
static const gchar *gda_sqlite_provider_get_database (GdaServerProvider *provider, GdaConnection
*cnc);
@@ -275,9 +274,7 @@ static gchar *gda_sqlite_provider_render_operation (GdaServerProvid
GdaServerOperation *op, GError **error);
static gboolean gda_sqlite_provider_perform_operation (GdaServerProvider *provider, GdaConnection
*cnc,
- GdaServerOperation *op, guint *task_id,
- GdaServerProviderAsyncCallback async_cb,
- gpointer cb_data, GError **error);
+ GdaServerOperation *op, GError **error);
/* transactions */
static gboolean gda_sqlite_provider_begin_transaction (GdaServerProvider *provider, GdaConnection
*cnc,
const gchar *name, GdaTransactionIsolation
level,
@@ -295,9 +292,10 @@ static gboolean gda_sqlite_provider_delete_savepoint (GdaServerProvid
/* information retrieval */
static const gchar *gda_sqlite_provider_get_version (GdaServerProvider *provider);
-static gboolean gda_sqlite_provider_supports (GdaServerProvider *provider, GdaConnection *cnc,
- GdaConnectionFeature feature);
+static gboolean gda_sqlite_provider_supports_feature (GdaServerProvider *provider, GdaConnection
*cnc,
+ GdaConnectionFeature feature);
+static GdaWorker *gda_sqlite_provider_create_worker (GdaServerProvider *provider);
static const gchar *gda_sqlite_provider_get_name (GdaServerProvider *provider);
static GdaDataHandler *gda_sqlite_provider_get_data_handler (GdaServerProvider *provider, GdaConnection
*cnc,
@@ -316,10 +314,8 @@ static gboolean gda_sqlite_provider_statement_prepare (GdaServerProv
static GObject *gda_sqlite_provider_statement_execute (GdaServerProvider *provider,
GdaConnection *cnc,
GdaStatement *stmt, GdaSet *params,
GdaStatementModelUsage model_usage,
- GType *col_types, GdaSet
**last_inserted_row,
- guint *task_id,
GdaServerProviderExecCallback async_cb,
- gpointer cb_data, GError **error);
-static GdaSqlStatement *gda_sqlite_statement_rewrite (GdaServerProvider *provider,
GdaConnection *cnc,
+ GType *col_types, GdaSet
**last_inserted_row, GError **error);
+static GdaSqlStatement *gda_sqlite_provider_statement_rewrite (GdaServerProvider *provider,
GdaConnection *cnc,
GdaStatement *stmt, GdaSet *params, GError
**error);
/* string escaping */
@@ -465,6 +461,91 @@ get_table_nth_column_name (GdaConnection *cnc, const gchar *table_name, gint pos
/*
* GdaSqliteProvider class implementation
*/
+GdaServerProviderBase sqlite_base_functions = {
+ gda_sqlite_provider_get_name,
+ gda_sqlite_provider_get_version,
+ gda_sqlite_provider_get_server_version,
+ gda_sqlite_provider_supports_feature,
+ gda_sqlite_provider_create_worker,
+ NULL,
+ gda_sqlite_provider_create_parser,
+ gda_sqlite_provider_get_data_handler,
+ gda_sqlite_provider_get_default_dbms_type,
+ gda_sqlite_provider_supports_operation,
+ gda_sqlite_provider_create_operation,
+ gda_sqlite_provider_render_operation,
+ gda_sqlite_provider_statement_to_sql,
+ NULL,
+ gda_sqlite_provider_statement_rewrite,
+ gda_sqlite_provider_open_connection,
+ gda_sqlite_provider_prepare_connection,
+ gda_sqlite_provider_close_connection,
+ gda_sqlite_provider_escape_string,
+ gda_sqlite_provider_unescape_string,
+ gda_sqlite_provider_get_database,
+ gda_sqlite_provider_perform_operation,
+ gda_sqlite_provider_begin_transaction,
+ gda_sqlite_provider_commit_transaction,
+ gda_sqlite_provider_rollback_transaction,
+ gda_sqlite_provider_add_savepoint,
+ gda_sqlite_provider_rollback_savepoint,
+ gda_sqlite_provider_delete_savepoint,
+ gda_sqlite_provider_statement_prepare,
+ gda_sqlite_provider_statement_execute,
+
+ NULL, NULL, NULL, NULL, /* padding */
+};
+
+GdaServerProviderMeta sqlite_meta_functions = {
+ _gda_sqlite_meta__info,
+ _gda_sqlite_meta__btypes,
+ _gda_sqlite_meta__udt,
+ _gda_sqlite_meta_udt,
+ _gda_sqlite_meta__udt_cols,
+ _gda_sqlite_meta_udt_cols,
+ _gda_sqlite_meta__enums,
+ _gda_sqlite_meta_enums,
+ _gda_sqlite_meta__domains,
+ _gda_sqlite_meta_domains,
+ _gda_sqlite_meta__constraints_dom,
+ _gda_sqlite_meta_constraints_dom,
+ _gda_sqlite_meta__el_types,
+ _gda_sqlite_meta_el_types,
+ _gda_sqlite_meta__collations,
+ _gda_sqlite_meta_collations,
+ _gda_sqlite_meta__character_sets,
+ _gda_sqlite_meta_character_sets,
+ _gda_sqlite_meta__schemata,
+ _gda_sqlite_meta_schemata,
+ _gda_sqlite_meta__tables_views,
+ _gda_sqlite_meta_tables_views,
+ _gda_sqlite_meta__columns,
+ _gda_sqlite_meta_columns,
+ _gda_sqlite_meta__view_cols,
+ _gda_sqlite_meta_view_cols,
+ _gda_sqlite_meta__constraints_tab,
+ _gda_sqlite_meta_constraints_tab,
+ _gda_sqlite_meta__constraints_ref,
+ _gda_sqlite_meta_constraints_ref,
+ _gda_sqlite_meta__key_columns,
+ _gda_sqlite_meta_key_columns,
+ _gda_sqlite_meta__check_columns,
+ _gda_sqlite_meta_check_columns,
+ _gda_sqlite_meta__triggers,
+ _gda_sqlite_meta_triggers,
+ _gda_sqlite_meta__routines,
+ _gda_sqlite_meta_routines,
+ _gda_sqlite_meta__routine_col,
+ _gda_sqlite_meta_routine_col,
+ _gda_sqlite_meta__routine_par,
+ _gda_sqlite_meta_routine_par,
+ _gda_sqlite_meta__indexes_tab,
+ _gda_sqlite_meta_indexes_tab,
+ _gda_sqlite_meta__index_cols,
+ _gda_sqlite_meta_index_cols,
+
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* padding */
+};
static void
gda_sqlite_provider_class_init (GdaSqliteProviderClass *klass)
@@ -473,101 +554,16 @@ gda_sqlite_provider_class_init (GdaSqliteProviderClass *klass)
parent_class = g_type_class_peek_parent (klass);
- provider_class->get_version = gda_sqlite_provider_get_version;
- provider_class->get_server_version = gda_sqlite_provider_get_server_version;
- provider_class->get_name = gda_sqlite_provider_get_name;
- provider_class->supports_feature = gda_sqlite_provider_supports;
-
- provider_class->get_data_handler = gda_sqlite_provider_get_data_handler;
- provider_class->get_def_dbms_type = gda_sqlite_provider_get_default_dbms_type;
-
- provider_class->create_connection = NULL;
- provider_class->identifier_quote = _gda_sqlite_identifier_quote;
- provider_class->open_connection = gda_sqlite_provider_open_connection;
- provider_class->close_connection = gda_sqlite_provider_close_connection;
- provider_class->get_database = gda_sqlite_provider_get_database;
-
- provider_class->supports_operation = gda_sqlite_provider_supports_operation;
- provider_class->create_operation = gda_sqlite_provider_create_operation;
- provider_class->render_operation = gda_sqlite_provider_render_operation;
- provider_class->perform_operation = gda_sqlite_provider_perform_operation;
-
- provider_class->begin_transaction = gda_sqlite_provider_begin_transaction;
- provider_class->commit_transaction = gda_sqlite_provider_commit_transaction;
- provider_class->rollback_transaction = gda_sqlite_provider_rollback_transaction;
- provider_class->add_savepoint = gda_sqlite_provider_add_savepoint;
- provider_class->rollback_savepoint = gda_sqlite_provider_rollback_savepoint;
- provider_class->delete_savepoint = gda_sqlite_provider_delete_savepoint;
-
- provider_class->create_parser = gda_sqlite_provider_create_parser;
- provider_class->statement_to_sql = gda_sqlite_provider_statement_to_sql;
- provider_class->statement_prepare = gda_sqlite_provider_statement_prepare;
- provider_class->statement_execute = gda_sqlite_provider_statement_execute;
- provider_class->statement_rewrite = gda_sqlite_statement_rewrite;
-
- provider_class->escape_string = gda_sqlite_provider_escape_string;
- provider_class->unescape_string = gda_sqlite_provider_unescape_string;
-
- memset (&(provider_class->meta_funcs), 0, sizeof (GdaServerProviderMeta));
- provider_class->meta_funcs._info = _gda_sqlite_meta__info;
- provider_class->meta_funcs._btypes = _gda_sqlite_meta__btypes;
- provider_class->meta_funcs._udt = _gda_sqlite_meta__udt;
- provider_class->meta_funcs.udt = _gda_sqlite_meta_udt;
- provider_class->meta_funcs._udt_cols = _gda_sqlite_meta__udt_cols;
- provider_class->meta_funcs.udt_cols = _gda_sqlite_meta_udt_cols;
- provider_class->meta_funcs._enums = _gda_sqlite_meta__enums;
- provider_class->meta_funcs.enums = _gda_sqlite_meta_enums;
- provider_class->meta_funcs._domains = _gda_sqlite_meta__domains;
- provider_class->meta_funcs.domains = _gda_sqlite_meta_domains;
- provider_class->meta_funcs._constraints_dom = _gda_sqlite_meta__constraints_dom;
- provider_class->meta_funcs.constraints_dom = _gda_sqlite_meta_constraints_dom;
- provider_class->meta_funcs._el_types = _gda_sqlite_meta__el_types;
- provider_class->meta_funcs.el_types = _gda_sqlite_meta_el_types;
- provider_class->meta_funcs._collations = _gda_sqlite_meta__collations;
- provider_class->meta_funcs.collations = _gda_sqlite_meta_collations;
- provider_class->meta_funcs._character_sets = _gda_sqlite_meta__character_sets;
- provider_class->meta_funcs.character_sets = _gda_sqlite_meta_character_sets;
- provider_class->meta_funcs._schemata = _gda_sqlite_meta__schemata;
- provider_class->meta_funcs.schemata = _gda_sqlite_meta_schemata;
- provider_class->meta_funcs._tables_views = _gda_sqlite_meta__tables_views;
- provider_class->meta_funcs.tables_views = _gda_sqlite_meta_tables_views;
- provider_class->meta_funcs._columns = _gda_sqlite_meta__columns;
- provider_class->meta_funcs.columns = _gda_sqlite_meta_columns;
- provider_class->meta_funcs._view_cols = _gda_sqlite_meta__view_cols;
- provider_class->meta_funcs.view_cols = _gda_sqlite_meta_view_cols;
- provider_class->meta_funcs._constraints_tab = _gda_sqlite_meta__constraints_tab;
- provider_class->meta_funcs.constraints_tab = _gda_sqlite_meta_constraints_tab;
- provider_class->meta_funcs._constraints_ref = _gda_sqlite_meta__constraints_ref;
- provider_class->meta_funcs.constraints_ref = _gda_sqlite_meta_constraints_ref;
- provider_class->meta_funcs._key_columns = _gda_sqlite_meta__key_columns;
- provider_class->meta_funcs.key_columns = _gda_sqlite_meta_key_columns;
- provider_class->meta_funcs._check_columns = _gda_sqlite_meta__check_columns;
- provider_class->meta_funcs.check_columns = _gda_sqlite_meta_check_columns;
- provider_class->meta_funcs._triggers = _gda_sqlite_meta__triggers;
- provider_class->meta_funcs.triggers = _gda_sqlite_meta_triggers;
- provider_class->meta_funcs._routines = _gda_sqlite_meta__routines;
- provider_class->meta_funcs.routines = _gda_sqlite_meta_routines;
- provider_class->meta_funcs._routine_col = _gda_sqlite_meta__routine_col;
- provider_class->meta_funcs.routine_col = _gda_sqlite_meta_routine_col;
- provider_class->meta_funcs._routine_par = _gda_sqlite_meta__routine_par;
- provider_class->meta_funcs.routine_par = _gda_sqlite_meta_routine_par;
- provider_class->meta_funcs._indexes_tab = _gda_sqlite_meta__indexes_tab;
- provider_class->meta_funcs.indexes_tab = _gda_sqlite_meta_indexes_tab;
- provider_class->meta_funcs._index_cols = _gda_sqlite_meta__index_cols;
- provider_class->meta_funcs.index_cols = _gda_sqlite_meta_index_cols;
-
- /* SQLite doe not support distributed transactions */
- provider_class->xa_funcs = NULL;
-
- /* If SQLite was not compiled with the SQLITE_THREADSAFE flag, then it is not
- * considered thread safe, and we limit the usage of the provider from the current thread */
- if (! SQLITE3_CALL (sqlite3_threadsafe) ()) {
- gda_log_message ("SQLite was not compiled with the SQLITE_THREADSAFE flag, "
- "only one thread can access the provider");
- provider_class->limiting_thread = GDA_SERVER_PROVIDER_UNDEFINED_LIMITING_THREAD;
- }
- else
- provider_class->limiting_thread = NULL;
+ /* set virtual functions */
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_BASE,
+ (gpointer) &sqlite_base_functions);
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_META,
+ (gpointer) &sqlite_meta_functions);
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_XA,
+ NULL);
}
static void
@@ -645,6 +641,21 @@ gda_sqlite_provider_get_type (void)
return type;
}
+static GdaWorker *
+gda_sqlite_provider_create_worker (GdaServerProvider *provider)
+{
+ static GdaWorker *unique_worker = NULL;
+ if (unique_worker)
+ return gda_worker_ref (unique_worker);
+
+ if (SQLITE3_CALL (sqlite3_threadsafe) ())
+ return gda_worker_new ();
+ else {
+ unique_worker = gda_worker_new ();
+ return gda_worker_ref (unique_worker);
+ }
+}
+
/*
* Get provider name request
*/
@@ -717,18 +728,15 @@ remove_diacritics_and_change_case (const gchar *str, gssize len, CaseModif cmod)
*/
static gboolean
gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
- GdaQuarkList *params, G_GNUC_UNUSED GdaQuarkList *auth,
- G_GNUC_UNUSED guint *task_id, GdaServerProviderAsyncCallback async_cb,
G_GNUC_UNUSED gpointer cb_data)
+ GdaQuarkList *params, G_GNUC_UNUSED GdaQuarkList *auth)
{
gchar *filename = NULL;
const gchar *dirname = NULL, *dbname = NULL;
const gchar *is_virtual = NULL;
const gchar *append_extension = NULL;
- const gchar *use_extra_functions = NULL, *with_fk = NULL, *regexp, *locale_collate, *extensions;
gint errmsg;
SqliteConnectionData *cdata;
gchar *dup = NULL;
- static GMutex cnc_mutex;
#ifdef SQLITE_HAS_CODEC
const gchar *passphrase = NULL;
#endif
@@ -736,13 +744,6 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
g_return_val_if_fail (GDA_IS_SQLITE_PROVIDER (provider), FALSE);
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
- if (async_cb) {
- gda_connection_add_event_string (cnc, _("Provider does not support asynchronous connection
open"));
- return FALSE;
- }
-
- g_mutex_lock (&cnc_mutex);
-
/* get all parameters received */
dirname = gda_quark_list_find (params, "DB_DIR");
if (!dirname)
@@ -750,14 +751,6 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
dbname = gda_quark_list_find (params, "DB_NAME");
append_extension = gda_quark_list_find (params, "APPEND_DB_EXTENSION");
is_virtual = gda_quark_list_find (params, "_IS_VIRTUAL");
- with_fk = gda_quark_list_find (params, "FK");
- use_extra_functions = gda_quark_list_find (params, "EXTRA_FUNCTIONS");
- if (!use_extra_functions)
- use_extra_functions = gda_quark_list_find (params, "LOAD_GDA_FUNCTIONS");
-
- regexp = gda_quark_list_find (params, "REGEXP");
- locale_collate = gda_quark_list_find (params, "EXTRA_COLLATIONS");
- extensions = gda_quark_list_find (params, "EXTENSIONS");
if (! is_virtual) {
if (!dbname) {
@@ -767,7 +760,6 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
if (!str) {
gda_connection_add_event_string (cnc,
_("The connection string must contain DB_DIR
and DB_NAME values"));
- g_mutex_unlock (&cnc_mutex);
return FALSE;
}
else {
@@ -797,7 +789,6 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
"DB_DIR (the path to the database
file) and DB_NAME "
"(the database file without the
'%s' at the end)."), FILE_EXTENSION);
g_free (dup);
- g_mutex_unlock (&cnc_mutex);
return FALSE;
}
else
@@ -819,7 +810,6 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
_("The DB_DIR part of the connection string
must point "
"to a valid directory"));
g_free (dup);
- g_mutex_unlock (&cnc_mutex);
return FALSE;
}
@@ -864,7 +854,6 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
gda_connection_add_event_string (cnc, SQLITE3_CALL (sqlite3_errmsg) (cdata->connection));
gda_sqlite_free_cnc_data (cdata);
- g_mutex_unlock (&cnc_mutex);
return FALSE;
}
@@ -880,13 +869,32 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
if (errmsg != SQLITE_OK) {
gda_connection_add_event_string (cnc, _("Wrong encryption passphrase"));
gda_sqlite_free_cnc_data (cdata);
- g_mutex_unlock (&cnc_mutex);
return FALSE;
}
}
#endif
- gda_connection_internal_set_provider_data (cnc, cdata, (GDestroyNotify) gda_sqlite_free_cnc_data);
+ gda_connection_internal_set_provider_data (cnc, (GdaServerProviderConnectionData*) cdata,
+ (GDestroyNotify) gda_sqlite_free_cnc_data);
+ return TRUE;
+}
+
+static gboolean
+gda_sqlite_provider_prepare_connection (GdaServerProvider *provider, GdaConnection *cnc, GdaQuarkList
*params, G_GNUC_UNUSED GdaQuarkList *auth)
+{
+ SqliteConnectionData *cdata;
+ cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata)
+ return FALSE;
+
+ const gchar *use_extra_functions = NULL, *with_fk = NULL, *regexp, *locale_collate, *extensions;
+ with_fk = gda_quark_list_find (params, "FK");
+ use_extra_functions = gda_quark_list_find (params, "EXTRA_FUNCTIONS");
+ if (!use_extra_functions)
+ use_extra_functions = gda_quark_list_find (params, "LOAD_GDA_FUNCTIONS");
+ regexp = gda_quark_list_find (params, "REGEXP");
+ locale_collate = gda_quark_list_find (params, "EXTRA_COLLATIONS");
+ extensions = gda_quark_list_find (params, "EXTENSIONS");
/* use extended result codes */
SQLITE3_CALL (sqlite3_extended_result_codes) (cdata->connection, 1);
@@ -901,7 +909,6 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
else {
gda_connection_add_event_string (cnc, _("Extension loading is not supported"));
gda_sqlite_free_cnc_data (cdata);
- g_mutex_unlock (&cnc_mutex);
return FALSE;
}
}
@@ -909,7 +916,8 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
/* try to prepare all the internal statements */
InternalStatementItem i;
for (i = INTERNAL_PRAGMA_INDEX_LIST; i < sizeof (internal_sql) / sizeof (gchar*); i++)
- gda_connection_statement_prepare (cnc, internal_stmt[i], NULL);
+ gda_connection_statement_prepare (cnc, internal_stmt[i], NULL); /* Note: some may fail because
+ * the SQL cannot
be "prepared" */
/* set SQLite library options */
GObject *obj;
@@ -947,7 +955,6 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
SQLITE3_CALL (sqlite3_free) (errmsg);
gda_sqlite_free_cnc_data (cdata);
gda_connection_internal_set_provider_data (cnc, NULL, (GDestroyNotify)
gda_sqlite_free_cnc_data);
- g_mutex_unlock (&cnc_mutex);
return FALSE;
}
}
@@ -972,7 +979,6 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
gda_sqlite_free_cnc_data (cdata);
gda_connection_internal_set_provider_data (cnc, NULL,
(GDestroyNotify) gda_sqlite_free_cnc_data);
- g_mutex_unlock (&cnc_mutex);
return FALSE;
}
}
@@ -985,7 +991,6 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
gda_sqlite_free_cnc_data (cdata);
gda_connection_internal_set_provider_data (cnc, NULL,
(GDestroyNotify) gda_sqlite_free_cnc_data);
- g_mutex_unlock (&cnc_mutex);
return FALSE;
}
}
@@ -1013,7 +1018,6 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
func->name);
gda_sqlite_free_cnc_data (cdata);
gda_connection_internal_set_provider_data (cnc, NULL, (GDestroyNotify)
gda_sqlite_free_cnc_data);
- g_mutex_unlock (&cnc_mutex);
return FALSE;
}
}
@@ -1033,7 +1037,6 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
func->name);
gda_sqlite_free_cnc_data (cdata);
gda_connection_internal_set_provider_data (cnc, NULL, (GDestroyNotify)
gda_sqlite_free_cnc_data);
- g_mutex_unlock (&cnc_mutex);
return FALSE;
}
}
@@ -1052,18 +1055,11 @@ gda_sqlite_provider_open_connection (GdaServerProvider *provider, GdaConnection
func->name);
gda_sqlite_free_cnc_data (cdata);
gda_connection_internal_set_provider_data (cnc, NULL, (GDestroyNotify)
gda_sqlite_free_cnc_data);
- g_mutex_unlock (&cnc_mutex);
return FALSE;
}
}
}
- if (SQLITE3_CALL (sqlite3_threadsafe) ())
- g_object_set (G_OBJECT (cnc), "thread-owner", NULL, NULL);
- else
- g_object_set (G_OBJECT (cnc), "thread-owner", g_thread_self (), NULL);
-
- g_mutex_unlock (&cnc_mutex);
return TRUE;
}
@@ -1141,7 +1137,7 @@ gda_sqlite_provider_get_database (GdaServerProvider *provider, GdaConnection *cn
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
- cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
return cdata->file;
@@ -1305,17 +1301,9 @@ gda_sqlite_provider_render_operation (GdaServerProvider *provider, GdaConnection
*/
static gboolean
gda_sqlite_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
- GdaServerOperation *op, G_GNUC_UNUSED guint *task_id,
GdaServerProviderAsyncCallback async_cb,
- G_GNUC_UNUSED gpointer cb_data, GError **error)
+ GdaServerOperation *op, GError **error)
{
GdaServerOperationType optype;
-
- if (async_cb) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
- "%s", _("Provider does not support asynchronous server operation"));
- return FALSE;
- }
-
optype = gda_server_operation_get_op_type (op);
switch (optype) {
case GDA_SERVER_OPERATION_CREATE_DB: {
@@ -1667,9 +1655,9 @@ gda_sqlite_provider_delete_savepoint (GdaServerProvider *provider, GdaConnection
* Feature support request
*/
static gboolean
-gda_sqlite_provider_supports (GdaServerProvider *provider,
- GdaConnection *cnc,
- GdaConnectionFeature feature)
+gda_sqlite_provider_supports_feature (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GdaConnectionFeature feature)
{
if (cnc) {
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
@@ -1685,8 +1673,6 @@ gda_sqlite_provider_supports (GdaServerProvider *provider,
case GDA_CONNECTION_FEATURE_VIEWS :
case GDA_CONNECTION_FEATURE_PROCEDURES :
return TRUE;
- case GDA_CONNECTION_FEATURE_MULTI_THREADING:
- return SQLITE3_CALL (sqlite3_threadsafe) () ? TRUE : FALSE;
default:
return FALSE;
}
@@ -2853,7 +2839,7 @@ fill_blob_data (GdaConnection *cnc, GdaSet *params,
if (rowid >= 0) {
/*g_print ("Filling BLOB @ %s.%s.%s, rowID %ld\n", pb->db, pb->table, pb->column,
rowid);*/
GdaSqliteBlobOp *bop;
- bop = (GdaSqliteBlobOp*) _gda_sqlite_blob_op_new (cdata, pb->db, pb->table,
pb->column, rowid);
+ bop = (GdaSqliteBlobOp*) _gda_sqlite_blob_op_new (cnc, pb->db, pb->table, pb->column,
rowid);
if (!bop) {
cstr = _("Can't create SQLite BLOB handle");
goto blobs_out;
@@ -2890,7 +2876,7 @@ fill_blob_data (GdaConnection *cnc, GdaSet *params,
goto blobs_out;
}
GdaSqliteBlobOp *bop;
- bop = (GdaSqliteBlobOp*) _gda_sqlite_blob_op_new (cdata, pb->db, pb->table,
pb->column, rowid);
+ bop = (GdaSqliteBlobOp*) _gda_sqlite_blob_op_new (cnc, pb->db, pb->table,
pb->column, rowid);
if (!bop) {
cstr = _("Can't create SQLite BLOB handle");
g_object_unref (model);
@@ -2938,9 +2924,7 @@ static GObject *
gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
GdaStatement *stmt, GdaSet *params,
GdaStatementModelUsage model_usage,
- GType *col_types, GdaSet **last_inserted_row,
- guint *task_id, GdaServerProviderExecCallback async_cb,
- gpointer cb_data, GError **error)
+ GType *col_types, GdaSet **last_inserted_row, GError **error)
{
GdaSqlitePStmt *ps;
SqliteConnectionData *cdata;
@@ -2953,12 +2937,6 @@ gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
- if (async_cb) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
- "%s", _("Provider does not support asynchronous statement execution"));
- return NULL;
- }
-
allow_noparam = (model_usage & GDA_STATEMENT_MODEL_ALLOW_NOPARAM) &&
(gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT);
@@ -3144,9 +3122,7 @@ gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
res = gda_sqlite_provider_statement_execute (provider, cnc,
rstmt, params,
model_usage,
- col_types, last_inserted_row,
- task_id,
- async_cb, cb_data, error);
+ col_types, last_inserted_row, error);
g_object_unref (rstmt);
return res;
}
@@ -3191,9 +3167,7 @@ gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
rstmt, params,
model_usage,
col_types,
- last_inserted_row,
- task_id, async_cb,
- cb_data, error);
+ last_inserted_row, error);
/* clear original @param_ids and restore copied one */
g_slist_foreach (prep_param_ids, (GFunc) g_free, NULL);
g_slist_free (prep_param_ids);
@@ -3578,8 +3552,8 @@ gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
* Removes any default value inserted or updated
*/
static GdaSqlStatement *
-gda_sqlite_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
- GdaStatement *stmt, GdaSet *params, GError **error)
+gda_sqlite_provider_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error)
{
if (cnc) {
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
diff --git a/libgda/sqlite/gda-sqlite-recordset.c b/libgda/sqlite/gda-sqlite-recordset.c
index e1c0376..6b207c1 100644
--- a/libgda/sqlite/gda-sqlite-recordset.c
+++ b/libgda/sqlite/gda-sqlite-recordset.c
@@ -219,7 +219,7 @@ _gda_sqlite_recordset_new (GdaConnection *cnc, GdaSqlitePStmt *ps, GdaSet *exec_
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (ps != NULL, NULL);
- cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
@@ -287,7 +287,8 @@ _gda_sqlite_recordset_new (GdaConnection *cnc, GdaSqlitePStmt *ps, GdaSet *exec_
rflags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD;
/* create data model */
- model = g_object_new (GDA_TYPE_SQLITE_RECORDSET, "connection", cnc,
+ model = g_object_new (GDA_TYPE_SQLITE_RECORDSET,
+ "connection", cnc,
"prepared-stmt", ps, "model-usage", rflags,
"exec-params", exec_params,
"auto-reset", force_empty, NULL);
@@ -349,9 +350,10 @@ fetch_next_sqlite_row (GdaSqliteRecordset *model, gboolean do_store, GError **er
SqliteConnectionData *cdata;
GdaSqlitePStmt *ps;
GdaRow *prow = NULL;
+ GdaConnection *cnc;
- cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error
- (gda_data_select_get_connection ((GdaDataSelect*) model), error);
+ cnc = gda_data_select_get_connection ((GdaDataSelect*) model);
+ cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
if (!cdata)
return NULL;
ps = GDA_SQLITE_PSTMT (GDA_DATA_SELECT (model)->prep_stmt);
@@ -497,7 +499,7 @@ fetch_next_sqlite_row (GdaSqliteRecordset *model, gboolean do_store, GError **er
gint64 rowid;
rowid = SQLITE3_CALL (sqlite3_column_int64) (ps->sqlite_stmt,
oidcol - 1); /* remove 1
because it was added in the first place */
- bop = _gda_sqlite_blob_op_new (cdata,
+ bop = _gda_sqlite_blob_op_new (cnc,
SQLITE3_CALL
(sqlite3_column_database_name) (ps->sqlite_stmt,
real_col),
SQLITE3_CALL
(sqlite3_column_table_name) (ps->sqlite_stmt,
diff --git a/libgda/sqlite/gda-sqlite-recordset.h b/libgda/sqlite/gda-sqlite-recordset.h
index 31d9759..c5dbebe 100644
--- a/libgda/sqlite/gda-sqlite-recordset.h
+++ b/libgda/sqlite/gda-sqlite-recordset.h
@@ -52,8 +52,8 @@ struct _GdaSqliteRecordsetClass {
GType _gda_sqlite_recordset_get_type (void) G_GNUC_CONST;
GdaDataModel *_gda_sqlite_recordset_new (GdaConnection *cnc, GdaSqlitePStmt *ps, GdaSet *exec_params,
- GdaDataModelAccessFlags flags, GType *col_types,
- gboolean force_empty);
+ GdaDataModelAccessFlags flags, GType *col_types,
+ gboolean force_empty);
G_END_DECLS
diff --git a/libgda/sqlite/gda-sqlite.h b/libgda/sqlite/gda-sqlite.h
index 5bf569d..e4660b6 100644
--- a/libgda/sqlite/gda-sqlite.h
+++ b/libgda/sqlite/gda-sqlite.h
@@ -27,6 +27,7 @@
#include <glib.h>
#include <libgda/libgda.h>
+#include <libgda/gda-connection-private.h>
#ifdef WITH_BDBSQLITE
#include <dbsql.h>
@@ -55,6 +56,7 @@
* Provider's specific connection data
*/
typedef struct {
+ GdaServerProviderConnectionData parent;
GdaConnection *gdacnc;
sqlite3 *connection;
gchar *file;
diff --git a/libgda/sqlite/virtual/gda-vconnection-data-model.c
b/libgda/sqlite/virtual/gda-vconnection-data-model.c
index c6f522e..08319c2 100644
--- a/libgda/sqlite/virtual/gda-vconnection-data-model.c
+++ b/libgda/sqlite/virtual/gda-vconnection-data-model.c
@@ -158,7 +158,7 @@ gda_vconnection_data_model_dispose (GObject *object)
td = (GdaVConnectionTableData *) cnc->priv->table_data_list->data;
get_rid_of_vtable (cnc, td, TRUE, NULL);
}
- gda_connection_close_no_warning ((GdaConnection *) cnc);
+ _gda_connection_close_no_warning ((GdaConnection *) cnc, NULL);
g_mutex_clear (& (cnc->priv->lock_context));
g_free (cnc->priv);
diff --git a/libgda/sqlite/virtual/gda-vconnection-hub.c b/libgda/sqlite/virtual/gda-vconnection-hub.c
index 87eb19e..bbf3672 100644
--- a/libgda/sqlite/virtual/gda-vconnection-hub.c
+++ b/libgda/sqlite/virtual/gda-vconnection-hub.c
@@ -29,6 +29,7 @@
#include <libgda/gda-data-select.h>
#include <gda-sql-builder.h>
#include "../gda-sqlite.h"
+#include <libgda/gda-connection-internal.h>
typedef struct {
GdaVconnectionHub *hub;
@@ -86,7 +87,7 @@ gda_vconnection_hub_dispose (GObject *object)
/* free memory */
if (cnc->priv) {
- gda_connection_close_no_warning ((GdaConnection *) cnc);
+ _gda_connection_close_no_warning ((GdaConnection *) cnc, NULL);
g_assert (!cnc->priv->hub_connections);
g_free (cnc->priv);
diff --git a/libgda/sqlite/virtual/gda-virtual-connection.c b/libgda/sqlite/virtual/gda-virtual-connection.c
index e04df44..c832662 100644
--- a/libgda/sqlite/virtual/gda-virtual-connection.c
+++ b/libgda/sqlite/virtual/gda-virtual-connection.c
@@ -23,8 +23,9 @@
#include <string.h>
#include "gda-virtual-connection.h"
#include <gda-connection-private.h>
+#include <libgda/gda-server-provider-private.h>
#include <libgda/gda-connection-internal.h>
-#include <libgda/thread-wrapper/gda-thread-provider.h>
+#include <libgda/gda-debug-macros.h>
#define PARENT_TYPE GDA_TYPE_CONNECTION
#define CLASS(obj) (GDA_VIRTUAL_CONNECTION_CLASS (G_OBJECT_GET_CLASS (obj)))
@@ -130,73 +131,23 @@ gda_virtual_connection_get_type (void)
* Returns: a new #GdaConnection object, or %NULL if an error occurred
*/
GdaConnection *
-gda_virtual_connection_open (GdaVirtualProvider *virtual_provider, GError **error)
+gda_virtual_connection_open (GdaVirtualProvider *virtual_provider, GdaConnectionOptions options, GError
**error)
{
- GdaConnection *cnc = NULL;
g_return_val_if_fail (GDA_IS_VIRTUAL_PROVIDER (virtual_provider), NULL);
- if (PROV_CLASS (virtual_provider)->create_connection) {
- cnc = PROV_CLASS (virtual_provider)->create_connection ((GdaServerProvider*)
virtual_provider);
- if (cnc) {
- g_object_set (G_OBJECT (cnc), "provider", virtual_provider, NULL);
- if (!gda_connection_open (cnc, error)) {
- g_object_unref (cnc);
- cnc = NULL;
- }
+ GdaConnection *cnc;
+ cnc = _gda_server_provider_create_connection (GDA_SERVER_PROVIDER (virtual_provider), NULL, NULL,
+ NULL, options);
+ if (cnc) {
+ g_object_set (G_OBJECT (cnc), "provider", virtual_provider, NULL);
+ if (!gda_connection_open (cnc, error)) {
+ g_object_unref (cnc);
+ cnc = NULL;
}
}
else
g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_PROVIDER_ERROR, "%s",
_("Internal error: virtual provider does not implement the create_operation()
virtual method"));
- return cnc;
-}
-
-/**
- * gda_virtual_connection_open_extended
- * @virtual_provider: a #GdaVirtualProvider object
- * @options: a set of options to specify the new connection
- * @error: a place to store errors, or %NULL
- *
- * Creates and opens a new virtual connection using the @virtual_provider provider. If @options
- * contains the %GDA_CONNECTION_OPTIONS_THREAD_ISOLATED flag, then the returned connection will be
- * a thread wrapped connection, and the actual (wrapped) virtual connection can be obtained through
- * the "gda-virtual-connection" user property (use g_object_get_data() to get it).
- *
- * The returned value is a new #GdaVirtualConnection which needs to be used to actually add some
- * contents to the virtual connection.
- *
- * Returns: a new #GdaConnection object, or %NULL if an error occurred
- */
-GdaConnection *
-gda_virtual_connection_open_extended (GdaVirtualProvider *virtual_provider, GdaConnectionOptions options,
GError **error)
-{
- GdaConnection *cnc = NULL;
- g_return_val_if_fail (GDA_IS_VIRTUAL_PROVIDER (virtual_provider), NULL);
-
- if (PROV_CLASS (virtual_provider)->create_connection) {
- cnc = PROV_CLASS (virtual_provider)->create_connection ((GdaServerProvider*)
virtual_provider);
- if (cnc) {
- g_object_set (G_OBJECT (cnc), "provider", virtual_provider,
- "options",
- options & (~ (GDA_CONNECTION_OPTIONS_THREAD_ISOLATED |
GDA_CONNECTION_OPTIONS_THREAD_SAFE)), NULL);
- if (!gda_connection_open (cnc, error)) {
- g_object_unref (cnc);
- cnc = NULL;
- }
- }
- }
- else
- g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_PROVIDER_ERROR, "%s",
- _("Internal error: virtual provider does not implement the create_operation()
virtual method"));
-
- if (cnc && (options & GDA_CONNECTION_OPTIONS_THREAD_ISOLATED)) {
- GdaConnection *wcnc;
- wcnc = _gda_thread_provider_handle_virtual_connection (GDA_THREAD_PROVIDER
(_gda_connection_get_internal_thread_provider ()),
- cnc);
- g_object_set_data (G_OBJECT (wcnc), "gda-virtual-connection", cnc);
- g_object_unref (cnc);
- cnc = wcnc;
- }
return cnc;
}
diff --git a/libgda/sqlite/virtual/gda-virtual-connection.h b/libgda/sqlite/virtual/gda-virtual-connection.h
index b08f0e0..da0c873 100644
--- a/libgda/sqlite/virtual/gda-virtual-connection.h
+++ b/libgda/sqlite/virtual/gda-virtual-connection.h
@@ -62,9 +62,8 @@ struct _GdaVirtualConnectionClass {
*/
GType gda_virtual_connection_get_type (void) G_GNUC_CONST;
-GdaConnection *gda_virtual_connection_open (GdaVirtualProvider *virtual_provider,
GError **error);
-GdaConnection *gda_virtual_connection_open_extended (GdaVirtualProvider *virtual_provider,
- GdaConnectionOptions options, GError
**error);
+GdaConnection *gda_virtual_connection_open (GdaVirtualProvider *virtual_provider,
GdaConnectionOptions options,
+ GError **error);
void gda_virtual_connection_internal_set_provider_data (GdaVirtualConnection *vcnc,
gpointer data, GDestroyNotify destroy_func);
gpointer gda_virtual_connection_internal_get_provider_data (GdaVirtualConnection *vcnc);
diff --git a/libgda/sqlite/virtual/gda-virtual-provider.c b/libgda/sqlite/virtual/gda-virtual-provider.c
index d9955b0..88f9e98 100644
--- a/libgda/sqlite/virtual/gda-virtual-provider.c
+++ b/libgda/sqlite/virtual/gda-virtual-provider.c
@@ -23,6 +23,8 @@
#include <string.h>
#include <sqlite3.h>
#include "gda-virtual-provider.h"
+#include <libgda/gda-debug-macros.h>
+#include <libgda/gda-server-provider-impl.h>
#define PARENT_TYPE GDA_TYPE_SQLITE_PROVIDER
#define CLASS(obj) (GDA_VIRTUAL_PROVIDER_CLASS (G_OBJECT_GET_CLASS (obj)))
@@ -32,9 +34,6 @@ static void gda_virtual_provider_init (GdaVirtualProvider *prov, GdaVirtua
static void gda_virtual_provider_finalize (GObject *object);
static GObjectClass *parent_class = NULL;
-static gboolean gda_virtual_provider_close_connection (GdaServerProvider *prov,
- GdaConnection *cnc);
-
/*
* GdaVirtualProvider class implementation
*/
@@ -46,9 +45,12 @@ gda_virtual_provider_class_init (GdaVirtualProviderClass *klass)
parent_class = g_type_class_peek_parent (klass);
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_BASE,
+ (gpointer) NULL);
+
/* virtual methods */
object_class->finalize = gda_virtual_provider_finalize;
- prov_class->close_connection = gda_virtual_provider_close_connection;
}
static void
@@ -67,13 +69,6 @@ gda_virtual_provider_finalize (GObject *object)
parent_class->finalize (object);
}
-static gboolean
-gda_virtual_provider_close_connection (GdaServerProvider *prov, GdaConnection *cnc)
-{
- g_return_val_if_fail (GDA_IS_VIRTUAL_PROVIDER (prov), FALSE);
- return GDA_SERVER_PROVIDER_CLASS (parent_class)->close_connection (prov, cnc);
-}
-
GType
gda_virtual_provider_get_type (void)
{
diff --git a/libgda/sqlite/virtual/gda-virtual-provider.h b/libgda/sqlite/virtual/gda-virtual-provider.h
index b2a32a4..3f7720b 100644
--- a/libgda/sqlite/virtual/gda-virtual-provider.h
+++ b/libgda/sqlite/virtual/gda-virtual-provider.h
@@ -37,18 +37,18 @@ typedef struct _GdaVirtualProviderClass GdaVirtualProviderClass;
struct _GdaVirtualProvider {
GdaSqliteProvider provider;
+
/*< private >*/
- void (*_gda_reserved1) (void);
+ void (*_gda_reserved1) (void);
+ void (*_gda_reserved2) (void);
};
struct _GdaVirtualProviderClass {
GdaSqliteProviderClass parent_class;
/*< private >*/
- /* Padding for future expansion */
void (*_gda_reserved1) (void);
- void (*_gda_reserved2) (void);
-};
+ void (*_gda_reserved2) (void);};
/**
* SECTION:gda-virtual-provider
diff --git a/libgda/sqlite/virtual/gda-vprovider-data-model.c
b/libgda/sqlite/virtual/gda-vprovider-data-model.c
index 649cde4..6a3ef39 100644
--- a/libgda/sqlite/virtual/gda-vprovider-data-model.c
+++ b/libgda/sqlite/virtual/gda-vprovider-data-model.c
@@ -32,6 +32,7 @@
#include "../gda-sqlite.h"
#include <sql-parser/gda-statement-struct-util.h>
#include <libgda/gda-debug-macros.h>
+#include <libgda/gda-server-provider-impl.h>
#define GDA_DEBUG_VIRTUAL
#undef GDA_DEBUG_VIRTUAL
@@ -47,17 +48,14 @@ static GObjectClass *parent_class = NULL;
static GdaConnection *gda_vprovider_data_model_create_connection (GdaServerProvider *provider);
static gboolean gda_vprovider_data_model_open_connection (GdaServerProvider *provider, GdaConnection
*cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- guint *task_id,
GdaServerProviderAsyncCallback async_cb,
- gpointer cb_data);
+ GdaQuarkList *params, GdaQuarkList *auth);
static gboolean gda_vprovider_data_model_close_connection (GdaServerProvider *provider,
GdaConnection *cnc);
static GObject *gda_vprovider_data_model_statement_execute (GdaServerProvider *provider,
GdaConnection *cnc,
GdaStatement *stmt, GdaSet *params,
GdaStatementModelUsage model_usage,
GType *col_types, GdaSet
**last_inserted_row,
- guint *task_id,
GdaServerProviderExecCallback async_cb,
- gpointer cb_data, GError **error);
+ GError **error);
static const gchar *gda_vprovider_data_model_get_name (GdaServerProvider *provider);
static GValue **create_gvalues_array_from_sqlite3_array (int argc, sqlite3_value **argv);
@@ -66,29 +64,57 @@ static GValue **create_gvalues_array_from_sqlite3_array (int argc, sqlite3_value
/*
* GdaVproviderDataModel class implementation
*/
+GdaServerProviderBase data_model_base_functions = {
+ gda_vprovider_data_model_get_name,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ gda_vprovider_data_model_create_connection,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ gda_vprovider_data_model_open_connection,
+ NULL,
+ gda_vprovider_data_model_close_connection,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ gda_vprovider_data_model_statement_execute,
+
+ NULL, NULL, NULL, NULL, /* padding */
+};
+
static void
gda_vprovider_data_model_class_init (GdaVproviderDataModelClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GdaServerProviderClass *server_class = GDA_SERVER_PROVIDER_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
+ /* set virtual functions */
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_BASE,
+ (gpointer) &data_model_base_functions);
+
object_class->finalize = gda_vprovider_data_model_finalize;
- server_class->create_connection = gda_vprovider_data_model_create_connection;
- server_class->open_connection = gda_vprovider_data_model_open_connection;
- server_class->close_connection = gda_vprovider_data_model_close_connection;
- server_class->statement_execute = gda_vprovider_data_model_statement_execute;
-
- server_class->get_name = gda_vprovider_data_model_get_name;
-
- /* explicitly unimplement the DDL queries */
- server_class->supports_operation = NULL;
- server_class->create_operation = NULL;
- server_class->render_operation = NULL;
- server_class->perform_operation = NULL;
}
+
static void
gda_vprovider_data_model_init (GdaVproviderDataModel *prov, G_GNUC_UNUSED GdaVproviderDataModelClass *klass)
{
@@ -362,19 +388,13 @@ gda_vprovider_data_model_create_connection (GdaServerProvider *provider)
static gboolean
gda_vprovider_data_model_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- G_GNUC_UNUSED guint *task_id, GdaServerProviderAsyncCallback
async_cb, G_GNUC_UNUSED gpointer cb_data)
+ GdaQuarkList *params, GdaQuarkList *auth)
{
GdaQuarkList *m_params;
g_return_val_if_fail (GDA_IS_VPROVIDER_DATA_MODEL (provider), FALSE);
g_return_val_if_fail (GDA_IS_VCONNECTION_DATA_MODEL (cnc), FALSE);
- if (async_cb) {
- gda_connection_add_event_string (cnc, _("Provider does not support asynchronous connection
open"));
- return FALSE;
- }
-
if (params) {
m_params = gda_quark_list_copy (params);
gda_quark_list_add_from_string (m_params, "_IS_VIRTUAL=TRUE;EXTRA_FUNCTIONS=TRUE", TRUE);
@@ -382,23 +402,21 @@ gda_vprovider_data_model_open_connection (GdaServerProvider *provider, GdaConnec
else
m_params = gda_quark_list_new_from_string ("_IS_VIRTUAL=TRUE;EXTRA_FUNCTIONS=TRUE");
- if (! GDA_SERVER_PROVIDER_CLASS (parent_class)->open_connection (GDA_SERVER_PROVIDER (provider), cnc,
m_params,
- auth, NULL, NULL, NULL)) {
- if (auth)
- gda_quark_list_protect_values (auth);
+ GdaServerProviderBase *parent_functions;
+ parent_functions = gda_server_provider_get_impl_functions_for_class (parent_class,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+
+ if (! parent_functions->open_connection (GDA_SERVER_PROVIDER (provider), cnc, m_params, auth)) {
gda_quark_list_free (m_params);
return FALSE;
}
- if (auth)
- gda_quark_list_protect_values (auth);
+
gda_quark_list_free (m_params);
SqliteConnectionData *scnc;
- scnc = (SqliteConnectionData*) gda_connection_internal_get_provider_data ((GdaConnection *) cnc);
+ scnc = (SqliteConnectionData*) gda_connection_internal_get_provider_data_error ((GdaConnection *)
cnc, NULL);
if (!scnc) {
- gda_connection_close_no_warning (cnc);
- gda_connection_add_event_string (cnc,
- _("Connection is closed"));
+ _gda_connection_close_no_warning (cnc, NULL);
+ gda_connection_add_event_string (cnc, _("Connection is closed"));
return FALSE;
}
@@ -431,29 +449,25 @@ gda_vprovider_data_model_close_connection (GdaServerProvider *provider, GdaConne
gda_vconnection_data_model_foreach (GDA_VCONNECTION_DATA_MODEL (cnc),
(GdaVconnectionDataModelFunc) cnc_close_foreach_func, cnc);
- return GDA_SERVER_PROVIDER_CLASS (parent_class)->close_connection (GDA_SERVER_PROVIDER (provider),
cnc);
+ GdaServerProviderBase *parent_functions;
+ parent_functions = gda_server_provider_get_impl_functions_for_class (parent_class,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+ return parent_functions->close_connection (provider, cnc);
}
static GObject *
gda_vprovider_data_model_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
GdaStatement *stmt, GdaSet *params,
GdaStatementModelUsage model_usage,
- GType *col_types, GdaSet **last_inserted_row,
- guint *task_id, GdaServerProviderExecCallback async_cb,
- gpointer cb_data, GError **error)
+ GType *col_types, GdaSet **last_inserted_row,GError **error)
{
- GObject *retval;
- if (async_cb) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
- "%s", _("Provider does not support asynchronous statement execution"));
- return NULL;
- }
-
+ GObject *retval = NULL;
_gda_vconnection_set_working_obj ((GdaVconnectionDataModel*) cnc, (GObject*) stmt);
- retval = GDA_SERVER_PROVIDER_CLASS (parent_class)->statement_execute (provider, cnc, stmt, params,
- model_usage, col_types,
- last_inserted_row, task_id,
- async_cb, cb_data, error);
+
+ GdaServerProviderBase *parent_functions;
+ parent_functions = gda_server_provider_get_impl_functions_for_class (parent_class,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+ retval = parent_functions->statement_execute (provider, cnc, stmt, params,
+ model_usage, col_types,
+ last_inserted_row, error);
if (retval) {
if (! GDA_IS_DATA_MODEL (retval))
@@ -511,7 +525,7 @@ gda_vprovider_data_model_statement_execute (GdaServerProvider *provider, GdaConn
static const gchar *
gda_vprovider_data_model_get_name (G_GNUC_UNUSED GdaServerProvider *provider)
{
- return "Virtual";
+ return "Virtual data model";
}
static int
diff --git a/libgda/sqlite/virtual/gda-vprovider-data-model.h
b/libgda/sqlite/virtual/gda-vprovider-data-model.h
index 9d0c1ba..3ad908d 100644
--- a/libgda/sqlite/virtual/gda-vprovider-data-model.h
+++ b/libgda/sqlite/virtual/gda-vprovider-data-model.h
@@ -43,7 +43,6 @@ struct _GdaVproviderDataModelClass {
GdaVirtualProviderClass parent_class;
/*< private >*/
- /* Padding for future expansion */
void (*_gda_reserved1) (void);
void (*_gda_reserved2) (void);
void (*_gda_reserved3) (void);
diff --git a/libgda/sqlite/virtual/gda-vprovider-hub.c b/libgda/sqlite/virtual/gda-vprovider-hub.c
index 90e95be..2517d9e 100644
--- a/libgda/sqlite/virtual/gda-vprovider-hub.c
+++ b/libgda/sqlite/virtual/gda-vprovider-hub.c
@@ -22,6 +22,8 @@
#include <string.h>
#include "gda-vprovider-hub.h"
#include "gda-vconnection-hub.h"
+#include <libgda/gda-debug-macros.h>
+#include <libgda/gda-server-provider-impl.h>
struct _GdaVproviderHubPrivate {
int foo;
@@ -47,34 +49,68 @@ static void gda_vprovider_hub_get_property (GObject *object,
static GObjectClass *parent_class = NULL;
static GdaConnection *gda_vprovider_hub_create_connection (GdaServerProvider *provider);
-static gboolean gda_vprovider_hub_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- guint *task_id, GdaServerProviderAsyncCallback
async_cb,
- gpointer cb_data);
static gboolean gda_vprovider_hub_close_connection (GdaServerProvider *provider, GdaConnection *cnc);
+static const gchar *gda_vprovider_hub_get_name (GdaServerProvider *provider);
/*
* GdaVproviderHub class implementation
*/
+static GdaServerProviderBase hub_base_functions = {
+ gda_vprovider_hub_get_name,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ gda_vprovider_hub_create_connection,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ gda_vprovider_hub_close_connection,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ NULL, NULL, NULL, NULL, /* padding */
+};
+
static void
gda_vprovider_hub_class_init (GdaVproviderHubClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GdaServerProviderClass *server_class = GDA_SERVER_PROVIDER_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
+ /* set virtual functions */
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_BASE,
+ (gpointer) &hub_base_functions);
+
object_class->finalize = gda_vprovider_hub_finalize;
- server_class->create_connection = gda_vprovider_hub_create_connection;
- server_class->open_connection = gda_vprovider_hub_open_connection;
- server_class->close_connection = gda_vprovider_hub_close_connection;
/* Properties */
object_class->set_property = gda_vprovider_hub_set_property;
object_class->get_property = gda_vprovider_hub_get_property;
}
+
static void
gda_vprovider_hub_init (GdaVproviderHub *prov, G_GNUC_UNUSED GdaVproviderHubClass *klass)
{
@@ -191,17 +227,6 @@ gda_vprovider_hub_create_connection (GdaServerProvider *provider)
return cnc;
}
-static gboolean
-gda_vprovider_hub_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- guint *task_id, GdaServerProviderAsyncCallback async_cb, gpointer cb_data)
-{
- /* nothing to do here */
- return GDA_SERVER_PROVIDER_CLASS (parent_class)->open_connection (GDA_SERVER_PROVIDER (provider),
- cnc, params, auth,
- task_id, async_cb, cb_data);
-}
-
static void
cnc_close_foreach_func (GdaConnection *cnc, G_GNUC_UNUSED const gchar *ns, GdaVconnectionHub *hub)
{
@@ -219,5 +244,13 @@ gda_vprovider_hub_close_connection (GdaServerProvider *provider, GdaConnection *
gda_vconnection_hub_foreach (GDA_VCONNECTION_HUB (cnc),
(GdaVConnectionHubFunc) cnc_close_foreach_func, cnc);
- return GDA_SERVER_PROVIDER_CLASS (parent_class)->close_connection (GDA_SERVER_PROVIDER (provider),
cnc);
+ GdaServerProviderBase *parent_functions;
+ parent_functions = gda_server_provider_get_impl_functions_for_class (parent_class,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+ return parent_functions->close_connection (provider, cnc);
+}
+
+static const gchar *
+gda_vprovider_hub_get_name (G_GNUC_UNUSED GdaServerProvider *provider)
+{
+ return "Virtual hub";
}
diff --git a/libgda/test-cnc-exec.c b/libgda/test-cnc-exec.c
new file mode 100644
index 0000000..c7b75ea
--- /dev/null
+++ b/libgda/test-cnc-exec.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2013 Vivien Malerba <malerba gnome-db org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <libgda/libgda.h>
+#include <glib/gstdio.h>
+
+static guint test1 (void);
+
+
+int main(int argc, const char *argv[])
+{
+ gda_init ();
+ guint nfailed = 0;
+
+ nfailed += test1 ();
+
+ if (nfailed > 0)
+ g_print ("Test failed %u times\n", nfailed);
+ else
+ g_print ("Test Ok\n");
+ return nfailed ? 1 : 0;
+}
+
+static gboolean
+idle_incr (guint *ptr)
+{
+ (*ptr)++;
+ return TRUE;
+}
+
+static void
+setup_main_context (GdaConnection *cnc, guint *ptr_to_incr)
+{
+ GMainContext *context;
+ GSource *idle;
+
+ context = g_main_context_new ();
+ idle = g_idle_source_new ();
+ g_source_set_priority (idle, G_PRIORITY_DEFAULT);
+ g_source_attach (idle, context);
+ g_source_set_callback (idle, (GSourceFunc) idle_incr, ptr_to_incr, NULL);
+ g_source_unref (idle);
+ gda_connection_set_main_context (cnc, context);
+ g_main_context_unref (context);
+}
+
+
+/*
+ * Test 1: gda_connection_open() when there is no error
+ */
+static guint
+test1 (void)
+{
+ g_print ("============= %s started =============\n", __FUNCTION__);
+ GdaConnection *cnc;
+ GError *error = NULL;
+
+ gchar *cnc_string, *fname;
+ fname = g_build_filename (ROOT_DIR, "data", NULL);
+ cnc_string = g_strdup_printf ("DB_DIR=%s;DB_NAME=sales_test", fname);
+ g_free (fname);
+ cnc = gda_connection_new_from_string ("SQLite", cnc_string, NULL,
+ GDA_CONNECTION_OPTIONS_READ_ONLY, NULL);
+ if (!cnc) {
+ g_print ("gda_connection_new_from_string([%s]) failed: %s\n", cnc_string,
+ error && error->message ? error->message : "No detail");
+ g_free (cnc_string);
+ return 1;
+ }
+
+ guint counter = 0;
+ setup_main_context (cnc, &counter);
+
+ /* connection open */
+ if (! gda_connection_open (cnc, &error)) {
+ g_print ("gda_connection_open([%s]) failed: %s\n", cnc_string,
+ error && error->message ? error->message : "No detail");
+ g_free (cnc_string);
+ return 1;
+ }
+ g_free (cnc_string);
+
+ if (counter == 0) {
+ g_print ("gda_connection_open() failed: did not make GMainContext 'run'\n");
+ return 1;
+ }
+ else
+ g_print ("Counter incremented to %u\n", counter);
+ g_print ("Connection %p Opened\n", cnc);
+
+
+ /* SELECT */
+ counter = 0;
+ GdaDataModel *model;
+ model = gda_connection_execute_select_command (cnc, "SELECT * FROM customers", &error);
+ if (model) {
+ gda_data_model_dump (model, NULL);
+ gint expnrows = 5;
+ if (gda_data_model_get_n_rows (model) != expnrows) {
+ g_print ("SELECT Exec() failed: expected %d and got %d\n", expnrows,
+ gda_data_model_get_n_rows (model));
+ g_object_unref (model);
+ g_object_unref (cnc);
+ return 1;
+ }
+ g_object_unref (model);
+ }
+ else {
+ g_print ("gda_connection_execute_select_command() failed: %s\n",
+ error && error->message ? error->message : "No detail");
+ g_object_unref (cnc);
+ return 1;
+ }
+
+ if (counter == 0) {
+ g_print ("gda_connection_open() failed: did not make GMainContext 'run'\n");
+ g_object_unref (cnc);
+ return 1;
+ }
+ else
+ g_print ("Counter incremented to %u\n", counter);
+
+
+ g_object_unref (cnc);
+
+ return 0;
+}
diff --git a/libgda/test-cnc-meta.c b/libgda/test-cnc-meta.c
new file mode 100644
index 0000000..885ad8a
--- /dev/null
+++ b/libgda/test-cnc-meta.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2013 Vivien Malerba <malerba gnome-db org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <libgda/libgda.h>
+#include <glib/gstdio.h>
+
+static guint test1 (void);
+
+
+int main(int argc, const char *argv[])
+{
+ gda_init ();
+ guint nfailed = 0;
+
+ nfailed += test1 ();
+
+ if (nfailed > 0)
+ g_print ("Test failed %u times\n", nfailed);
+ else
+ g_print ("Test Ok\n");
+ return nfailed ? 1 : 0;
+}
+
+static gboolean
+idle_incr (guint *ptr)
+{
+ (*ptr)++;
+ return TRUE;
+}
+
+static void
+setup_main_context (GdaConnection *cnc, guint *ptr_to_incr)
+{
+ GMainContext *context;
+ GSource *idle;
+
+ context = g_main_context_new ();
+ idle = g_idle_source_new ();
+ g_source_set_priority (idle, G_PRIORITY_DEFAULT);
+ g_source_attach (idle, context);
+ g_source_set_callback (idle, (GSourceFunc) idle_incr, ptr_to_incr, NULL);
+ g_source_unref (idle);
+ gda_connection_set_main_context (cnc, context);
+ g_main_context_unref (context);
+}
+
+
+/*
+ * Test 1: gda_connection_open() when there is no error
+ */
+static guint
+test1 (void)
+{
+ g_print ("============= %s started =============\n", __FUNCTION__);
+ GdaConnection *cnc;
+ GError *error = NULL;
+
+ gchar *cnc_string, *fname;
+ fname = g_build_filename (ROOT_DIR, "data", NULL);
+ cnc_string = g_strdup_printf ("DB_DIR=%s;DB_NAME=sales_test", fname);
+ g_free (fname);
+ cnc = gda_connection_new_from_string ("SQLite", cnc_string, NULL,
+ GDA_CONNECTION_OPTIONS_READ_ONLY, NULL);
+ if (!cnc) {
+ g_print ("gda_connection_new_from_string([%s]) failed: %s\n", cnc_string,
+ error && error->message ? error->message : "No detail");
+ g_free (cnc_string);
+ return 1;
+ }
+
+ guint counter = 0;
+ setup_main_context (cnc, &counter);
+
+ /* connection open */
+ if (! gda_connection_open (cnc, &error)) {
+ g_print ("gda_connection_open([%s]) failed: %s\n", cnc_string,
+ error && error->message ? error->message : "No detail");
+ g_free (cnc_string);
+ return 1;
+ }
+ g_free (cnc_string);
+
+ if (counter == 0) {
+ g_print ("gda_connection_open() failed: did not make GMainContext 'run'\n");
+ return 1;
+ }
+ else
+ g_print ("Counter incremented to %u\n", counter);
+ g_print ("Connection %p Opened\n", cnc);
+
+
+ /* Update meta store */
+ counter = 0;
+ if (! gda_connection_update_meta_store (cnc, NULL, &error)) {
+ g_print ("gda_connection_update_meta_store () failed: %s\n",
+ error && error->message ? error->message : "No detail");
+ return 1;
+ }
+
+ if (counter == 0) {
+ g_print ("gda_connection_update_meta_store() failed: did not make GMainContext 'run'\n");
+ g_object_unref (cnc);
+ return 1;
+ }
+ else
+ g_print ("Counter incremented to %u\n", counter);
+
+ /* get meta data */
+ counter = 0;
+ GdaDataModel *model;
+ model = gda_connection_get_meta_store_data (cnc, GDA_CONNECTION_META_TABLES, &error, 0);
+ if (!model) {
+ g_print ("gda_connection_get_meta_store_data () failed: %s\n",
+ error && error->message ? error->message : "No detail");
+ return 1;
+ }
+
+ if (counter == 0) {
+ g_print ("gda_connection_get_meta_store_data() failed: did not make GMainContext 'run'\n");
+ g_object_unref (cnc);
+ return 1;
+ }
+ else
+ g_print ("Counter incremented to %u\n", counter);
+
+ gda_data_model_dump (model, NULL);
+ g_object_unref (model);
+
+ g_object_unref (cnc);
+
+ return 0;
+}
diff --git a/libgda/test-cnc-open.c b/libgda/test-cnc-open.c
new file mode 100644
index 0000000..1b0f66c
--- /dev/null
+++ b/libgda/test-cnc-open.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2013 Vivien Malerba <malerba gnome-db org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <libgda/libgda.h>
+#include <glib/gstdio.h>
+
+static guint test1 (void);
+static guint test2 (void);
+static guint test3 (void);
+static guint test4 (void);
+
+
+int main(int argc, const char *argv[])
+{
+ gda_init ();
+ guint nfailed = 0;
+
+ nfailed += test1 ();
+ nfailed += test2 ();
+ nfailed += test3 ();
+ nfailed += test4 ();
+
+ g_unlink ("test-cnc-opendb.db");
+
+ if (nfailed > 0)
+ g_print ("Test failed %u times\n", nfailed);
+ else
+ g_print ("Test Ok\n");
+ return nfailed ? 1 : 0;
+}
+
+static gboolean
+idle_incr (guint *ptr)
+{
+ (*ptr)++;
+ return TRUE;
+}
+
+static void
+setup_main_context (GdaConnection *cnc, guint *ptr_to_incr)
+{
+ GMainContext *context;
+ GSource *idle;
+
+ context = g_main_context_new ();
+ idle = g_idle_source_new ();
+ g_source_set_priority (idle, G_PRIORITY_DEFAULT);
+ g_source_attach (idle, context);
+ g_source_set_callback (idle, (GSourceFunc) idle_incr, ptr_to_incr, NULL);
+ g_source_unref (idle);
+ gda_connection_set_main_context (cnc, context);
+ g_main_context_unref (context);
+}
+
+
+/*
+ * Test 1: gda_connection_open() when there is no error
+ */
+static guint
+test1 (void)
+{
+ g_print ("============= %s started =============\n", __FUNCTION__);
+ GdaConnection *cnc;
+ GError *error = NULL;
+ cnc = gda_connection_new_from_string ("SQLite", "DB_NAME=test-cnc-opendb", NULL,
+ GDA_CONNECTION_OPTIONS_AUTO_META_DATA, &error);
+
+ if (!cnc) {
+ g_print ("gda_connection_new_from_string() failed: %s\n", error && error->message ?
error->message : "No detail");
+ return 1;
+ }
+
+ guint counter = 0;
+ setup_main_context (cnc, &counter);
+
+ if (! gda_connection_open (cnc, &error)) {
+ g_print ("gda_connection_open() failed: %s\n", error && error->message ? error->message : "No
detail");
+ return 1;
+ }
+
+ if (counter == 0) {
+ g_print ("gda_connection_open() failed: did not make GMainContext 'run'\n");
+ return 1;
+ }
+ else
+ g_print ("Counter incremented to %u\n", counter);
+
+ g_object_unref (cnc);
+
+ return 0;
+}
+
+/*
+ * Test 2: gda_connection_open_async() when there is no error
+ */
+static void
+test2_open_func (GdaConnection *cnc, guint job_id, gboolean result, GError *error, GMainLoop *loop)
+{
+ g_print ("Test connection %p is now %s, job was %u and error [%s]\n", cnc, result ? "OPENED" :
"CLOSED",
+ job_id, error ? (error->message ? error->message : "No detail") : "No error");
+ if (!result)
+ exit (1);
+ g_main_loop_quit (loop);
+}
+
+static guint
+test2 (void)
+{
+ g_print ("============= %s started =============\n", __FUNCTION__);
+ GdaConnection *cnc;
+ GError *error = NULL;
+ cnc = gda_connection_new_from_string ("SQLite", "DB_NAME=test-cnc-opendb", NULL,
+ GDA_CONNECTION_OPTIONS_AUTO_META_DATA, &error);
+
+ if (!cnc) {
+ g_print ("gda_connection_new_from_string() failed: %s\n", error && error->message ?
error->message : "No detail");
+ return 1;
+ }
+
+ guint counter = 0;
+ setup_main_context (cnc, &counter);
+
+ GMainLoop *loop;
+ loop = g_main_loop_new (gda_connection_get_main_context (cnc), FALSE);
+
+ guint job_id;
+ job_id = gda_connection_open_async (cnc, (GdaConnectionOpenFunc) test2_open_func, loop, &error);
+
+ if (!job_id) {
+ g_print ("gda_connection_open_async() failed: %s\n", error && error->message ? error->message
: "No detail");
+ return 1;
+ }
+ else {
+ g_print ("Connection opening job is %u\n", job_id);
+ }
+
+ g_main_loop_run (loop);
+
+ if (counter == 0) {
+ g_print ("gda_connection_open() failed: did not make GMainContext 'run'\n");
+ return 1;
+ }
+ else
+ g_print ("Counter incremented to %u\n", counter);
+
+ gboolean opened;
+ opened = gda_connection_is_opened (cnc);
+ g_object_unref (cnc);
+
+ return opened ? 0 : 1;
+}
+
+/*
+ * Test 3: gda_connection_open() when there is an error
+ */
+static guint
+test3 (void)
+{
+ g_print ("============= %s started =============\n", __FUNCTION__);
+ GdaConnection *cnc;
+ GError *error = NULL;
+ cnc = gda_connection_new_from_string ("SQLite", "DB_NAMEEEE=test-cnc-opendb", NULL,
+ GDA_CONNECTION_OPTIONS_AUTO_META_DATA, &error);
+
+ if (!cnc) {
+ g_print ("gda_connection_new_from_string() failed: %s\n", error && error->message ?
error->message : "No detail");
+ return 1;
+ }
+
+ guint counter = 0;
+ setup_main_context (cnc, &counter);
+
+ if (! gda_connection_open (cnc, &error)) {
+ g_print ("gda_connection_open() failed: %s\n", error && error->message ? error->message : "No
detail");
+ g_object_unref (cnc);
+
+ if (counter == 0) {
+ g_print ("gda_connection_open() failed: did not make GMainContext 'run'\n");
+ return 1;
+ }
+ else
+ g_print ("Counter incremented to %u\n", counter);
+
+ return 0;
+ }
+ else {
+ g_print ("Connection opened when it should not have!\n");
+ g_object_unref (cnc);
+ return 1;
+ }
+}
+
+/*
+ * Test 4: gda_connection_open_async() when there is an error
+ */
+static void
+test4_open_func (GdaConnection *cnc, guint job_id, gboolean result, GError *error, GMainLoop *loop)
+{
+ g_print ("Test connection %p is now %s, job was %u and error [%s]\n", cnc, result ? "OPENED" :
"CLOSED",
+ job_id, error ? (error->message ? error->message : "No detail") : "No error");
+ if (!error || (error->domain != GDA_CONNECTION_ERROR) || (error->code != GDA_CONNECTION_OPEN_ERROR))
+ exit (1);
+ g_main_loop_quit (loop);
+}
+
+static guint
+test4 (void)
+{
+ g_print ("============= %s started =============\n", __FUNCTION__);
+ GdaConnection *cnc;
+ GError *error = NULL;
+ cnc = gda_connection_new_from_string ("SQLite", "DB_NAMEEEE=test-cnc-opendb", NULL,
+ GDA_CONNECTION_OPTIONS_AUTO_META_DATA, &error);
+
+ if (!cnc) {
+ g_print ("gda_connection_new_from_string() failed: %s\n", error && error->message ?
error->message : "No detail");
+ return 1;
+ }
+
+ guint counter = 0;
+ setup_main_context (cnc, &counter);
+
+ GMainLoop *loop;
+ loop = g_main_loop_new (gda_connection_get_main_context (cnc), FALSE);
+
+ guint job_id;
+ job_id = gda_connection_open_async (cnc, (GdaConnectionOpenFunc) test4_open_func, loop, &error);
+
+ if (!job_id) {
+ g_print ("gda_connection_open_async() failed: %s\n", error && error->message ? error->message
: "No detail");
+ return 1;
+ }
+ else {
+ g_print ("Connection opening job is %u\n", job_id);
+ }
+
+ g_main_loop_run (loop);
+
+ gboolean opened;
+ opened = gda_connection_is_opened (cnc);
+ g_object_unref (cnc);
+
+ if (counter == 0) {
+ g_print ("gda_connection_open() failed: did not make GMainContext 'run'\n");
+ return 1;
+ }
+ else
+ g_print ("Counter incremented to %u\n", counter);
+
+ return opened ? 1 : 0;
+}
diff --git a/libgda/thread-wrapper/.gitignore b/libgda/thread-wrapper/.gitignore
new file mode 100644
index 0000000..1b98527
--- /dev/null
+++ b/libgda/thread-wrapper/.gitignore
@@ -0,0 +1,8 @@
+test-itsignaler
+test-raw-itsignaler
+test-raw-itsignaler-no-eventfd
+test-blocking-itsignaler
+perf-itsignaler
+perf-itsignaler-no-eventfd
+test-worker
+test-connect
\ No newline at end of file
diff --git a/libgda/thread-wrapper/Makefile.am b/libgda/thread-wrapper/Makefile.am
index 92f7d07..6bf839a 100644
--- a/libgda/thread-wrapper/Makefile.am
+++ b/libgda/thread-wrapper/Makefile.am
@@ -1,5 +1,18 @@
noinst_LTLIBRARIES = libgda_threadwrapper-5.0.la
+TESTS = test-raw-itsignaler test-itsignaler test-blocking-itsignaler test-worker test-connect
+check_PROGRAMS = test-raw-itsignaler test-itsignaler test-blocking-itsignaler test-worker test-connect
+noinst_PROGRAMS = perf-itsignaler
+
+if PLATFORM_WIN32
+EXTRALDFLAGS=-lwsock32 -lws2_32
+else
+TESTS += test-raw-itsignaler-no-eventfd
+check_PROGRAMS += test-raw-itsignaler-no-eventfd
+noinst_PROGRAMS += perf-itsignaler-no-eventfd
+EXTRALDFLAGS=
+endif
+
AM_CPPFLAGS = \
-I$(top_srcdir) -I$(srcdir)/.. \
-I$(top_srcdir)/libgda/sqlite \
@@ -8,19 +21,127 @@ AM_CPPFLAGS = \
$(COREDEPS_WFLAGS)
libgda_threadwrapper_headers = \
- gda-thread-wrapper.h
+ gda-worker.h \
+ gda-connect.h
libgda_threadwrapperincludedir=$(includedir)/libgda-$(GDA_ABI_MAJOR_VERSION).$(GDA_ABI_MINOR_VERSION)/libgda/thread-wrapper
libgda_threadwrapperinclude_HEADERS=$(libgda_threadwrapper_headers)
libgda_threadwrapper_5_0_la_SOURCES = \
$(libgda_threadwrapper_headers) \
- gda-thread-blob-op.h \
- gda-thread-blob-op.c \
- gda-thread-meta.h \
- gda-thread-meta.c \
- gda-thread-provider.h \
- gda-thread-provider.c \
- gda-thread-recordset.h \
- gda-thread-recordset.c \
- gda-thread-wrapper.c
+ itsignaler.h \
+ itsignaler.c \
+ gda-worker.c \
+ gda-connect.c
+
+# test_itsignaler
+test_itsignaler_CFLAGS = \
+ $(COREDEPS_CFLAGS)
+
+test_itsignaler_SOURCES = \
+ itsignaler.h \
+ itsignaler.c \
+ test-itsignaler.c
+
+test_itsignaler_LDADD = \
+ $(COREDEPS_LIBS)
+
+
+# test_raw_itsignaler
+test_raw_itsignaler_CFLAGS = \
+ $(COREDEPS_CFLAGS)
+
+test_raw_itsignaler_SOURCES = \
+ itsignaler.h \
+ itsignaler.c \
+ test-raw-itsignaler.c
+
+test_raw_itsignaler_LDADD = \
+ $(COREDEPS_LIBS) \
+ $(EXTRALDFLAGS)
+
+
+# test_raw_itsignaler_no_eventfd
+test_raw_itsignaler_no_eventfd_CFLAGS = \
+ -DFORCE_NO_EVENTFD \
+ $(COREDEPS_CFLAGS)
+
+test_raw_itsignaler_no_eventfd_SOURCES = \
+ itsignaler.h \
+ itsignaler.c \
+ test-raw-itsignaler.c
+
+test_raw_itsignaler_no_eventfd_LDADD = \
+ $(COREDEPS_LIBS)
+
+# test_blocking_itsignaler
+test_blocking_itsignaler_CFLAGS = \
+ $(COREDEPS_CFLAGS)
+
+test_blocking_itsignaler_SOURCES = \
+ itsignaler.h \
+ itsignaler.c \
+ test-blocking-itsignaler.c
+
+test_blocking_itsignaler_LDADD = \
+ $(COREDEPS_LIBS) \
+ $(EXTRALDFLAGS)
+
+# perf_itsignaler
+perf_itsignaler_CFLAGS = \
+ -DPERF \
+ $(COREDEPS_CFLAGS)
+
+perf_itsignaler_SOURCES = \
+ itsignaler.h \
+ itsignaler.c \
+ test-raw-itsignaler.c
+
+perf_itsignaler_LDADD = \
+ $(COREDEPS_LIBS) \
+ $(EXTRALDFLAGS)
+
+
+# perf_itsignaler_no_eventfd
+perf_itsignaler_no_eventfd_CFLAGS = \
+ -DFORCE_NO_EVENTFD \
+ -DPERF \
+ $(COREDEPS_CFLAGS)
+
+perf_itsignaler_no_eventfd_SOURCES = \
+ itsignaler.h \
+ itsignaler.c \
+ test-raw-itsignaler.c
+
+perf_itsignaler_no_eventfd_LDADD = \
+ $(COREDEPS_LIBS)
+
+# test_worker
+test_worker_CFLAGS = \
+ $(COREDEPS_CFLAGS)
+
+test_worker_SOURCES = \
+ itsignaler.h \
+ itsignaler.c \
+ gda-worker.h \
+ gda-worker.c \
+ test-worker.c
+
+test_worker_LDADD = \
+ $(COREDEPS_LIBS)
+
+# test_connect
+test_connect_CFLAGS = \
+ $(COREDEPS_CFLAGS)
+
+test_connect_SOURCES = \
+ dummy-object.h \
+ dummy-object.c \
+ itsignaler.h \
+ itsignaler.c \
+ gda-connect.h \
+ gda-connect.c \
+ test-connect.c
+
+test_connect_LDADD = \
+ $(COREDEPS_LIBS)
\ No newline at end of file
diff --git a/libgda/thread-wrapper/dummy-object.c b/libgda/thread-wrapper/dummy-object.c
new file mode 120000
index 0000000..cebbfbe
--- /dev/null
+++ b/libgda/thread-wrapper/dummy-object.c
@@ -0,0 +1 @@
+../../tests/multi-threading/dummy-object.c
\ No newline at end of file
diff --git a/libgda/thread-wrapper/dummy-object.h b/libgda/thread-wrapper/dummy-object.h
new file mode 120000
index 0000000..f080d0c
--- /dev/null
+++ b/libgda/thread-wrapper/dummy-object.h
@@ -0,0 +1 @@
+../../tests/multi-threading/dummy-object.h
\ No newline at end of file
diff --git a/libgda/thread-wrapper/gda-connect.c b/libgda/thread-wrapper/gda-connect.c
new file mode 100644
index 0000000..dccd2ba
--- /dev/null
+++ b/libgda/thread-wrapper/gda-connect.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2014 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 Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "gda-connect.h"
+#include "itsignaler.h"
+#include <gda-debug-macros.h>
+#include <glib/gi18n-lib.h>
+
+#define DEBUG_NOTIFICATION
+//#undef DEBUG_NOTIFICATION
+
+#ifdef DEBUG_NOTIFICATION
+static gchar *
+_value_stringify (const GValue *value)
+{
+ if (!value)
+ return g_strdup ("NULL");
+ if (g_value_type_transformable (G_VALUE_TYPE (value), G_TYPE_STRING)) {
+ GValue *string;
+ gchar *str;
+
+ string = g_value_init (g_new0 (GValue, 1), G_TYPE_STRING);
+ g_value_transform (value, string);
+ str = g_value_dup_string (string);
+ g_value_reset (string);
+ g_free (string);
+ return str;
+ }
+ else {
+ GType type = G_VALUE_TYPE (value);
+ if (type == G_TYPE_DATE) {
+ GDate *date;
+ date = (GDate *) g_value_get_boxed (value);
+ if (date) {
+ if (g_date_valid (date))
+ return g_strdup_printf ("%04u-%02u-%02u",
+ g_date_get_year (date),
+ g_date_get_month (date),
+ g_date_get_day (date));
+ else
+ return g_strdup_printf ("%04u-%02u-%02u",
+ date->year, date->month, date->day);
+ }
+ else
+ return g_strdup ("0000-00-00");
+ }
+ else if (G_TYPE_IS_OBJECT (type)) {
+ GObject *obj;
+ obj = g_value_get_object (value);
+ return g_strdup_printf ("%p (%s)", obj, G_OBJECT_TYPE_NAME (obj));
+ }
+ else
+ return g_strdup ("");
+ }
+}
+#endif
+
+static GHashTable *handlers_hash = NULL;
+
+typedef struct _SigClosure SigClosure;
+struct _SigClosure
+{
+ GClosure closure;
+ GMainContext *context; /* ref held */
+ gulong ext_handler_id;
+
+ GCallback callback;
+
+ ITSignaler *signal_its;
+ ITSignaler *return_its;
+ guint its_add_id;
+};
+
+static void
+sig_closure_finalize (G_GNUC_UNUSED gpointer notify_data, GClosure *closure)
+{
+ SigClosure *sig_closure = (SigClosure *)closure;
+
+ g_print ("%s()\n", __FUNCTION__);
+ itsignaler_remove (sig_closure->signal_its, sig_closure->context, sig_closure->its_add_id);
+ itsignaler_unref (sig_closure->signal_its);
+ itsignaler_unref (sig_closure->return_its);
+ g_main_context_unref (sig_closure->context);
+}
+
+/* data to pass through ITSignaler and back */
+typedef struct {
+ GValue *return_value;
+ guint n_param_values;
+ GValue *param_values;
+ gpointer invocation_hint; /* FIXME: problem here to copy value! */
+
+ GClosure *rcl; /* real closure, used in the main loop context */
+} PassedData;
+
+/*
+ * This function is called in the thread which emitted the signal
+ *
+ * In it we pack the data, push it through the ITSignaler to the thead from which the callback will be
called, and
+ * wait for the result before returning.
+ */
+static void
+sig_closure_marshal (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ SigClosure *sig_closure;
+ sig_closure = (SigClosure *) closure;
+
+#ifdef DEBUG_NOTIFICATION
+ g_print ("Th%p: %s (closure->data = \"%s\") called\n", g_thread_self(), __FUNCTION__, (gchar*)
closure->data);
+ guint n;
+ for (n = 0; n < n_param_values; n++) {
+ gchar *tmp;
+ tmp = _value_stringify (& (param_values [n]));
+ g_print ("Th%p Param value %d is [%s]\n", g_thread_self(), n, tmp);
+ g_free (tmp);
+ }
+ if (return_value)
+ g_print ("Th%p Return value expected: of type %s\n", g_thread_self(), g_type_name
(G_VALUE_TYPE (return_value)));
+ else
+ g_print ("Th%p Return value expected: none\n", g_thread_self());
+#endif
+
+ if (g_main_context_acquire (sig_closure->context)) {
+ /* the signal has to be propagated in the same thread */
+ GClosure *rcl;
+ rcl = g_cclosure_new (sig_closure->callback, closure->data, NULL);
+ g_closure_set_marshal (rcl, g_cclosure_marshal_generic);
+ g_closure_invoke (rcl, return_value, n_param_values, param_values, invocation_hint);
+ g_closure_unref (rcl);
+ g_main_context_release (sig_closure->context);
+ }
+ else {
+ PassedData data;
+ data.n_param_values = n_param_values;
+ data.invocation_hint = invocation_hint;
+ data.return_value = return_value;
+ data.param_values = (GValue*) param_values;
+ data.rcl = g_cclosure_new (sig_closure->callback, closure->data, NULL);
+ g_closure_set_marshal (data.rcl, g_cclosure_marshal_generic);
+ if (itsignaler_push_notification (sig_closure->signal_its, &data, NULL)) {
+ gpointer rdata;
+ rdata = itsignaler_pop_notification (sig_closure->return_its, -1);
+ g_assert (rdata == &data);
+ }
+ else
+ g_warning ("Internal Gda Connect error, the signal will not be propagated, please
report the bug");
+
+ g_closure_unref (data.rcl);
+ }
+}
+
+/*
+ * This function is called in the thread where the signal is intended by the
+ * programmer to be propagated, when a PassedData pointer is available through the ITS
+ */
+static gboolean
+propagate_signal (ITSignaler *its, SigClosure *sig_closure)
+{
+ PassedData *data;
+ data = itsignaler_pop_notification (sig_closure->signal_its, 0);
+ if (data) {
+ g_closure_invoke (data->rcl, data->return_value, data->n_param_values,
+ data->param_values, data->invocation_hint);
+ if (! itsignaler_push_notification (sig_closure->return_its, data, NULL))
+ g_warning ("Internal Gda Connect error, the signal result will not be propagated,
please report the bug");
+ }
+ else
+ g_warning ("Internal Gda Connect error: no signal data to process, please report a bug");
+ return TRUE; /* don't remove the source! */
+}
+
+
+/*
+ * FIXME: what is @data for ?
+ */
+static SigClosure *
+sig_closure_new (gpointer instance, GMainContext *context, gpointer data)
+{
+ g_assert (context);
+
+ ITSignaler *its1, *its2;
+ its1 = itsignaler_new ();
+ its2 = itsignaler_new ();
+ if (! its1 || ! its2) {
+ g_warning ("Not enough ressources to allocate internal communication object");
+ itsignaler_unref (its1); /* in case it was created */
+ return NULL;
+ }
+
+ GClosure *closure;
+ SigClosure *sig_closure;
+
+ closure = g_closure_new_simple (sizeof (SigClosure), data);
+ sig_closure = (SigClosure *) closure;
+ sig_closure->context = g_main_context_ref (context);
+ sig_closure->ext_handler_id = 0;
+ sig_closure->callback = NULL;
+ sig_closure->signal_its = its1;
+ sig_closure->return_its = its2;
+
+ sig_closure->its_add_id = itsignaler_add (sig_closure->signal_its, context,
+ (ITSignalerFunc) propagate_signal, sig_closure, NULL);
+
+ /* initialize closure */
+ g_closure_set_marshal (closure, sig_closure_marshal);
+ gpointer notify_data = NULL; /* as unused in sig_closure_finalize() */
+ g_closure_add_finalize_notifier (closure, notify_data, sig_closure_finalize);
+
+ return sig_closure;
+}
+
+static guint
+ulong_hash (gconstpointer key)
+{
+ return (guint) *((gulong*) key);
+}
+
+static gboolean
+ulong_equal (gconstpointer a, gconstpointer b)
+{
+ return *((const gulong*) a) == *((const gulong*) b);
+}
+
+
+/**
+ * gda_connect:
+ * @instance: the instance to connect to
+ * @detailed_signal: a string of the form "signal-name::detail"
+ * @c_handler: the GCallback to connect
+ * @data: (allow-none): data to pass to @c_handler, or %NULL
+ * @destroy_data: (allow-none): function to destroy @data when not needed anymore, or %NULL
+ * @connect_flags:
+ * @context: (allow-none): the #GMainContext in which signals will actually be treated, or %NULL for the
default one
+ *
+ * Connects a GCallback function to a signal for a particular object.
+ *
+ * Returns: the handler id, or %0 if an error occurred
+ *
+ * Since: 6.0
+ */
+gulong
+gda_connect (gpointer instance,
+ const gchar *detailed_signal,
+ GCallback c_handler,
+ gpointer data,
+ GClosureNotify destroy_data,
+ GConnectFlags connect_flags,
+ GMainContext *context)
+{
+ static gulong ids = 1;
+ g_return_val_if_fail (instance, 0);
+
+ guint signal_id;
+ if (! g_signal_parse_name (detailed_signal, G_TYPE_FROM_INSTANCE (instance), &signal_id, NULL,
FALSE)) {
+ g_warning (_("Could not find signal named \"%s\""), detailed_signal);
+ return 0;
+ }
+
+ if (context)
+ g_main_context_ref (context);
+ else
+ context = g_main_context_ref_thread_default ();
+
+ SigClosure *sig_closure;
+ sig_closure = sig_closure_new (instance, context, data);
+ g_main_context_unref (context);
+ if (!sig_closure)
+ return 0;
+
+ GSignalQuery query;
+ g_signal_query (signal_id, &query);
+ g_assert (query.signal_id == signal_id);
+
+ gulong hid;
+ hid = g_signal_connect_closure (instance, detailed_signal, (GClosure *) sig_closure, 0);
+ g_closure_sink ((GClosure *) sig_closure);
+ sig_closure->callback = c_handler;
+
+ if (hid > 0) {
+ if (!handlers_hash)
+ handlers_hash = g_hash_table_new_full (ulong_hash, ulong_equal,
+ NULL, (GDestroyNotify) g_closure_unref);
+ sig_closure->ext_handler_id = ids++;
+ g_hash_table_insert (handlers_hash, &(sig_closure->ext_handler_id),
+ (GClosure*) sig_closure);
+
+ return sig_closure->ext_handler_id;
+ }
+ else {
+ g_closure_unref ((GClosure *) sig_closure);
+ return 0;
+ }
+
+}
+
+void
+gda_disconnect (gpointer instance, gulong handler_id, GMainContext *context)
+{
+ SigClosure *sig_closure = NULL;
+ if (handlers_hash)
+ sig_closure = g_hash_table_lookup (handlers_hash, &handler_id);
+ if (sig_closure)
+ g_hash_table_remove (handlers_hash, &handler_id);
+ else
+ g_warning (_("Could not find handler %lu"), handler_id);
+}
diff --git a/libgda/thread-wrapper/gda-connect.h b/libgda/thread-wrapper/gda-connect.h
new file mode 100644
index 0000000..a2d9b70
--- /dev/null
+++ b/libgda/thread-wrapper/gda-connect.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 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 Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GDA_CONNECT_H__
+#define __GDA_CONNECT_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/**
+ * SECTION:gda-connect
+ * @short_description: Connect signals to objects and "forward" them to be handled from a specific
#GMainContext
+ * @title: GdaConnect
+ * @stability: Stable
+ * @see_also:
+ *
+ * The purpose of the #GdaConnect object is to allow one to connect to a signal emitted by an object and be
sure that
+ * the acutal signal handling will occur _only_ when running a specific #GMainContext.
+ *
+ * Use these functions for exemple when you need to handle signals from objects which are emitted from
within a thread
+ * which is not the main UI thread.
+ *
+ * The #GdaConnect implements its own locking mechanism and can safely be used from multiple
+ * threads at once without needing further locking.
+ */
+
+gulong gda_connect (gpointer instance,
+ const gchar *detailed_signal,
+ GCallback c_handler,
+ gpointer data,
+ GClosureNotify destroy_data,
+ GConnectFlags connect_flags,
+ GMainContext *context);
+
+void gda_disconnect (gpointer instance, gulong handler_id, GMainContext *context);
+
+G_END_DECLS
+
+#endif
diff --git a/libgda/thread-wrapper/gda-worker.c b/libgda/thread-wrapper/gda-worker.c
new file mode 100644
index 0000000..a6af91d
--- /dev/null
+++ b/libgda/thread-wrapper/gda-worker.c
@@ -0,0 +1,1016 @@
+/*
+ * Copyright (C) 2013 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 Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "gda-worker.h"
+#include "itsignaler.h"
+#include <gda-debug-macros.h>
+#include <glib/gi18n-lib.h>
+
+#define DEBUG_NOTIFICATION
+#undef DEBUG_NOTIFICATION
+
+typedef struct {
+ ITSignaler *its; /* ref held */
+ GdaWorker *worker; /* no ref held */
+ GMainContext *context; /* ref held */
+ GdaWorkerCallback callback;
+ gpointer user_data;
+ guint source_sig_id;
+} DeclaredCallback;
+
+static DeclaredCallback *
+declared_callback_new (GdaWorker *worker, GMainContext *context, GdaWorkerCallback callback, gpointer
user_data)
+{
+ g_assert (callback);
+ g_assert (context);
+
+ ITSignaler *its;
+ its = itsignaler_new ();
+ if (!its)
+ return NULL;
+
+ DeclaredCallback *dc;
+ dc = g_slice_new0 (DeclaredCallback);
+ dc->its = its;
+ dc->worker = worker;
+ dc->context = g_main_context_ref (context);
+ dc->callback = callback;
+ dc->user_data = user_data;
+ dc->source_sig_id = 0;
+
+ return dc;
+}
+
+static void
+declared_callback_free (DeclaredCallback *dc)
+{
+ if (!dc)
+ return;
+ if (dc->source_sig_id)
+ g_assert (itsignaler_remove (dc->its, dc->context, dc->source_sig_id));
+ if (dc->its)
+ itsignaler_unref (dc->its);
+ g_main_context_unref (dc->context);
+ g_slice_free (DeclaredCallback, dc);
+}
+
+/* structure is completely opaque for end user */
+struct _GdaWorker {
+ GRecMutex rmutex; /* protects all the attributes in GdaWorker and any WorkerJob */
+
+ guint refcount; /* +1 for any user
+ * Object is destroyed when refcount reaches 0 */
+
+ GThread *worker_thread; /* used to join thread when cleaning up, created when 1st job is submitted */
+ gint8 worker_must_quit; /* set to 1 if worker is requested to exit */
+ gint8 worker_terminated; /* set to 1 by worker thread just before terminating */
+
+ ITSignaler *submit_its; /* used to submit jobs to worker thread, jobs IDs are pushed */
+
+ GHashTable *callbacks_hash; /* used to declare callbacks
+ * gda_worker_set_callback() was called
+ * key = a GMainContext (ref held),
+ * value = corresponding DeclaredCallback (memory managed here) */
+
+ GHashTable *jobs_hash; /* locked by @mutex when reading or writing, by any thread
+ * key = a #WorkerJob's job ID, value = the #WorkerJob */
+};
+
+
+/* module error */
+GQuark gda_worker_error_quark (void)
+{
+ static GQuark quark;
+ if (!quark)
+ quark = g_quark_from_static_string ("gda_worker_error");
+ return quark;
+}
+
+/*
+ * Individual jobs
+ *
+ * If the status is in JOB_QUEUED or JOB_BEING_PROCESSED, then it may be in the ITSignaler's internal queue
+ * It the status is JOB_PROCESSED, then it will _not_ be in the ITSignaler's internal queue
+ */
+typedef enum {
+ JOB_QUEUED = 1,
+ JOB_BEING_PROCESSED = 1 << 1,
+ JOB_PROCESSED = 1 << 2,
+ JOB_CANCELLED = 1 << 3,
+} JobStatus;
+
+typedef struct {
+ guint id;
+ JobStatus status; /* protected by associated worker's mutex */
+
+ ITSignaler *reply_its; /* where to push the result to, ref held */
+
+ /* information to call function in worker thread */
+ GdaWorkerFunc func;
+ gpointer data;
+ GDestroyNotify data_destroy_func; /* to destroy @data */
+
+ /* result */
+ gpointer result;
+ GDestroyNotify result_destroy_func; /* to destroy @result */
+ GError *error;
+} WorkerJob;
+
+static WorkerJob *
+worker_job_new (ITSignaler *reply_its, GdaWorkerFunc func, gpointer data, GDestroyNotify data_destroy_func,
+ GDestroyNotify result_destroy_func)
+{
+ static guint counter = 0;
+
+ WorkerJob *job;
+ job = g_slice_new0 (WorkerJob);
+ counter ++;
+ job->id = counter;
+ job->status = JOB_QUEUED;
+ job->reply_its = reply_its ? itsignaler_ref (reply_its) : NULL;
+
+ job->func = func;
+ job->data = data;
+ job->data_destroy_func = data_destroy_func;
+
+ job->result = NULL;
+ job->result_destroy_func = result_destroy_func;
+ job->error = NULL;
+
+ return job;
+}
+
+static void
+worker_job_free (WorkerJob *job)
+{
+ if (!job)
+ return;
+ if (job->data_destroy_func && job->data)
+ job->data_destroy_func (job->data);
+ if (job->result) {
+ if (job->result_destroy_func)
+ job->result_destroy_func (job->result);
+ else
+ g_warning (_("Possible memory leak as no destroy function provided to free value
returned by the worker thread"));
+ }
+ if (job->error)
+ g_error_free (job->error);
+ if (job->reply_its)
+ itsignaler_unref (job->reply_its);
+ g_slice_free (WorkerJob, job);
+}
+
+/*
+ * main function of the worker thread
+ */
+static gpointer
+worker_thread_main (GdaWorker *worker)
+{
+#define TIMER 150
+#ifdef DEBUG_NOTIFICATION
+ g_print ("[W] Worker %p thread for %p started!\n", worker, g_thread_self());
+#endif
+ itsignaler_ref (worker->submit_its);
+ while (1) {
+ WorkerJob *job;
+ job = itsignaler_pop_notification (worker->submit_its, TIMER);
+ if (job) {
+ g_rec_mutex_lock (&worker->rmutex);
+ if (! (job->status & JOB_CANCELLED)) {
+ /* handle job */
+ job->status |= JOB_BEING_PROCESSED;
+ g_rec_mutex_unlock (&worker->rmutex);
+
+ job->result = job->func (job->data, & job->error);
+
+ g_rec_mutex_lock (&worker->rmutex);
+ job->status |= JOB_PROCESSED;
+ if (job->reply_its)
+ itsignaler_push_notification (job->reply_its, job, NULL);
+ }
+
+ if (job->status & JOB_CANCELLED)
+ g_hash_table_remove (worker->jobs_hash, &job->id);
+ g_rec_mutex_unlock (&worker->rmutex);
+ }
+
+ if (worker->worker_must_quit) {
+#ifdef DEBUG_NOTIFICATION
+ g_print ("[W] GdaWorker %p, worker thread %p finished!\n", worker, g_thread_self());
+#endif
+ worker->worker_terminated = 1;
+ itsignaler_unref (worker->submit_its);
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * gda_worker_new: (skip)
+ *
+ * Creates a new #GdaWorker object.
+ *
+ * Returns: (transfer full): a new #GdaWorker, or %NULL if an error occurred
+ *
+ * Since: 6.0
+ */
+GdaWorker *
+gda_worker_new (void)
+{
+ GdaWorker *worker;
+ worker = g_slice_new0 (GdaWorker);
+ worker->submit_its = itsignaler_new ();
+ if (!worker->submit_its) {
+ g_slice_free (GdaWorker, worker);
+ return NULL;
+ }
+
+ worker->refcount = 1;
+
+ worker->callbacks_hash = g_hash_table_new_full (NULL, NULL, NULL,
+ (GDestroyNotify) declared_callback_free);
+ worker->jobs_hash = g_hash_table_new_full (g_int_hash, g_int_equal, NULL, (GDestroyNotify)
worker_job_free);
+
+ worker->worker_must_quit = 0;
+ worker->worker_terminated = 0;
+
+ g_rec_mutex_init (& worker->rmutex);
+
+ gchar *str;
+ str = g_strdup_printf ("Wkr%p", worker);
+ worker->worker_thread = g_thread_try_new (str, (GThreadFunc) worker_thread_main, worker, NULL);
+ g_free (str);
+ if (!worker->worker_thread) {
+ itsignaler_unref (worker->submit_its);
+ g_hash_table_destroy (worker->callbacks_hash);
+ g_hash_table_destroy (worker->jobs_hash);
+ g_rec_mutex_clear (& worker->rmutex);
+ g_slice_free (GdaWorker, worker);
+ return NULL;
+ }
+
+#ifdef DEBUG_NOTIFICATION
+ g_print ("[W] created GdaWorker %p\n", worker);
+#endif
+
+ return worker;
+}
+
+/**
+ * gda_worker_ref: (skip)
+ * @worker: a #GdaWorker
+ *
+ * Increases @worker's reference count.
+ *
+ * Returns: (transfer full): @worker
+ *
+ * Since: 6.0
+ */
+GdaWorker *
+gda_worker_ref (GdaWorker *worker)
+{
+ g_return_val_if_fail (worker, NULL);
+ g_rec_mutex_lock (& worker->rmutex);
+ worker->refcount ++;
+#ifdef DEBUG_NOTIFICATION
+ g_print ("[W] GdaWorker %p reference increased to %u\n", worker, worker->refcount);
+#endif
+ g_rec_mutex_unlock (& worker->rmutex);
+
+ return worker;
+}
+
+/**
+ * gda_worker_unref: (skip)
+ * @worker: (allow-none): a #GdaWorker, or %NULL
+ *
+ * Decreases @worker's reference count. When reference count reaches %0, then the
+ * object is destroyed, note that in this case this function only returns when the
+ * worker thread actually has terminated, which can take some time if it's busy.
+ *
+ * If @worker is %NULL, then nothing happens.
+ *
+ * Since: 6.0
+ */
+void
+gda_worker_unref (GdaWorker *worker)
+{
+ if (worker) {
+ g_rec_mutex_lock (& worker->rmutex);
+ worker->refcount --;
+ g_rec_mutex_unlock (& worker->rmutex);
+
+#ifdef DEBUG_NOTIFICATION
+ g_print ("[W] GdaWorker %p reference decreased to %u\n", worker, worker->refcount);
+#endif
+ if (worker->refcount == 0) {
+ /* request the worker thread to exit */
+ worker->worker_must_quit = 1;
+
+ /* we need to call g_thread_join() to avoid zombie threads */
+ g_thread_join (worker->worker_thread);
+
+ /* free all the resources used by @worker */
+ g_rec_mutex_lock (& worker->rmutex);
+ g_hash_table_destroy (worker->callbacks_hash);
+ worker->callbacks_hash = NULL;
+ g_hash_table_destroy (worker->jobs_hash);
+ worker->jobs_hash = NULL;
+ g_rec_mutex_unlock (& worker->rmutex);
+
+ g_rec_mutex_clear (& worker->rmutex);
+ itsignaler_unref (worker->submit_its);
+ g_slice_free (GdaWorker, worker);
+ }
+ }
+}
+
+/**
+ * gda_worker_kill: (skip)
+ * @worker: (allow-none): a #GdaWorker, or %NULL
+ *
+ * Requests that @worker's worker thread be terminated. This is usefull before calling
+ * gda_worker_unref() to make sure it won't lock.
+ *
+ * Returns: %TRUE if the worker thread has exited
+ *
+ * Since: 6.0
+ */
+gboolean
+gda_worker_kill (GdaWorker *worker)
+{
+ if (!worker)
+ return TRUE;
+ worker->worker_must_quit = 1;
+ g_thread_yield ();
+
+ return worker->worker_terminated == 1 ? TRUE : FALSE;
+}
+
+/*
+ * WARNING: calling this function, the worker->rmutex _must_ be locked
+ *
+ * Returns: a job ID, or %0 if an error occurred
+ */
+static guint
+_gda_worker_submit_job_with_its (GdaWorker *worker, ITSignaler *reply_its, GdaWorkerFunc func,
+ gpointer data, GDestroyNotify data_destroy_func,
+ GDestroyNotify result_destroy_func, GError **error)
+{
+ guint jid = 0;
+ WorkerJob *job;
+ job = worker_job_new (reply_its, func, data, data_destroy_func, result_destroy_func);
+ g_assert (job);
+ if (worker->worker_thread == g_thread_self ()) {
+ /* run the job right away */
+ g_hash_table_insert (worker->jobs_hash, & job->id, job);
+ jid = job->id;
+ job->status |= JOB_BEING_PROCESSED;
+ job->result = job->func (job->data, & job->error);
+ job->status |= JOB_PROCESSED;
+ if (job->reply_its)
+ itsignaler_push_notification (job->reply_its, job, NULL);
+ }
+ else {
+ if (itsignaler_push_notification (worker->submit_its, job, NULL)) {
+ g_hash_table_insert (worker->jobs_hash, & job->id, job);
+ jid = job->id;
+ }
+ else
+ worker_job_free (job);
+ }
+
+ return jid;
+}
+
+/**
+ * gda_worker_submit_job: (skip)
+ * @worker: a #GdaWorker object
+ * @callback_context: (allow-none): a #GMainContext, or %NULL (ignored if no setting has been defined with
gda_worker_set_callback())
+ * @func: the function to call from the worker thread
+ * @data: (allow-none): the data to pass to @func, or %NULL
+ * @data_destroy_func: (allow-none): a function to destroy @data, or %NULL
+ * @result_destroy_func: (allow-none): a function to destroy the result, if any, of the execution of @func,
or %NULL
+ * @error: (allow-none): a place to store errors, or %NULL.
+ *
+ * Request that the worker thread call @func with the @data argument.
+ *
+ * Notes:
+ * <itemizedlist>
+ * <listitem><para>if @data_destroy_func is not %NULL, then it will be called to destroy @data when the
job is removed,
+ * which can occur within the context of the worker thread, or within the context of any thread using
@worker.</para></listitem>
+ * <listitem><para>if @result_destroy_func is not %NULL, then it will be called to destroy the result
produced by @func.
+ * Similarly to @data_destroy_func, if it is not %NULL (and if there is a non %NULL result), then that
function can be
+ * called in the context of any thread.</para></listitem>
+ * <listitem><para>the error here can only report failures while executing gda_worker_submit_job(), not
any error which may occur
+ * while executing @func from the worker thread.</para></listitem>
+ * <listitem><para>when this function returns, the job may already have been completed, so you should not
assume that the job
+ * is in any specific state.</para></listitem>
+ * <listitem><para>passing %NULL for @callback_context is similar to passing the result of
g_main_context_ref_thread_default()</para></listitem>
+ * </itemizedlist>
+ *
+ * Returns: a job ID, or %0 if an error occurred
+ *
+ * Since: 6.0
+ */
+guint
+gda_worker_submit_job (GdaWorker *worker, GMainContext *callback_context, GdaWorkerFunc func,
+ gpointer data, GDestroyNotify data_destroy_func,
+ GDestroyNotify result_destroy_func, GError **error)
+{
+ g_return_val_if_fail (worker, 0);
+ g_return_val_if_fail (func, 0);
+ if (!worker->callbacks_hash) {
+ g_warning ("GdaWorker has been destroyed\n");
+ return 0;
+ }
+
+ DeclaredCallback *dc;
+ guint jid;
+ GMainContext *co;
+ gboolean unref_co = FALSE;
+
+ co = callback_context;
+ if (!co) {
+ co = g_main_context_ref_thread_default ();
+ unref_co = TRUE;
+ }
+
+ g_rec_mutex_lock (& worker->rmutex);
+ dc = g_hash_table_lookup (worker->callbacks_hash, co);
+ jid = _gda_worker_submit_job_with_its (worker, dc ? dc->its : NULL,
+ func, data, data_destroy_func, result_destroy_func, error);
+ g_rec_mutex_unlock (& worker->rmutex);
+
+ if (unref_co)
+ g_main_context_unref (co);
+
+ return jid;
+}
+
+/**
+ * gda_worker_fetch_job_result: (skip)
+ * @worker: a #GdaWorker object
+ * @job_id: the ID of the job, as returned by gda_worker_submit_job()
+ * @out_result: (allow-none): a place to store the value returned by the execution of the requested function
within the worker thread, or %NULL
+ * @error: (allow-none): a place to store errors, or %NULL
+ *
+ * Fetch the value returned by execution the @job_id job.
+ *
+ * Warning: if an error occurred during the
+ * execution of the requested function within the worker thread, then it will show as @error, while the
return value
+ * of this function will be %TRUE.
+ *
+ * Note: if there is a result, it will be stored in @out_result, and it's up to the caller to free
+ * the result, the #GdaWorker object will not do it (ownership of the result is transfered to the caller).
+ *
+ * Returns: %TRUE if the jobs has completed
+ *
+ * Since: 6.0
+ */
+gboolean
+gda_worker_fetch_job_result (GdaWorker *worker, guint job_id, gpointer *out_result, GError **error)
+{
+ g_return_val_if_fail (worker, FALSE);
+ if (!worker->jobs_hash) {
+ g_warning ("GdaWorker has been destroyed\n");
+ return FALSE;
+ }
+
+ gda_worker_ref (worker); /* increase reference count to having @worker freed while destroying job */
+
+ if (out_result)
+ *out_result = NULL;
+
+ g_rec_mutex_lock (&worker->rmutex);
+ WorkerJob *job;
+ job = g_hash_table_lookup (worker->jobs_hash, &job_id);
+ if (!job) {
+ g_rec_mutex_unlock (& worker->rmutex);
+ g_set_error (error, GDA_WORKER_ERROR, GDA_WORKER_JOB_NOT_FOUND_ERROR,
+ _("Unknown requested job %u"), job_id);
+ gda_worker_unref (worker);
+ return FALSE;
+ }
+
+ gboolean retval = FALSE;
+ if (job->status & JOB_CANCELLED)
+ g_set_error (error, GDA_WORKER_ERROR, GDA_WORKER_JOB_CANCELLED_ERROR,
+ _("Job %u has been cancelled"), job_id);
+ else if (job->status & JOB_PROCESSED) {
+ retval = TRUE;
+ if (out_result) {
+ *out_result = job->result;
+ job->result = NULL;
+ }
+ if (job->error) {
+ g_propagate_error (error, job->error);
+ job->error = NULL;
+ }
+ g_hash_table_remove (worker->jobs_hash, &job_id);
+ }
+ else if (job->status & JOB_BEING_PROCESSED)
+ g_set_error (error, GDA_WORKER_ERROR, GDA_WORKER_JOB_BEING_PROCESSED_ERROR,
+ _("Job %u is being processed"), job_id);
+ else
+ g_set_error (error, GDA_WORKER_ERROR, GDA_WORKER_JOB_QUEUED_ERROR,
+ _("Job %u has not yet been processed"), job_id);
+ g_rec_mutex_unlock (&worker->rmutex);
+
+ gda_worker_unref (worker);
+ return retval;
+}
+
+/**
+ * gda_worker_cancel_job: (skip)
+ * @worker: a #GdaWorker object
+ * @job_id: the ID of the job, as returned by gda_worker_submit_job()
+ * @error: (allow-none): a place to store errors, or %NULL
+ *
+ * Cancels a job which has not yet been processed. If the job cannot be found, is being processed or has
already been processed,
+ * then this function returns %FALSE.
+ *
+ * This function can be called on already cancelled jobs, and simply returns %TRUE in that case.
+ *
+ * Returns: %TRUE if the job was cancelled
+ *
+ * Since: 6.0
+ */
+gboolean
+gda_worker_cancel_job (GdaWorker *worker, guint job_id, GError **error)
+{
+ g_return_val_if_fail (worker, FALSE);
+
+ if (!worker->jobs_hash) {
+ g_warning ("GdaWorker has been destroyed\n");
+ return FALSE;
+ }
+
+ g_rec_mutex_lock (& worker->rmutex);
+
+ WorkerJob *job;
+ job = g_hash_table_lookup (worker->jobs_hash, &job_id);
+ if (!job) {
+ g_rec_mutex_unlock (& worker->rmutex);
+ g_set_error (error, GDA_WORKER_ERROR, GDA_WORKER_JOB_NOT_FOUND_ERROR,
+ _("Unknown requested job %u"), job_id);
+ return FALSE;
+ }
+
+ gboolean retval = FALSE;
+ if (job->status & JOB_BEING_PROCESSED)
+ g_set_error (error, GDA_WORKER_ERROR, GDA_WORKER_JOB_BEING_PROCESSED_ERROR,
+ _("Job %u is being processed"), job_id);
+ else if (job->status & JOB_PROCESSED)
+ g_set_error (error, GDA_WORKER_ERROR, GDA_WORKER_JOB_QUEUED_ERROR,
+ _("Job %u has already been processed"), job_id);
+ else {
+ retval = TRUE;
+ job->status |= JOB_CANCELLED;
+ }
+
+ g_rec_mutex_unlock (&worker->rmutex);
+
+ return retval;
+}
+
+/**
+ * gda_worker_forget_job: (skip)
+ * @worker: a #GdaWorker object
+ * @job_id: the ID of the job, as returned by gda_worker_submit_job()
+ *
+ * Forget all about the job with ID @job_id. As opposed to gda_worker_cancel_job(), this function can be
used to tell
+ * @worker that whatever happens to the specific job, you are not interrested anymore (i.e. that @worker can
+ * do whatever is possible to simple discard everything related to that job).
+ *
+ * Since: 6.0
+ */
+void
+gda_worker_forget_job (GdaWorker *worker, guint job_id)
+{
+ g_return_if_fail (worker);
+
+ if (!worker->jobs_hash) {
+ g_warning ("GdaWorker has been destroyed\n");
+ return;
+ }
+
+ g_rec_mutex_lock (& worker->rmutex);
+ WorkerJob *job;
+ job = g_hash_table_lookup (worker->jobs_hash, &job_id);
+ if (job) {
+ if (job->status & JOB_PROCESSED)
+ /* only case where we can remove the job because the worker thread won't use it */
+ g_hash_table_remove (worker->jobs_hash, & job->id);
+ else
+ /* the job will be 'cleared' by the worker thread */
+ job->status |= JOB_CANCELLED;
+ }
+ g_rec_mutex_unlock (&worker->rmutex);
+}
+
+static gboolean
+dc_callback (ITSignaler *its, DeclaredCallback *dc)
+{
+ WorkerJob *job;
+ job = itsignaler_pop_notification (its, 0);
+ g_assert (job);
+
+ gpointer result;
+ guint jid;
+ GError *error = NULL;
+ jid = job->id;
+ if (gda_worker_fetch_job_result (dc->worker, jid, &result, &error)) {
+ dc->callback (dc->worker, jid, result, error, dc->user_data);
+ g_clear_error (&error);
+ }
+ return TRUE; /* don't remove the source from poll, this can be done using gda_worker_set_callback() */
+}
+
+/**
+ * gda_worker_set_callback: (skip)
+ * @worker: a #GdaWorker object
+ * @context: (allow-none): a #GMainContext, or %NULL
+ * @callback: (allow-none): the function to call when a job submitted from within the calling thread using
gda_worker_submit_job() has finished being processed.
+ * @user_data: argument passed to @callback
+ * @error: (allow-none): a place to store errors, or %NULL
+ *
+ * Declare a callback function to be called when a job has been processed. If @callback is %NULL, then any
previously
+ * effect of this function is removed. If the same function is called with a different @callback value, then
the previous one
+ * is simply replaced.
+ *
+ * Since this function adds a new source of events to the specified #GMainContext (or the default one if
@context is %NULL),
+ * FIXME.
+ *
+ * Notes:
+ * <itemizedlist>
+ * <listitem><para>before calling this function, @worker internally gets rid of the job, so the @jib_id
passed
+ * to @callback does not actually designate a known job ID, and so calling gda_worker_fetch_job_result()
for that
+ * job ID will fail</para></listitem>
+ * <listitem><para>the job's result, if any, has to be freed by @callback (@worker does not do
it)</para></listitem>
+ * <listitem><para>any call to this function will only be honored for the jobs submitted _after_ calling
it, the ones
+ * submitted before are not affected</para></listitem>
+ * <listitem><para>passing %NULL for @context is similar to passing the result of
g_main_context_ref_thread_default()</para></listitem>
+ * </itemizedlist>
+ *
+ * Returns: %TRUE if no error occurred.
+ *
+ * Since: 6.0
+ */
+gboolean
+gda_worker_set_callback (GdaWorker *worker, GMainContext *context, GdaWorkerCallback callback,
+ gpointer user_data, GError **error)
+{
+ g_return_val_if_fail (worker, FALSE);
+ g_return_val_if_fail (callback, FALSE);
+ if (!worker->callbacks_hash) {
+ g_warning ("GdaWorker has been destroyed\n");
+ return FALSE;
+ }
+
+ GMainContext *co;
+ gboolean unref_co = FALSE;
+
+ co = context;
+ if (!co) {
+ co = g_main_context_ref_thread_default ();
+ unref_co = TRUE;
+ }
+
+#ifdef DEBUG_NOTIFICATION
+ g_print ("[W] %s() GMainContext=%p, thread=%p\n", __FUNCTION__, co, g_thread_self());
+#endif
+ g_rec_mutex_lock (& worker->rmutex);
+
+ gboolean retval = TRUE;
+ DeclaredCallback *dc = NULL;
+ dc = g_hash_table_lookup (worker->callbacks_hash, co);
+
+ if (dc) {
+ if (callback) {
+ /* change callback's attributes */
+ dc->callback = callback;
+ dc->user_data = user_data;
+ }
+ else {
+ /* remove callback */
+ g_hash_table_remove (worker->callbacks_hash, co);
+ }
+ }
+ if (!dc) {
+ if (callback) {
+ /* add callback */
+ dc = declared_callback_new (worker, co, callback, user_data);
+ if (!dc) {
+ g_set_error (error, GDA_WORKER_ERROR, GDA_WORKER_INTER_THREAD_ERROR,
+ _("Cannot build inter thread communication device"));
+ g_rec_mutex_unlock (& worker->rmutex);
+ return FALSE;
+ }
+ g_hash_table_insert (worker->callbacks_hash, co, dc);
+ dc->source_sig_id = itsignaler_add (dc->its, co, (ITSignalerFunc) dc_callback, dc,
NULL);
+ if (dc->source_sig_id == 0) {
+ g_hash_table_remove (worker->callbacks_hash, co);
+ g_set_error (error, GDA_WORKER_ERROR, GDA_WORKER_INTER_THREAD_ERROR,
+ _("GdaWorker internal error"));
+ retval = FALSE;
+ }
+ }
+ else {
+ /* nothing to do */
+ }
+ }
+
+ g_rec_mutex_unlock (& worker->rmutex);
+
+ if (unref_co)
+ g_main_context_unref (co);
+
+ return retval;
+}
+
+static gboolean
+do_timer_cb (GMainLoop *loop)
+{
+ if (g_main_loop_is_running (loop))
+ g_main_loop_quit (loop);
+ return FALSE; /* remove timer */
+}
+
+static gboolean
+do_itsignaler_cb (ITSignaler *its, GMainLoop *loop)
+{
+ if (g_main_loop_is_running (loop))
+ g_main_loop_quit (loop);
+ return TRUE; /* keep */
+}
+
+/**
+ * gda_worker_do_job: (skip)
+ * @worker: a #GdaWorker object
+ * @context: (allow-none): a #GMainContext to execute a main loop in (while waiting), or %NULL
+ * @timeout_ms: the maximum number of milisecons to wait before returning, or %0 for unlimited wait
+ * @out_result: (allow-none): a place to store the result, if any, of @func's execution, or %NULL
+ * @out_job_id: (allow-none): a place to store the ID of the job having been submitted, or %NULL
+ * @func: the function to call from the worker thread
+ * @data: (allow-none): the data to pass to @func, or %NULL
+ * @data_destroy_func: (allow-none): a function to destroy @data, or %NULL
+ * @result_destroy_func: (allow-none): a function to destroy the result, if any, of @func's execution, or
%NULL
+ * @error: (allow-none): a place to store errors, or %NULL.
+ *
+ * Request that the worker thread call @func with the @data argument, much like gda_worker_submit_job(),
+ * but waits (starting a #GMainLoop) for a maximum of @timeout_ms miliseconds for @func to be executed.
+ *
+ * If this function is called from within @worker's worker thread, then this function simply calls @func
with @data.
+ *
+ * The following cases are possible if this function is not called from within @worker's worker thread:
+ * <itemizedlist>
+ * <listitem><para>the call to @func took less than @timeout_ms miliseconds: the return value is %TRUE and
+ * @out_result contains the result of the @func's execution, and @out_job_id contains %NULL. Note in this
+ * case that @error may still contain an error code if @func's execution produced an error. Also note
that in this case
+ * any setting defined by gda_worker_set_callback() is not applied (as the result is immediately
returned)</para></listitem>
+ * <listitem><para>The call to @func takes more then @timeout_ms miliseconds: the return value is %TRUE and
+ * @out_result is %NULL and @out_job_id contains the ID of the job as if it had been submitted using
gda_worker_submit_job().
+ * If @out_job_id is %NULL, and if no setting has been defined using gda_worker_set_callback(), then the
job will be discarded
+ * (as if gda_worker_forget_job() had been called).
+ * </para></listitem>
+ * <listitem><para>The call to @func could not be done (some kind of plumbing error for instance): the
returned value is %FALSE
+ * and @out_result and @out_job_id are set to %NULL (if they are not %NULL)</para></listitem>
+ * </itemizedlist>
+ *
+ * Notes:
+ * <itemizedlist>
+ * <listitem><para>@result_destroy_func is needed in case @out_result is %NULL (to avoid memory
leaks)</para></listitem>
+ * <listitem><para>passing %NULL for @context is similar to passing the result of
g_main_context_ref_thread_default()</para></listitem>
+ * </itemizedlist>
+ *
+ * Returns: %TRUE if no error occurred
+ *
+ * Since: 6.0
+ */
+gboolean
+gda_worker_do_job (GdaWorker *worker, GMainContext *context, gint timeout_ms,
+ gpointer *out_result, guint *out_job_id,
+ GdaWorkerFunc func, gpointer data, GDestroyNotify data_destroy_func,
+ GDestroyNotify result_destroy_func,
+ GError **error)
+{
+ if (out_result)
+ *out_result = NULL;
+ if (out_job_id)
+ *out_job_id = 0;
+
+ g_return_val_if_fail (worker, FALSE);
+ g_return_val_if_fail (func, FALSE);
+ if (!worker->callbacks_hash || !worker->jobs_hash) {
+ g_warning ("GdaWorker has been destroyed\n");
+ return FALSE;
+ }
+
+ if (gda_worker_thread_is_worker (worker)) {
+ /* we are called from within the worker thread => call the function directly */
+ gpointer result;
+ result = func (data, error);
+ if (data_destroy_func)
+ data_destroy_func (data);
+ if (out_result)
+ *out_result = result;
+ else if (result && result_destroy_func)
+ result_destroy_func (result);
+ return TRUE;
+ }
+
+ guint jid, itsid, timer = 0;
+
+ /* determine which GMainContext to use */
+ GMainContext *co;
+ gboolean unref_co = FALSE;
+
+ co = context;
+ if (!co) {
+ co = g_main_context_ref_thread_default ();
+ unref_co = TRUE;
+ }
+
+ /* prepare main loop */
+ GMainLoop *loop;
+ loop = g_main_loop_new (co, FALSE);
+
+ /* prepare ITSignaler to be notified */
+ ITSignaler *its;
+ its = itsignaler_new ();
+ itsid = itsignaler_add (its, co, (ITSignalerFunc) do_itsignaler_cb,
+ g_main_loop_ref (loop), (GDestroyNotify) g_main_loop_unref);
+
+ /* push job */
+ g_rec_mutex_lock (& worker->rmutex); /* required to call _gda_worker_submit_job_with_its() */
+ jid = _gda_worker_submit_job_with_its (worker, its,
+ func, data, data_destroy_func, result_destroy_func, error);
+ g_rec_mutex_unlock (& worker->rmutex);
+ if (jid == 0) {
+ /* an error occurred */
+ g_assert (itsignaler_remove (its, co, itsid));
+ itsignaler_unref (its);
+ g_main_loop_unref (loop);
+
+ if (unref_co)
+ g_main_context_unref (co);
+
+ return FALSE;
+ }
+
+ /* check if result is already here */
+ WorkerJob *job;
+ job = itsignaler_pop_notification (its, 0);
+ if (!job) {
+ if (timeout_ms > 0) {
+ /* start timer to limit waiting time */
+ GSource *timer_src;
+ timer_src = g_timeout_source_new (timeout_ms);
+ g_source_set_callback (timer_src, (GSourceFunc) do_timer_cb, loop, NULL);
+ timer = g_source_attach (timer_src, co);
+ g_source_unref (timer_src);
+ }
+ g_main_loop_run (loop);
+
+ /* either timer has arrived or job has been done */
+ job = itsignaler_pop_notification (its, 0);
+ }
+ g_main_loop_unref (loop);
+
+ g_assert (itsignaler_remove (its, co, itsid));
+ itsignaler_unref (its);
+
+ if (job) {
+ /* job done before the timer, if any, elapsed */
+
+ if (timer > 0)
+ g_assert (g_source_remove (timer));
+
+ g_assert (gda_worker_fetch_job_result (worker, jid, out_result, error));
+ }
+ else {
+ /* timer came first, job is not yet finished */
+
+ /* apply settings from gda_worker_set_callback(), if any */
+ g_rec_mutex_lock (&worker->rmutex);
+ DeclaredCallback *dc;
+ dc = g_hash_table_lookup (worker->callbacks_hash, co);
+ if (dc) {
+ job = g_hash_table_lookup (worker->jobs_hash, &jid);
+ g_assert (job);
+ g_assert (!job->reply_its);
+ job->reply_its = itsignaler_ref (dc->its);
+ }
+ g_rec_mutex_unlock (& worker->rmutex);
+
+ /* cleanups */
+ if (out_job_id)
+ *out_job_id = jid;
+ else if (!dc)
+ /* forget all about the job */
+ gda_worker_forget_job (worker, jid);
+ }
+
+ if (unref_co)
+ g_main_context_unref (co);
+
+ return TRUE;
+}
+
+/**
+ * gda_worker_wait_job: (skip)
+ * @worker: a #GdaWorker object
+ * @func: the function to call from the worker thread
+ * @data: (allow-none): the data to pass to @func, or %NULL
+ * @data_destroy_func: (allow-none): a function to destroy @data, or %NULL
+ * @error: (allow-none): a place to store errors, or %NULL.
+ *
+ * Request that the worker thread call @func with the @data argument, much like gda_worker_submit_job(),
+ * but waits (blocks) until @func has been executed.
+ *
+ * Note: it's up to the caller to free the result, the #GdaWorker object will not do it (ownership of the
result is
+ * transfered to the caller).
+ *
+ * Returns: (transfer full): the result of @func's execution
+ *
+ * Since: 6.0
+ */
+gpointer
+gda_worker_wait_job (GdaWorker *worker, GdaWorkerFunc func, gpointer data, GDestroyNotify data_destroy_func,
+ GError **error)
+{
+ g_return_val_if_fail (worker, NULL);
+ g_return_val_if_fail (func, NULL);
+
+ if (gda_worker_thread_is_worker (worker)) {
+ /* we are called from within the worker thread => call the function directly */
+ gpointer retval;
+ retval = func (data, error);
+ if (data_destroy_func)
+ data_destroy_func (data);
+ return retval;
+ }
+
+ guint jid;
+
+ /* prepare ITSignaler to be notified */
+ ITSignaler *its;
+ its = itsignaler_new ();
+
+ /* push job */
+ g_rec_mutex_lock (& worker->rmutex); /* required to call _gda_worker_submit_job_with_its() */
+ jid = _gda_worker_submit_job_with_its (worker, its,
+ func, data, data_destroy_func, NULL, error);
+ g_rec_mutex_unlock (& worker->rmutex);
+
+ if (jid == 0) {
+ /* an error occurred */
+ itsignaler_unref (its);
+ return NULL;
+ }
+
+ WorkerJob *job;
+ job = itsignaler_pop_notification (its, -1);
+ g_assert (job);
+ itsignaler_unref (its);
+
+ gpointer result;
+ g_assert (gda_worker_fetch_job_result (worker, jid, &result, error));
+
+ return result;
+}
+
+/**
+ * gda_worker_thread_is_worker: (skip)
+ * @worker: a #GdaWorker
+ *
+ * Tells if the thread from which this function is called is @worker's worker thread.
+ *
+ * Returns: %TRUE if this function is called is @worker's worker thread
+ *
+ * Since: 6.0
+ */
+gboolean
+gda_worker_thread_is_worker (GdaWorker *worker)
+{
+ g_return_val_if_fail (worker, NULL);
+ return worker->worker_thread == g_thread_self () ? TRUE : FALSE;
+}
diff --git a/libgda/thread-wrapper/gda-worker.h b/libgda/thread-wrapper/gda-worker.h
new file mode 100644
index 0000000..a34b44c
--- /dev/null
+++ b/libgda/thread-wrapper/gda-worker.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2013 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 Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GDA_WORKER_H__
+#define __GDA_WORKER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GdaWorker GdaWorker;
+
+/**
+ * SECTION:gda-worker
+ * @short_description: Execute functions in a sub thread
+ * @title: GdaWorker
+ * @stability: Stable
+ * @see_also:
+ *
+ * The purpose of the #GdaWorker object is to execute "jobs" (functions with arguments) within a worker
thread, using
+ * gda_worker_submit_job().
+ *
+ * Any code executing in any thread context can submit jobs to @worker and is guaranted not to be blocked
(except if using
+ * gda_worker_wait_job() or if the
+ * jobs are submitted within the worker thread itself). Once jobs have been submitted, it's up to the caller
to regularly
+ * check if a job has completed using gda_worker_fetch_job_result(). If you don't want to have to check
regularly (which is
+ * like some polling operation), then you can use gda_worker_set_callback() which adds a callback when any
job has completed.
+ *
+ * gda_worker_wait_job() allows you to execute a job in the worker thread while blocking the calling thread.
+ *
+ * Before fetching a jobs's result, it is also possible to request the cancellation of the job using
gda_worker_cancel_job(), or
+ * completely discard the job using gda_worker_forget_job().
+ *
+ * Jobs can also be submitted using gda_worker_do_job(), which internally runs a #GMainLoop and allows you
to execute a job
+ * while at the same time processing events for the specified #GMainContext.
+ *
+ * The #GdaWorker implements its own locking mechanism and can safely be used from multiple
+ * threads at once without needing further locking.
+ */
+
+/* error reporting */
+extern GQuark gda_worker_error_quark (void);
+#define GDA_WORKER_ERROR gda_worker_error_quark ()
+
+typedef enum {
+ GDA_WORKER_INTER_THREAD_ERROR,
+
+ GDA_WORKER_JOB_NOT_FOUND_ERROR,
+ GDA_WORKER_JOB_QUEUED_ERROR,
+ GDA_WORKER_JOB_BEING_PROCESSED_ERROR,
+ GDA_WORKER_JOB_PROCESSED_ERROR,
+ GDA_WORKER_JOB_CANCELLED_ERROR,
+ GDA_WORKER_THREAD_KILLED,
+} GdaWorkerError;
+
+GdaWorker *gda_worker_new (void);
+GdaWorker *gda_worker_ref (GdaWorker *worker);
+void gda_worker_unref (GdaWorker *worker);
+gboolean gda_worker_kill (GdaWorker *worker);
+
+/**
+ * GdaWorkerFunc:
+ * @user_data: pointer to the data (which is the argument passed to gda_worker_submit_job())
+ * @error: a place to store errors
+ * @Returns: a pointer to some data which will be returned by gda_worker_fetch_job_result()
+ *
+ * Specifies the type of function to be passed to gda_worker_submit_job(), gda_worker_do_job() and
gda_worker_wait_job().
+ */
+typedef gpointer (*GdaWorkerFunc) (gpointer user_data, GError **error);
+guint gda_worker_submit_job (GdaWorker *worker, GMainContext *callback_context,
+ GdaWorkerFunc func, gpointer data, GDestroyNotify data_destroy_func,
+ GDestroyNotify result_destroy_func, GError **error);
+
+gboolean gda_worker_fetch_job_result (GdaWorker *worker, guint job_id, gpointer *out_result, GError
**error);
+gboolean gda_worker_cancel_job (GdaWorker *worker, guint job_id, GError **error);
+void gda_worker_forget_job (GdaWorker *worker, guint job_id);
+
+gboolean gda_worker_do_job (GdaWorker *worker, GMainContext *context, gint timeout_ms,
+ gpointer *out_result, guint *out_job_id,
+ GdaWorkerFunc func, gpointer data, GDestroyNotify data_destroy_func,
+ GDestroyNotify result_destroy_func,
+ GError **error);
+gpointer gda_worker_wait_job (GdaWorker *worker,
+ GdaWorkerFunc func, gpointer data, GDestroyNotify data_destroy_func,
+ GError **error);
+
+
+typedef void (*GdaWorkerCallback) (GdaWorker *worker, guint job_id, gpointer result_data, GError *error,
gpointer user_data);
+gboolean gda_worker_set_callback (GdaWorker *worker, GMainContext *context, GdaWorkerCallback callback,
+ gpointer user_data, GError **error);
+
+gboolean gda_worker_thread_is_worker (GdaWorker *worker);
+
+G_END_DECLS
+
+#endif
diff --git a/libgda/thread-wrapper/itsignaler.c b/libgda/thread-wrapper/itsignaler.c
new file mode 100644
index 0000000..6db4167
--- /dev/null
+++ b/libgda/thread-wrapper/itsignaler.c
@@ -0,0 +1,984 @@
+/*
+ * Copyright (C) 2013 - 2014 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 Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef FORCE_NO_EVENTFD
+ /* for testing purposes */
+ #undef HAVE_EVENTFD
+#endif
+
+#define DEBUG_NOTIFICATION
+#undef DEBUG_NOTIFICATION
+
+#ifdef __GNUC__
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#else
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif
+
+#include "itsignaler.h"
+#include <unistd.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <glib-object.h>
+
+/* optimizations */
+static guint spare_size = 0; /* optimized spare size */
+static guint created_objects = 0; /* counter of all the ITSignaler objects ever created */
+static GPtrArray *spare_array = NULL;
+static GMutex spare_mutex; /* to protect @spare_array */
+
+
+#ifdef G_OS_WIN32
+ #define INVALID_SOCK INVALID_SOCKET
+ #define SIGNALER_PORT 5906
+#else
+ #define _GNU_SOURCE
+ #include <sys/types.h>
+ #include <fcntl.h>
+ #ifdef HAVE_EVENTFD
+ #include <sys/eventfd.h>
+ #else
+
+ #endif
+ #define INVALID_SOCK -1
+ #include <poll.h>
+#endif
+
+typedef struct {
+ gpointer data;
+ GDestroyNotify destroy_func;
+} NotificationData;
+
+/*
+ * Threads synchronization with notifications
+ *
+ * Use a GAsyncQueue to pass notifications from one thread to the other.
+ *
+ * Windows specific implementation:
+ * Use a client/server pair of sockets, waiting can be done on the reading socket
+ *
+ * Unix specific implementation:
+ * If HAVE_EVENTFD is defined (Linux extension), then use eventfd(), else use a pair of file descriptors
obtained
+ * using pipe()
+ *
+ */
+struct _ITSignaler {
+ guint8 broken; /* TRUE if the object has suffered an unrecoverable error */
+ guint8 spared; /* TRUE if the object is in the spare array and should not be used */
+
+#ifdef HAVE_FORK
+ /* detect forked process */
+ pid_t pid;
+#endif
+
+ /* data queue */
+ GAsyncQueue *data_queue;
+
+ /* signaling mechanism */
+#ifdef G_OS_WIN32
+ SOCKET socks[2]; /* [0] for reading and [1] for writing */
+#else
+ #ifdef HAVE_EVENTFD
+ int event_fd;
+ #else
+ int fds[2]; /* [0] for reading and [1] for writing */
+ GIOChannel *ioc;
+ #endif
+#endif
+
+ /* reference count, thread safe */
+ guint ref_count;
+ GMutex mutex;
+};
+
+#define itsignaler_lock(x) g_mutex_lock(& (((ITSignaler*)x)->mutex))
+#define itsignaler_unlock(x) g_mutex_unlock(& (((ITSignaler*)x)->mutex))
+
+/**
+ * itsignaler_ref:
+ * @its: (allow-none): a #ITSignaler object
+ *
+ * Increases the reference count of @its. If @its is %NULL, then nothing happens.
+ *
+ * This function can be called from any thread.
+ *
+ * Returns: @its
+ */
+ITSignaler *
+itsignaler_ref (ITSignaler *its)
+{
+ if (its) {
+ g_assert (!its->spared);
+ itsignaler_lock (its);
+ its->ref_count++;
+#ifdef DEBUG_NOTIFICATION
+ g_print ("[I] ITSignaler %p ++: %u\n", its, its->ref_count);
+#endif
+ itsignaler_unlock (its);
+ }
+ return its;
+}
+
+static void
+cleanup_signaling (ITSignaler *its)
+{
+#ifdef G_OS_WIN32
+ int rc;
+ if (its->socks[1] != INVALID_SOCKET) {
+ struct linger so_linger = { 1, 0 };
+ rc = setsockopt (its->socks[1], SOL_SOCKET, SO_LINGER,
+ (char *)&so_linger, sizeof (so_linger));
+ g_assert (rc != SOCKET_ERROR);
+ rc = closesocket (its->socks[1]);
+ g_assert (rc != SOCKET_ERROR);
+ its->socks [1] = INVALID_SOCKET;
+ }
+ if (its->socks[0] != INVALID_SOCKET) {
+ rc = closesocket (its->socks[0]);
+ g_assert (rc != SOCKET_ERROR);
+ its->socks [0] = INVALID_SOCKET;
+ }
+#else
+ #ifdef HAVE_EVENTFD
+ if (its->event_fd != INVALID_SOCK) {
+ g_assert (close (its->event_fd) == 0);
+ its->event_fd = INVALID_SOCK;
+ }
+ #else
+ if (its->fds[0] != INVALID_SOCK) {
+ g_assert (close (its->fds[0]) == 0);
+ its->fds[0] = INVALID_SOCK;
+ }
+ if (its->fds[1] != INVALID_SOCK) {
+ g_assert (close (its->fds[1]) == 0);
+ its->fds[1] = INVALID_SOCK;
+ }
+ #endif
+#endif
+}
+
+static void
+itsignaler_reset (ITSignaler *its)
+{
+ g_assert (its->ref_count == 0);
+#ifdef G_OS_WIN32
+ guint8 value;
+ ssize_t nr;
+ for (nr = recv (its->socks[0], (char*) &value, sizeof (value), 0);
+ nr >= 0;
+ nr = recv (its->socks[0], (char*) &value, sizeof (value), 0));
+ g_assert (nr == -1);
+#else
+ #ifdef HAVE_EVENTFD
+ guint64 nbnotif;
+ ssize_t nr = read (its->event_fd, &nbnotif, sizeof (nbnotif));
+ nr = read (its->event_fd, &nbnotif, sizeof (nbnotif));
+ g_assert (nr == -1);
+ #else
+ guint8 value;
+ ssize_t nr;
+ for (nr = read (its->fds[0], &value, sizeof (value));
+ nr >= 0;
+ nr = read (its->fds[0], &value, sizeof (value)));
+ g_assert (nr == -1);
+ #endif
+#endif
+ NotificationData *nd;
+ for (nd = g_async_queue_try_pop (its->data_queue);
+ nd;
+ nd = g_async_queue_try_pop (its->data_queue)) {
+ if (nd->data && nd->destroy_func)
+ nd->destroy_func (nd->data);
+ }
+}
+
+static void
+itsignaler_free (ITSignaler *its)
+{
+ /* destroy @its */
+ GMutex *m = &(its->mutex);
+ cleanup_signaling (its);
+
+ /* clear queue's contents */
+ g_async_queue_unref (its->data_queue);
+
+#ifdef DEBUG_NOTIFICATION
+ g_print ("[I] Destroyed ITSignaler %p\n", its);
+#endif
+ g_mutex_unlock (m);
+ g_mutex_clear (m);
+
+ g_free (its);
+}
+
+static void
+trim_spares (void)
+{
+ g_mutex_lock (&spare_mutex);
+ for (;spare_array->len > spare_size + 1;) {
+ ITSignaler *its;
+ its = g_ptr_array_remove_index_fast (spare_array, spare_array->len - 1);
+#ifdef DEBUG_NOTIFICATION
+ g_print ("[I] Trimming operation: get rid of ITSignaler %p\n", its);
+#endif
+ itsignaler_free (its);
+ }
+ g_mutex_unlock (&spare_mutex);
+}
+
+/**
+ * itsignaler_unref:
+ * @its: (allow-none): a #ITSignaler object
+ *
+ * Decrease the reference count of @its; when the rerefence count reaches zero, the object
+ * is freed. If @its is %NULL, then nothing happens.
+ *
+ * This function can be called from any thread.
+ */
+void
+itsignaler_unref (ITSignaler *its)
+{
+ if (its) {
+ g_assert (!its->spared);
+ itsignaler_lock (its);
+ its->ref_count--;
+#ifdef DEBUG_NOTIFICATION
+ g_print ("[I] ITSignaler %p --: %u\n", its, its->ref_count);
+#endif
+ if (its->ref_count == 0) {
+ spare_size--;
+ itsignaler_unlock (its);
+
+ /* destroy or store as spare */
+ g_mutex_lock (&spare_mutex);
+ if (!its->broken && (spare_array->len < spare_size)) {
+ itsignaler_reset (its);
+ g_ptr_array_add (spare_array, its);
+ its->spared = TRUE;
+ }
+ else {
+ itsignaler_unlock (its);
+ itsignaler_free (its);
+ }
+ g_mutex_unlock (&spare_mutex);
+
+ trim_spares ();
+ }
+ else
+ itsignaler_unlock (its);
+ }
+}
+
+static void
+notification_data_free (NotificationData *nd)
+{
+ if (nd->data && nd->destroy_func)
+ nd->destroy_func (nd->data);
+ g_free (nd);
+}
+
+/**
+ * itsignaler_new:
+ *
+ * Creates a new #ITSignaler object.
+ *
+ * Returns: a new #ITSignaler, or %NULL if an error occurred. Use itsignaler_unref() when not needed anymore.
+ */
+ITSignaler *
+itsignaler_new (void)
+{
+ ITSignaler *its;
+ gboolean err = FALSE;
+
+ if (G_UNLIKELY (! spare_array)) {
+ static GMutex registering;
+ g_mutex_lock (®istering);
+ g_mutex_init (&spare_mutex);
+ if (!spare_array)
+ spare_array = g_ptr_array_new ();
+ g_mutex_unlock (®istering);
+ }
+
+ trim_spares ();
+
+ g_mutex_lock (&spare_mutex);
+ if (spare_array->len > 0) {
+ /* pick up the 1st spare */
+ its = g_ptr_array_remove_index_fast (spare_array, spare_array->len - 1);
+ its->ref_count = 1;
+ its->spared = FALSE;
+ spare_size++;
+#ifdef DEBUG_NOTIFICATION
+ g_print ("[I]: Reused ITS %p, total created ITSignaler objects: %u, spare size: %u, nb in
spare: %d\n", its, created_objects, spare_size, spare_array->len);
+#endif
+ g_mutex_unlock (&spare_mutex);
+
+ return its;
+ }
+ g_mutex_unlock (&spare_mutex);
+
+ its = g_new0 (ITSignaler, 1);
+ its->ref_count = 1;
+ its->broken = FALSE;
+ its->spared = FALSE;
+
+#ifdef G_OS_WIN32
+ SECURITY_DESCRIPTOR sd;
+ SECURITY_ATTRIBUTES sa;
+ memset (&sd, 0, sizeof (sd));
+ memset (&sa, 0, sizeof (sa));
+
+ InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
+ SetSecurityDescriptorDacl (&sd, TRUE, 0, FALSE);
+
+ sa.nLength = sizeof (SECURITY_ATTRIBUTES);
+ sa.lpSecurityDescriptor = &sd;
+
+ DWORD dwrc;
+ HANDLE sync = CreateEvent (&sa, FALSE, TRUE, TEXT ("Global\\gda-signaler-port"));
+ if (!sync && (GetLastError () == ERROR_ACCESS_DENIED))
+ sync = OpenEvent (SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE, TEXT
("Global\\gda-signaler-port"));
+ if (!sync ||
+ ((dwrc = WaitForSingleObject (sync, INFINITE)) != WAIT_OBJECT_0)) {
+ err = TRUE;
+ goto next;
+ }
+
+ /* Windows has no 'socketpair' function. CreatePipe is no good as pipe
+ * handles cannot be polled on. Here we create the socketpair by hand
+ */
+ its->socks [0] = INVALID_SOCKET;
+ its->socks [1] = INVALID_SOCKET;
+
+ /* Initialize sockets */
+ static gboolean init_done = FALSE;
+ if (!init_done) {
+ WORD version_requested = MAKEWORD (2, 2);
+ WSADATA wsa_data;
+ int rc = WSAStartup (version_requested, &wsa_data); // FIXME: call WSACleanup() somehow...
+ if ((rc != 0) || (LOBYTE (wsa_data.wVersion) != 2) || (HIBYTE (wsa_data.wVersion) != 2)) {
+ err = TRUE;
+ goto next;
+ }
+ init_done = TRUE;
+ }
+
+ /* Create listening socket */
+ SOCKET listener;
+ listener = socket (AF_INET, SOCK_STREAM, 0);
+ if (listener == INVALID_SOCKET) {
+ err = TRUE;
+ goto next;
+ }
+
+ /* preventing sockets to be inherited by child processes */
+ BOOL brc = SetHandleInformation ((HANDLE) listener, HANDLE_FLAG_INHERIT, 0);
+ if (!brc) {
+ closesocket (listener);
+ err = TRUE;
+ goto next;
+ }
+
+ /* Set SO_REUSEADDR and TCP_NODELAY on listening socket */
+ BOOL so_reuseaddr = 1;
+ int rc = setsockopt (listener, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&so_reuseaddr, sizeof (so_reuseaddr));
+ if (rc == SOCKET_ERROR) {
+ closesocket (listener);
+ err = TRUE;
+ goto next;
+ }
+
+ BOOL tcp_nodelay = 1;
+ rc = setsockopt (listener, IPPROTO_TCP, TCP_NODELAY,
+ (char *)&tcp_nodelay, sizeof (tcp_nodelay));
+ if (rc == SOCKET_ERROR) {
+ closesocket (listener);
+ err = TRUE;
+ goto next;
+ }
+
+ /* Bind listening socket to signaler port */
+ struct sockaddr_in addr;
+ memset (&addr, 0, sizeof (addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+ addr.sin_port = htons (SIGNALER_PORT);
+ rc = bind (listener, (const struct sockaddr*) &addr, sizeof (addr));
+ if (rc == SOCKET_ERROR) {
+ closesocket (listener);
+ err = TRUE;
+ goto next;
+ }
+
+ /* Listen for incomming connections */
+ rc = listen (listener, 1);
+ if (rc == SOCKET_ERROR) {
+ closesocket (listener);
+ err = TRUE;
+ goto next;
+ }
+
+ /* Create the writer socket */
+ its->socks[1] = WSASocket (AF_INET, SOCK_STREAM, 0, NULL, 0, 0);
+ if (its->socks[1] == INVALID_SOCKET) {
+ err = TRUE;
+ goto next;
+ }
+
+ /* Preventing sockets to be inherited by child processes */
+ brc = SetHandleInformation ((HANDLE) its->socks[1], HANDLE_FLAG_INHERIT, 0);
+ if (!brc) {
+ err = TRUE;
+ goto next;
+ }
+
+ /* Set TCP_NODELAY on writer socket */
+ rc = setsockopt (its->socks[1], IPPROTO_TCP, TCP_NODELAY,
+ (char *)&tcp_nodelay, sizeof (tcp_nodelay));
+ if (rc == SOCKET_ERROR) {
+ err = TRUE;
+ goto next;
+ }
+
+ /* Connect writer to the listener */
+ rc = connect (its->socks[1], (struct sockaddr*) &addr, sizeof (addr));
+
+ /* Accept connection from writer */
+ its->socks[0] = accept (listener, NULL, NULL);
+
+ /* We don't need the listening socket anymore. Close it */
+ rc = closesocket (listener);
+ if (rc == SOCKET_ERROR) {
+ err = TRUE;
+ goto next;
+ }
+
+ /* Exit the critical section */
+ brc = SetEvent (sync);
+ if (!brc) {
+ err = TRUE;
+ goto next;
+ }
+
+ if (its->socks[0] == INVALID_SOCKET) {
+ err = TRUE;
+ closesocket (its->socks[1]);
+ its->socks[1] = INVALID_SOCKET;
+ goto next;
+ }
+
+ /* Set non blocking mode */
+ u_long nonblock = 1;
+ rc = ioctlsocket (its->socks[0], FIONBIO, &nonblock);
+ if (rc == SOCKET_ERROR) {
+ err = TRUE;
+ goto next;
+ }
+
+ /* Preventing sockets to be inherited by child processes */
+ brc = SetHandleInformation ((HANDLE) its->socks[0], HANDLE_FLAG_INHERIT, 0);
+ if (!brc) {
+ err = TRUE;
+ goto next;
+ }
+#else
+ #ifdef HAVE_EVENTFD
+ its->event_fd = eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC);
+ if (its->event_fd == INVALID_SOCK) {
+ err = TRUE;
+ goto next;
+ }
+ #else /* HAVE_EVENTFD */
+ if (pipe (its->fds) != 0) {
+ err = TRUE;
+ goto next;
+ }
+
+ /* set read to non blocking */
+ int flags;
+ flags = fcntl (its->fds[0], F_GETFL, 0);
+ if (flags < 0)
+ err = TRUE;
+ else {
+ flags = flags | O_NONBLOCK;
+ #ifdef HAVE_FD_CLOEXEC
+ flags = flags | FD_CLOEXEC;
+ #endif
+ if (fcntl (its->fds[0], F_SETFL, flags) < 0)
+ err = TRUE;
+ }
+ #endif /* HAVE_EVENTFD */
+#endif /* G_OS_WIN32 */
+
+ next:
+ if (err) {
+ cleanup_signaling (its);
+ g_free (its);
+ return NULL;
+ }
+
+ /* finish init */
+ its->data_queue = g_async_queue_new_full ((GDestroyNotify) notification_data_free);
+ g_mutex_init (&(its->mutex));
+
+#ifdef HAVE_FORK
+ its->pid = getpid ();
+#endif
+
+ if (err) {
+ its->broken = TRUE;
+ itsignaler_unref (its);
+ return NULL;
+ }
+
+#ifdef DEBUG_NOTIFICATION
+ g_print ("[I] Created ITSignaler %p\n", its);
+#endif
+
+ created_objects++;
+ spare_size++;
+#ifdef DEBUG_NOTIFICATION
+ g_print ("[I]: total created ITSignaler objects: %u, spare size: %u\n", created_objects, spare_size);
+#endif
+ return its;
+}
+
+#ifdef G_OS_WIN32
+/**
+ * itsignaler_windows_get_poll_fd:
+ * @its: a #ITSignaler object
+ *
+ * Get the socket descriptor associated to @its.
+ *
+ * Returns: the file descriptor number, or -1 on error
+ */
+SOCKET
+itsignaler_windows_get_poll_fd (ITSignaler *its)
+{
+ g_return_val_if_fail (its, -1);
+ g_assert (!its->spared);
+ return its->socks[0];
+}
+
+#else
+
+/**
+ * itsignaler_unix_get_poll_fd:
+ * @its: a #ITSignaler object
+ *
+ * Get the file descriptor associated to @its.
+ *
+ * Returns: the file descriptor number, or -1 on error
+ */
+int
+itsignaler_unix_get_poll_fd (ITSignaler *its)
+{
+ g_return_val_if_fail (its, -1);
+ g_assert (!its->spared);
+
+#ifdef HAVE_EVENTFD
+ return its->event_fd;
+#else
+ return its->fds[0];
+#endif
+}
+#endif /* G_OS_WIN32 */
+
+/**
+ * itsignaler_push_notification:
+ * @its: a #ITSignaler pointer
+ * @data: a pointer to some data.
+ * @destroy_func: (allow-none): a function to be called to free @data, or %NULL
+ *
+ * Use this function to push a notification.
+ *
+ * Note that @data will be passes AS-IS to the thread which calls itsignaler_pop_notification(), any memory
allocation
+ * must be handled correctly by the caller. However, in case itsignaler_unref() is called while there are
still some
+ * undelivered notifications, each notification's data will be freed using the @destroy_func which was
specified when
+ * itsignaler_push_notification() was called (note that no warning of any sort will be shown if
@destroy_func is %NULL
+ * and some notification data should have been freed).
+ *
+ * Returns: %TRUE if no error occurred
+ */
+gboolean
+itsignaler_push_notification (ITSignaler *its, gpointer data, GDestroyNotify destroy_func)
+{
+ g_return_val_if_fail (its, FALSE);
+ g_return_val_if_fail (data, FALSE);
+ g_assert (!its->spared);
+
+ if (its->broken)
+ return FALSE;
+
+#ifdef HAVE_FORK
+ if (unlikely (its->pid != getpid ()))
+ return FALSE;
+#endif
+
+#ifdef DEBUG_NOTIFICATION_FORCE
+ /* force an error */
+ static guint c = 0;
+ c++;
+ if (c == 4)
+ goto onerror;
+#endif
+
+ /* push notification to queue */
+ NotificationData *nd;
+ nd = g_new (NotificationData, 1);
+ nd->data = data;
+ nd->destroy_func = destroy_func;
+ g_async_queue_push (its->data_queue, nd);
+
+ /* actual notification */
+#ifdef G_OS_WIN32
+ const guint8 value = 1;
+ ssize_t nw;
+ nw = send (its->socks[1], (char*) &value, sizeof (value), 0);
+ if (nw != sizeof (value))
+ goto onerror; /* Error */
+#else
+ #ifdef HAVE_EVENTFD
+ const uint64_t inc = 1;
+ ssize_t nw;
+ nw = write (its->event_fd, &inc, sizeof (inc));
+ if (nw != sizeof (inc))
+ goto onerror; /* Error */
+ #else
+ const guint8 value = 1;
+ ssize_t nw;
+ nw = write (its->fds[1], &value, sizeof (value));
+ if (nw != sizeof (value))
+ goto onerror; /* Error */
+ #endif
+#endif
+
+ return TRUE;
+
+ onerror:
+ its->broken = TRUE;
+ cleanup_signaling (its);
+
+#ifdef DEBUG_NOTIFICATION
+ g_print ("[I] %s(): returned FALSE\n", __FUNCTION__);
+ g_print ("[I] ITSignaler will not be useable anymore\n");
+#endif
+ return FALSE;
+}
+
+static gpointer
+itsignaler_pop_notification_non_block (ITSignaler *its)
+{
+ g_return_val_if_fail (its, NULL);
+
+#ifdef G_OS_WIN32
+ guint8 value;
+ ssize_t nr = recv (its->socks[0], (char*) &value, sizeof (value), 0);
+ if (nr == -1)
+ return NULL; /* nothing to read */
+ else
+ g_assert (nr == sizeof (value));
+#else
+ #ifdef HAVE_EVENTFD
+ guint64 nbnotif;
+ ssize_t nr = read (its->event_fd, &nbnotif, sizeof (nbnotif));
+ if (nr == -1) {
+ return NULL; /* nothing to read */
+ }
+ else
+ g_assert (nr == sizeof (nbnotif));
+ nbnotif --;
+
+ if (nbnotif > 0) {
+ /* some other notifications need to be processed */
+ ssize_t nw;
+ nw = write (its->event_fd, &nbnotif, sizeof (nbnotif));
+ if (nw != sizeof (nbnotif)) {
+ close (its->event_fd);
+ its->event_fd = INVALID_SOCK;
+ its->broken = TRUE;
+ }
+ }
+ #else
+ guint8 value;
+ ssize_t nr = read (its->fds[0], &value, sizeof (value));
+ if (nr == -1)
+ return NULL; /* nothing to read */
+ else
+ g_assert (nr == sizeof (value));
+ #endif
+#endif
+
+ /* actual notification contents */
+ NotificationData *nd;
+ nd = (NotificationData*) g_async_queue_try_pop (its->data_queue);
+ if (nd) {
+ gpointer retval;
+ retval = nd->data;
+ g_free (nd);
+ return retval;
+ }
+ else
+ return NULL;
+}
+
+/**
+ * itsignaler_pop_notification:
+ * @its: a #ITSignaler object
+ * @timeout_ms: if set to %0, then the function returns immediately if there is no notification, if set to a
negative value, then this function blocks until a notification becomes available, otherwise maximum number of
miliseconds to wait for a notification.
+ *
+ * Use this function from the thread to be signaled, to fetch any pending notification. If no notification
is available,
+ * then this function returns immediately %NULL. It's up to the caller to free the returned data.
+ *
+ * Returns: a pointer to some data which has been pushed by the notifying thread using
itsignaler_push_notification(), or %NULL
+ * if no notification is present.
+ */
+gpointer
+itsignaler_pop_notification (ITSignaler *its, gint timeout_ms)
+{
+ g_return_val_if_fail (its, NULL);
+ g_assert (!its->spared);
+
+ if (timeout_ms == 0)
+ return itsignaler_pop_notification_non_block (its);
+
+#ifdef G_OS_WIN32
+ struct timeval *timeout_ptr = NULL;
+ fd_set fds;
+ SOCKET sock;
+
+ if (timeout_ms > 0) {
+ struct timeval timeout;
+ timeout.tv_sec = timeout_ms / 1000;
+ timeout.tv_usec = (timeout_ms - (timeout.tv_sec * 1000)) * 1000;
+ timeout_ptr = &timeout;
+ }
+ sock = itsignaler_windows_get_poll_fd (its);
+ FD_ZERO (&fds);
+ FD_SET (sock, &fds);
+
+ int res;
+ res = select (1, &fds, 0, 0, timeout_ptr);
+ if (res == SOCKET_ERROR)
+ return NULL;
+ else if (res > 0)
+ return itsignaler_pop_notification_non_block (its);
+#else
+ struct pollfd fds[1];
+ fds[0].fd = itsignaler_unix_get_poll_fd (its);
+ fds[0].events = POLLIN;
+ fds[0].revents = 0;
+
+ int res;
+ res = poll (fds, 1, timeout_ms);
+ if (res == -1)
+ return NULL;
+ else if (res > 0) {
+ if (fds[0].revents | POLLIN)
+ return itsignaler_pop_notification_non_block (its);
+ else
+ return NULL;
+ }
+#endif
+
+ return NULL;
+}
+
+/*
+ * GSource integration
+ */
+typedef struct {
+ GSource source;
+ ITSignaler *its; /* reference held */
+#ifndef G_OS_WIN32
+ GPollFD pollfd;
+#endif
+} ITSSource;
+
+static gboolean its_source_prepare (GSource *source, gint *timeout_);
+static gboolean its_source_check (GSource *source);
+static gboolean its_source_dispatch (GSource *source, GSourceFunc callback, gpointer user_data);
+static void its_source_finalize (GSource *source);
+
+GSourceFuncs funcs = {
+ its_source_prepare,
+ its_source_check,
+ its_source_dispatch,
+ its_source_finalize
+};
+
+/**
+ * itsignaler_create_source:
+ * @its: a #ITSignaler object
+ *
+ * Create a new #GSource for @its.
+ *
+ * The source will not initially be associated with any #GMainContext and must be added to one
+ * with g_source_attach() before it will be executed.
+ *
+ * Returns: a new #GSource.
+ */
+GSource *
+itsignaler_create_source (ITSignaler *its)
+{
+ g_return_val_if_fail (its, NULL);
+ g_assert (!its->spared);
+
+ GSource *source;
+ ITSSource *isource;
+ source = g_source_new (&funcs, sizeof (ITSSource));
+ isource = (ITSSource*) source;
+ isource->its = itsignaler_ref (its);
+
+#ifdef G_OS_WIN32
+ SOCKET sock;
+ GIOChannel *channel;
+ sock = itsignaler_windows_get_poll_fd (its);
+ channel = g_io_channel_win32_new_socket (sock);
+ GSource *child_source;
+ child_source = g_io_create_watch (channel, G_IO_IN | G_IO_HUP | G_IO_ERR);
+ g_source_add_child_source (source, child_source);
+ g_source_set_dummy_callback (child_source);
+ g_io_channel_unref (channel);
+ g_source_unref (child_source);
+#else
+ isource->pollfd.fd = itsignaler_unix_get_poll_fd (its);
+ isource->pollfd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
+ isource->pollfd.revents = 0;
+ g_source_add_poll (source, &(isource->pollfd));
+#endif
+
+ return source;
+}
+
+static gboolean
+its_source_prepare (GSource *source, gint *timeout_)
+{
+ ITSSource *isource = (ITSSource*) source;
+ g_assert (! isource->its->spared);
+ *timeout_ = -1;
+ return FALSE;
+}
+
+static gboolean
+its_source_check (GSource *source)
+{
+ ITSSource *isource = (ITSSource*) source;
+ g_assert (! isource->its->spared);
+
+#ifndef G_OS_WIN32
+ if (isource->pollfd.revents & G_IO_IN)
+ return TRUE;
+
+ if (isource->pollfd.revents & (G_IO_HUP | G_IO_ERR)) {
+ g_source_remove_poll (source, &(isource->pollfd));
+ isource->its->broken = TRUE;
+ cleanup_signaling (isource->its);
+ g_warning ("ITSignaler %p: ERROR HUP or ERR!\n", isource->its);
+ }
+#endif
+ return FALSE;
+}
+
+static gboolean
+its_source_dispatch (GSource *source, GSourceFunc callback, gpointer user_data)
+{
+ ITSSource *isource = (ITSSource*) source;
+ g_assert (! isource->its->spared);
+ ITSignalerFunc func;
+ func = (ITSignalerFunc) callback;
+
+ gboolean retval;
+ itsignaler_ref (isource->its);
+ retval = func (isource->its, user_data);
+ itsignaler_unref (isource->its);
+ return retval;
+}
+
+static
+void its_source_finalize (GSource *source)
+{
+ ITSSource *isource = (ITSSource*) source;
+ g_assert (! isource->its->spared);
+ itsignaler_unref (isource->its);
+}
+
+/**
+ * itsignaler_add:
+ * @its: a #ITSignaler object
+ * @context: (allow-none): a GMainContext (if NULL, the default context will be used).
+ * @func: callback function to be called when a notification is ready
+ * @data: data to pass to @func
+ * @notify: (allow-none): a function to call when data is no longer in use, or NULL.
+ *
+ * Have @its call @func (with @data) in the context of @context. Remove using itsignaler_remove(). This
function
+ * is similar to itsignaler_create_source() but is packaged for easier usage.
+ *
+ * Use itsignaler_remove() to undo this function.
+ *
+ * Returns: the ID (greater than 0) for the source within the #GMainContext.
+ */
+guint
+itsignaler_add (ITSignaler *its, GMainContext *context, ITSignalerFunc func, gpointer data, GDestroyNotify
notify)
+{
+ GSource *source;
+ guint id;
+
+ g_return_val_if_fail (its, 0);
+ g_assert (! its->spared);
+
+ source = itsignaler_create_source (its);
+ if (!source)
+ return 0;
+
+ g_source_set_callback (source, (GSourceFunc) func, data, notify);
+ id = g_source_attach (source, context);
+ g_source_unref (source);
+
+ return id;
+}
+
+/**
+ * itsignaler_remove:
+ * @its: a #ITSignaler object
+ * @context: (allow-none): a GMainContext (if NULL, the default context will be used).
+ * @id: the ID of the source as returned by itsignaler_add()
+ *
+ * Does the reverse of itsignaler_add().
+ *
+ * Returns: %TRUE if the source has been removed
+ */
+gboolean
+itsignaler_remove (ITSignaler *its, GMainContext *context, guint id)
+{
+ GSource *source;
+ g_assert (! its->spared);
+ source = g_main_context_find_source_by_id (context, id);
+ if (source) {
+ g_source_destroy (source);
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
diff --git a/libgda/thread-wrapper/itsignaler.h b/libgda/thread-wrapper/itsignaler.h
new file mode 100644
index 0000000..490e189
--- /dev/null
+++ b/libgda/thread-wrapper/itsignaler.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2013 - 2014 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 Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __ITSIGNALER_H__
+#define __ITSIGNALER_H__
+
+#include <glib.h>
+#ifdef G_OS_WIN32
+ #include <winsock2.h>
+#endif
+
+G_BEGIN_DECLS
+
+typedef struct _ITSignaler ITSignaler;
+
+ITSignaler *itsignaler_new (void);
+
+#ifdef G_OS_WIN32
+SOCKET itsignaler_windows_get_poll_fd (ITSignaler *its);
+#else
+int itsignaler_unix_get_poll_fd (ITSignaler *its);
+#endif
+
+ITSignaler *itsignaler_ref (ITSignaler *its);
+void itsignaler_unref (ITSignaler *its);
+
+gboolean itsignaler_push_notification (ITSignaler *its, gpointer data, GDestroyNotify destroy_func);
+gpointer itsignaler_pop_notification (ITSignaler *its, gint timeout_ms);
+
+GSource *itsignaler_create_source (ITSignaler *its);
+
+/*
+ * Returns: %FALSE if the source should be removed from the poll
+ */
+typedef gboolean (*ITSignalerFunc) (ITSignaler *its, gpointer user_data);
+
+guint itsignaler_add (ITSignaler *its, GMainContext *context, ITSignalerFunc func, gpointer data,
GDestroyNotify notify);
+gboolean itsignaler_remove (ITSignaler *its, GMainContext *context, guint id);
+
+G_END_DECLS
+
+#endif
diff --git a/libgda/thread-wrapper/test-blocking-itsignaler.c
b/libgda/thread-wrapper/test-blocking-itsignaler.c
new file mode 100644
index 0000000..c273072
--- /dev/null
+++ b/libgda/thread-wrapper/test-blocking-itsignaler.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2013 Vivien Malerba <malerba gnome-db org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include "itsignaler.h"
+#include <stdlib.h>
+
+/*
+ * Data to be passed between threads
+ */
+typedef struct {
+ gchar dummy[10000];
+ gint counter;
+} Data;
+
+static gpointer thread1_start (ITSignaler *its);
+
+int
+main (int argc, char** argv)
+{
+ g_print ("Test started\n");
+
+ ITSignaler *its;
+ its = itsignaler_new ();
+
+ Data *data;
+
+ /* simple blocking when there is non notification to pop */
+ GTimer *timer;
+ gdouble waited;
+ timer = g_timer_new ();
+ data = itsignaler_pop_notification (its, 500);
+ if (data) {
+ g_print ("itsignaler_pop_notification() sould have returned NULL\n");
+ return EXIT_FAILURE;
+ }
+ g_timer_stop (timer);
+ waited = g_timer_elapsed (timer, NULL);
+ g_timer_destroy (timer);
+ g_print ("Waited for %.0f ms\n", waited * 1000);
+ if ((waited < 0.5) || (waited > 0.55))
+ return EXIT_FAILURE;
+
+ /* waiting with a notification to pop */
+ GThread *th;
+ th = g_thread_new ("sub", (GThreadFunc) thread1_start, its);
+ timer = g_timer_new ();
+ data = itsignaler_pop_notification (its, 500);
+ if (!data) {
+ g_print ("itsignaler_pop_notification() should have returned a value\n");
+ return EXIT_FAILURE;
+ }
+ g_timer_stop (timer);
+ waited = g_timer_elapsed (timer, NULL);
+ g_timer_destroy (timer);
+ g_print ("Waited for %.0f ms\n", waited * 1000);
+ if (strcmp (data->dummy, "Delayed...") || (data->counter != 345)) {
+ g_print ("itsignaler_pop_notification() returned an unexpected notification content\n");
+ return EXIT_FAILURE;
+ }
+ g_free (data);
+ g_thread_join (th);
+
+ return EXIT_SUCCESS;
+}
+
+/*
+ * Send notifications from this thread, to be caught in the main thread
+ */
+static gpointer
+thread1_start (ITSignaler *its)
+{
+ itsignaler_ref (its);
+ g_usleep (300000);
+
+ Data *data;
+ data = g_new0 (Data, 1);
+ strcpy (data->dummy, "Delayed...");
+ data->counter = 345;
+#ifndef PERF
+ g_print ("Pushing %d...\n", data->counter);
+#endif
+ itsignaler_push_notification (its, data, g_free);
+ itsignaler_unref (its);
+ return (gpointer) 0x01;
+}
diff --git a/libgda/thread-wrapper/test-connect.c b/libgda/thread-wrapper/test-connect.c
new file mode 100644
index 0000000..f94c875
--- /dev/null
+++ b/libgda/thread-wrapper/test-connect.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2014 Vivien Malerba <malerba gnome-db org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include "gda-connect.h"
+#include "dummy-object.h"
+#include <stdlib.h>
+
+int test1 (void);
+
+int
+main (int argc, char** argv)
+{
+ gint nfailed = 0;
+#if GLIB_CHECK_VERSION(2,36,0)
+#else
+ g_type_init ();
+#endif
+
+ nfailed += test1 ();
+
+ return nfailed > 0 ? 1 : 0;
+}
+
+static gboolean
+idle_stop_main_loop (GMainLoop *loop)
+{
+ g_main_loop_quit (loop);
+ return FALSE; /* remove the source */
+}
+
+/***********************************************/
+
+typedef struct {
+ GThread *exp_thread;
+ guint counter;
+} SigData;
+
+static void
+sig0_cb (DummyObject *obj, SigData *data)
+{
+ g_print ("%s() called from thread %p\n", __FUNCTION__, g_thread_self());
+
+ if (data->exp_thread != g_thread_self ()) {
+ g_print ("%s() called from the wrong thread!\n", __FUNCTION__);
+ exit (1); /* failed! */
+ }
+ data->counter++;
+}
+
+/*
+ * Emit signals from this thread, to be caught in the main thread
+ */
+static gpointer
+thread1_start (DummyObject *obj)
+{
+ g_signal_emit_by_name (obj, "sig0");
+ return (gpointer) 0x01;
+}
+
+int
+test1 (void)
+{
+ g_print ("Test1 started\n");
+ gint retval = 0;
+
+ DummyObject *obj;
+ obj = dummy_object_new ();
+
+ SigData sig_data;
+ sig_data.exp_thread = g_thread_self ();
+ sig_data.counter = 0;
+
+ gulong hid;
+ hid = gda_connect (obj, "sig0",
+ G_CALLBACK (sig0_cb),
+ &sig_data, NULL, G_CONNECT_SWAPPED, NULL);
+
+ /* prepare loop */
+ GMainLoop *loop;
+ loop = g_main_loop_new (NULL, FALSE);
+ g_timeout_add (100, (GSourceFunc) idle_stop_main_loop, loop); /* stop main loop after 100 ms */
+
+ /* run thread to emit signals */
+ GThread *th;
+ th = g_thread_new ("sub", (GThreadFunc) thread1_start, obj);
+
+ g_signal_emit_by_name (obj, "sig0");
+
+ /* run loop */
+ g_main_loop_run (loop);
+ g_main_loop_unref (loop);
+ g_thread_join (th);
+
+ gda_disconnect (obj, hid, NULL);
+
+ g_signal_emit_by_name (obj, "sig0");
+
+ g_object_unref (obj);
+
+ /* results! */
+ if (sig_data.counter != 2) {
+ g_print ("Error: callback has been called %u times when it should have been called %u
times!\n",
+ sig_data.counter, 2);
+ retval++;
+ }
+ g_print ("Test %s\n", retval ? "failed": "succeded");
+ return retval;
+}
+
diff --git a/libgda/thread-wrapper/test-itsignaler.c b/libgda/thread-wrapper/test-itsignaler.c
new file mode 100644
index 0000000..ad4fe4e
--- /dev/null
+++ b/libgda/thread-wrapper/test-itsignaler.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2013 Vivien Malerba <malerba gnome-db org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include "itsignaler.h"
+#include <stdlib.h>
+
+#ifdef PERF
+ #define MAX_ITERATIONS 1000000
+#else
+ #define MAX_ITERATIONS 50
+#endif
+
+int test1 (void);
+int test2 (void);
+int test3 (void);
+
+
+int
+main (int argc, char** argv)
+{
+ gint nfailed = 0;
+
+ nfailed += test1 ();
+ nfailed += test2 ();
+ nfailed += test3 ();
+
+ return nfailed > 0 ? 1 : 0;
+}
+
+/*
+ * Data to be passed between threads
+ */
+typedef struct {
+ gchar dummy[10000];
+ gint counter;
+} Data;
+
+typedef struct {
+ gint counter;
+ GMainLoop *loop;
+} CbData;
+
+static gpointer thread1_start (ITSignaler *its);
+
+static gboolean
+source_callback (ITSignaler *its, CbData *cbdata)
+{
+ Data *data;
+ data = itsignaler_pop_notification (its, 0);
+ if (cbdata->counter != data->counter) {
+ g_warning ("itsignaler_pop_notification() returned wrong value %d instead of %d",
+ cbdata->counter, data->counter);
+ return EXIT_FAILURE;
+ }
+ g_print ("Popped %d\n", data->counter);
+ g_free (data);
+
+ cbdata->counter ++;
+ if (cbdata->counter == MAX_ITERATIONS * 2) {
+ g_main_loop_quit (cbdata->loop);
+ return FALSE;
+ }
+ else
+ return TRUE;
+}
+
+int
+test1 (void)
+{
+ g_print ("Test1 started\n");
+
+ ITSignaler *its;
+ its = itsignaler_new ();
+
+ Data *data;
+#ifndef PERF
+ g_print ("Try popping initially...\n");
+#endif
+ data = itsignaler_pop_notification (its, 0);
+ if (data) {
+ g_warning ("itsignaler_pop_notification() sould have returned NULL");
+ return EXIT_FAILURE;
+ }
+#ifndef PERF
+ g_print ("Done\n");
+#endif
+
+ GTimer *timer;
+ timer = g_timer_new ();
+
+ GMainLoop *loop;
+ loop = g_main_loop_new (NULL, FALSE);
+
+ GSource *source;
+ source = itsignaler_create_source (its);
+ itsignaler_unref (its);
+
+ CbData cbdata;
+ cbdata.counter = 0;
+ cbdata.loop = loop;
+ g_source_set_callback (source, (GSourceFunc) source_callback, &cbdata, NULL);
+ g_source_attach (source, NULL);
+
+ GThread *th;
+ th = g_thread_new ("sub", (GThreadFunc) thread1_start, its);
+
+ g_main_loop_run (loop);
+ g_source_unref (source);
+
+ g_timer_stop (timer);
+
+ g_thread_join (th);
+
+ if (cbdata.counter == MAX_ITERATIONS * 2) {
+ gdouble duration;
+ duration = g_timer_elapsed (timer, NULL);
+ g_print ("Test Ok, %0.5f s\n", duration);
+ g_timer_destroy (timer);
+ return 0;
+ }
+ else {
+ g_print ("Test Failed: got %d notification(s) out of %d\n", cbdata.counter, MAX_ITERATIONS *
2);
+ g_timer_destroy (timer);
+ return 1;
+ }
+}
+
+/*
+ * Send notifications from this thread, to be caught in the main thread
+ */
+static gpointer
+thread1_start (ITSignaler *its)
+{
+ gint i, counter;
+ itsignaler_ref (its);
+ for (counter = 0, i = 0; i < MAX_ITERATIONS; i++) {
+ Data *data;
+ data = g_new0 (Data, 1);
+ data->counter = counter++;
+#ifndef PERF
+ g_print ("Pushing %d...\n", counter);
+#endif
+ itsignaler_push_notification (its, data, g_free);
+
+ data = g_new0 (Data, 1);
+ data->counter = counter++;
+ itsignaler_push_notification (its, data, g_free);
+ }
+ itsignaler_unref (its);
+ return (gpointer) 0x01;
+}
+
+int
+test2 (void)
+{
+ g_print ("Test2 started\n");
+
+ ITSignaler *its;
+ its = itsignaler_new ();
+
+
+ GTimer *timer;
+ timer = g_timer_new ();
+
+ GMainLoop *loop;
+ loop = g_main_loop_new (NULL, FALSE);
+
+ CbData cbdata;
+ cbdata.counter = 0;
+ cbdata.loop = loop;
+ itsignaler_add (its, NULL, (ITSignalerFunc) source_callback, &cbdata, NULL);
+ itsignaler_unref (its);
+
+ GThread *th;
+ th = g_thread_new ("sub", (GThreadFunc) thread1_start, its);
+
+ g_main_loop_run (loop);
+ g_main_loop_unref (loop);
+
+ g_timer_stop (timer);
+
+ g_thread_join (th);
+
+ if (cbdata.counter == MAX_ITERATIONS * 2) {
+ gdouble duration;
+ duration = g_timer_elapsed (timer, NULL);
+ g_print ("Test Ok, %0.5f s\n", duration);
+ g_timer_destroy (timer);
+ return 0;
+ }
+ else {
+ g_print ("Test Failed: got %d notification(s) out of %d\n", cbdata.counter, MAX_ITERATIONS *
2);
+ g_timer_destroy (timer);
+ return 1;
+ }
+}
+
+
+int test3_destroyed;
+
+static void
+test3_destroy_func (gpointer data)
+{
+ g_print ("Destroy function called for data %p\n", data);
+ test3_destroyed++;
+}
+
+int
+test3 (void)
+{
+ g_print ("Test3 started\n");
+
+ ITSignaler *its;
+ its = itsignaler_new ();
+ test3_destroyed = 0;
+ itsignaler_push_notification (its, (gpointer) 0x01, test3_destroy_func);
+ itsignaler_push_notification (its, (gpointer) 0x02, test3_destroy_func);
+ itsignaler_push_notification (its, (gpointer) 0x03, test3_destroy_func);
+
+ gpointer data;
+ data = itsignaler_pop_notification (its, 100);
+ if (!data || data != (gpointer) 0x01) {
+ g_print ("Popped wrong value: %p instead of %p\n", data, (gpointer) 0x01);
+ itsignaler_unref (its);
+ return 1;
+ }
+
+ itsignaler_unref (its);
+
+ return test3_destroyed == 2 ? 0 : 1;
+}
diff --git a/libgda/thread-wrapper/test-raw-itsignaler.c b/libgda/thread-wrapper/test-raw-itsignaler.c
new file mode 100644
index 0000000..4a95798
--- /dev/null
+++ b/libgda/thread-wrapper/test-raw-itsignaler.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2013 Vivien Malerba <malerba gnome-db org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include "itsignaler.h"
+#include <stdlib.h>
+#include <errno.h>
+#ifdef G_OS_WIN32
+//#include <fcntl.h>
+//#include <io.h>
+#else
+ #include <poll.h>
+#endif
+#include <stdio.h>
+#include <unistd.h>
+
+#ifdef PERF
+ #define MAX_ITERATIONS 1000000
+#else
+ #define MAX_ITERATIONS 50
+#endif
+
+/*
+ * Data to be passed between threads
+ */
+typedef struct {
+ gchar dummy[10000];
+ gint counter;
+} Data;
+
+static gpointer thread1_start (ITSignaler *its);
+
+int
+main (int argc, char** argv)
+{
+ g_print ("Test started\n");
+
+ ITSignaler *its;
+ its = itsignaler_new ();
+
+ Data *data;
+#ifndef PERF
+ g_print ("Try popping initially...\n");
+#endif
+ data = itsignaler_pop_notification (its, 0);
+ if (data) {
+ g_warning ("itsignaler_pop_notification() sould have returned NULL");
+ return EXIT_FAILURE;
+ }
+#ifndef PERF
+ g_print ("Done\n");
+#endif
+
+ GThread *th;
+ th = g_thread_new ("sub", (GThreadFunc) thread1_start, its);
+ gint counter = 0;
+ guint ticks;
+#ifdef G_OS_WIN32
+ struct timeval timeout;
+ fd_set fds;
+ SOCKET sock;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 100000;
+ sock = itsignaler_windows_get_poll_fd (its);
+ FD_ZERO (&fds);
+ FD_SET (sock, &fds);
+#else
+ struct pollfd fds[1];
+ fds[0].fd = itsignaler_unix_get_poll_fd (its);
+ fds[0].events = POLLIN;
+ fds[0].revents = 0;
+#endif
+
+ GTimer *timer;
+ timer = g_timer_new ();
+
+ for (ticks = 0; ticks < MAX_ITERATIONS * 4; ticks++) {
+ data = NULL;
+ int res;
+#ifndef PERF
+ g_print (".");
+ fflush (stdout);
+#endif
+
+#ifdef G_OS_WIN32
+ res = select (1, &fds, 0, 0, &timeout);
+ if (res == SOCKET_ERROR) {
+ g_warning ("Failure on select(): %d", WSAGetLastError ()); /* FIXME! */
+ return EXIT_FAILURE;
+ }
+ else if (res > 0) {
+ data = (Data*) itsignaler_pop_notification (its, 0);
+ }
+#else
+ res = poll (fds, 1, 100);
+ if (res == -1) {
+ g_warning ("Failure on poll(): %s", strerror (errno));
+ return EXIT_FAILURE;
+ }
+ else if (res > 0) {
+ if (fds[0].revents | POLLIN) {
+ data = (Data*) itsignaler_pop_notification (its, 0);
+ }
+ else {
+ g_warning ("Something nasty happened on file desciptor...");
+ return EXIT_FAILURE;
+ }
+ }
+#endif
+
+ if (data) {
+ if (counter != data->counter) {
+ g_warning ("itsignaler_pop_notification() returned wrong value %d instead of
%d",
+ data->counter, counter);
+ return EXIT_FAILURE;
+ }
+ else {
+#ifndef PERF
+ g_print ("Popped %d\n", counter);
+#endif
+ counter++;
+ }
+ g_free (data);
+ if (counter == MAX_ITERATIONS * 2)
+ break;
+ }
+ }
+
+ g_timer_stop (timer);
+
+ g_thread_join (th);
+ itsignaler_unref (its);
+
+ if (counter == MAX_ITERATIONS * 2) {
+ gdouble duration;
+ duration = g_timer_elapsed (timer, NULL);
+ g_print ("Test Ok, %0.5f s\n", duration);
+ g_timer_destroy (timer);
+ return EXIT_SUCCESS;
+ }
+ else {
+ g_print ("Test Failed: got %d notification(s) out of 20\n", counter);
+ g_timer_destroy (timer);
+ return EXIT_SUCCESS;
+ }
+}
+
+/*
+ * Send notifications from this thread, to be caught in the main thread
+ */
+static gpointer
+thread1_start (ITSignaler *its)
+{
+ gint i, counter;
+ itsignaler_ref (its);
+ for (counter = 0, i = 0; i < MAX_ITERATIONS; i++) {
+ Data *data;
+ data = g_new0 (Data, 1);
+ data->counter = counter++;
+#ifndef PERF
+ g_print ("Pushing %d...\n", counter);
+#endif
+ itsignaler_push_notification (its, data, g_free);
+
+ data = g_new0 (Data, 1);
+ data->counter = counter++;
+ itsignaler_push_notification (its, data, g_free);
+ }
+ itsignaler_unref (its);
+ return (gpointer) 0x01;
+}
diff --git a/libgda/thread-wrapper/test-worker.c b/libgda/thread-wrapper/test-worker.c
new file mode 100644
index 0000000..544110c
--- /dev/null
+++ b/libgda/thread-wrapper/test-worker.c
@@ -0,0 +1,835 @@
+/*
+ * Copyright (C) 2013 Vivien Malerba <malerba gnome-db org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include "gda-worker.h"
+#include <stdlib.h>
+
+int test1 (void);
+int test2 (void);
+int test3 (void);
+int test4 (void);
+int test5 (void);
+int test6 (void);
+int test7 (void);
+int test8 (void);
+int test9 (void);
+int test10 (void);
+int test11 (void);
+int test12 (void);
+
+
+int
+main (int argc, char** argv)
+{
+ gint nfailed = 0;
+
+ nfailed += test1 ();
+ nfailed += test2 ();
+ nfailed += test3 ();
+ nfailed += test4 ();
+ nfailed += test5 ();
+ nfailed += test6 ();
+ nfailed += test7 ();
+ nfailed += test8 ();
+ nfailed += test9 ();
+ nfailed += test10 ();
+ nfailed += test11 ();
+ nfailed += test12 ();
+
+ g_print ("Test %s\n", nfailed > 0 ? "Failed" : "Ok");
+ return nfailed > 0 ? 1 : 0;
+}
+
+/*
+ * Test 1: so basic
+ */
+int
+test1 (void)
+{
+ g_print ("Test1 started\n");
+ GdaWorker *worker;
+
+ worker = gda_worker_new ();
+ gda_worker_unref (worker);
+ return 0;
+}
+
+/*
+ * Test 2: killing worker
+ */
+int
+test2 (void)
+{
+ g_print ("Test2 started\n");
+ GdaWorker *worker;
+
+ worker = gda_worker_new ();
+ g_usleep (100000);
+ guint i = 0;
+ while (! gda_worker_kill (worker)) {
+ g_print ("Wait %d\n", i++);
+ g_usleep (100000);
+ }
+ gda_worker_unref (worker);
+ return 0;
+}
+
+
+/*
+ * Test 3: fetching results
+ */
+typedef struct {
+ guint counter;
+} Data3;
+
+static void
+data3_free (Data3 *data)
+{
+ g_print ("%s() from thread %p\n", __FUNCTION__, g_thread_self());
+ g_free (data);
+}
+
+static gpointer
+test3_worker_func (Data3 *data)
+{
+ gint *retval;
+ g_print ("%s() called from thread %p\n", __FUNCTION__, g_thread_self());
+ g_usleep (500000); /* short delay */
+ retval = g_new0 (gint, 1);
+ *retval = data->counter + 1;
+ return retval;
+}
+
+int
+test3 (void)
+{
+ g_print ("Test3 started, main thread is %p\n", g_thread_self ());
+ GdaWorker *worker;
+ gint nfailed = 0;
+
+ worker = gda_worker_new ();
+ guint jid;
+ GError *error = NULL;
+ Data3 *data;
+ data = g_new (Data3, 1);
+ data->counter = 5;
+ jid = gda_worker_submit_job (worker, NULL,
+ (GdaWorkerFunc) test3_worker_func, data, (GDestroyNotify) data3_free,
NULL, &error);
+ if (jid == 0) {
+ g_print ("Error in gda_worker_submit_job(): %s\n", error && error->message ? error->message :
"no detail");
+ g_clear_error (&error);
+ nfailed++;
+ goto out;
+ }
+
+ while (1) {
+ gint *result;
+ if (! gda_worker_fetch_job_result (worker, jid, (gpointer*) &result, &error)) {
+ g_print ("Still not done, error: %s\n", error && error->message ? error->message :
"no detail");
+ if ((error->domain == GDA_WORKER_ERROR) && (error->code ==
GDA_WORKER_JOB_NOT_FOUND_ERROR)) {
+ nfailed++;
+ g_clear_error (&error);
+ break;
+ }
+ g_clear_error (&error);
+ }
+ else {
+ if (result) {
+ g_print ("Got result value: %d\n", *result);
+ g_free (result);
+ }
+ else {
+ g_print ("Error: got no result value!\n");
+ nfailed++;
+ }
+ break;
+ }
+ g_usleep (100000);
+ }
+
+ out:
+ gda_worker_unref (worker);
+
+ return nfailed;
+}
+
+/*
+ * Test 4: cancellation tests
+ */
+static gpointer
+test4_worker_func (gpointer data)
+{
+ /* just spend some idle time */
+ g_print ("%s() called from thread %p\n", __FUNCTION__, g_thread_self());
+ g_usleep (500000); /* short delay */
+ return NULL;
+}
+
+int
+test4 (void)
+{
+ g_print ("Test4 started, main thread is %p\n", g_thread_self ());
+ GdaWorker *worker;
+ gint nfailed = 0;
+
+ worker = gda_worker_new ();
+ guint jid1, jid2;
+ GError *error = NULL;
+ jid1 = gda_worker_submit_job (worker, NULL, (GdaWorkerFunc) test4_worker_func, NULL, NULL, NULL,
&error);
+ if (jid1 == 0) {
+ g_print ("Error in gda_worker_submit_job(): %s\n", error && error->message ? error->message :
"no detail");
+ g_clear_error (&error);
+ nfailed++;
+ goto out;
+ }
+ jid2 = gda_worker_submit_job (worker, NULL, (GdaWorkerFunc) test4_worker_func, NULL, NULL, NULL,
&error);
+ if (jid2 == 0) {
+ g_print ("Error in gda_worker_submit_job(): %s\n", error && error->message ? error->message :
"no detail");
+ g_clear_error (&error);
+ nfailed++;
+ goto out;
+ }
+
+ if (! gda_worker_cancel_job (worker, jid2, &error)) {
+ g_print ("Error in gda_worker_cancel_job(): %s\n", error && error->message ? error->message :
"no detail");
+ g_clear_error (&error);
+ nfailed++;
+ goto out;
+ }
+ if (! gda_worker_cancel_job (worker, jid2, &error)) {
+ g_print ("Error in gda_worker_cancel_job(): %s\n", error && error->message ? error->message :
"no detail");
+ g_clear_error (&error);
+ nfailed++;
+ goto out;
+ }
+ if (gda_worker_cancel_job (worker, 10, NULL)) {
+ g_print ("Error in gda_worker_cancel_job(): should have failed!\n");
+ nfailed++;
+ goto out;
+ }
+
+ while (1) {
+ gint *result;
+ if (! gda_worker_fetch_job_result (worker, jid1, (gpointer*) &result, &error)) {
+ g_print ("Still not done, error: %s\n", error && error->message ? error->message :
"no detail");
+ if ((error->domain == GDA_WORKER_ERROR) && (error->code ==
GDA_WORKER_JOB_NOT_FOUND_ERROR)) {
+ nfailed++;
+ g_clear_error (&error);
+ break;
+ }
+ g_clear_error (&error);
+ }
+ else {
+ if (result) {
+ g_print ("Error: got result value when expected none!\n");
+ nfailed++;
+ }
+ break;
+ }
+ g_usleep (100000);
+ }
+ out:
+ gda_worker_unref (worker);
+
+ return nfailed;
+}
+
+/*
+ * Test 5: with main loop
+ */
+static gpointer
+test5_worker_func (gpointer data)
+{
+ /* just spend some idle time */
+ g_print ("%s() called from thread %p\n", __FUNCTION__, g_thread_self());
+ g_usleep (100000); /* short delay */
+ return NULL;
+}
+
+static gboolean
+test5_idle_push_jobs (GdaWorker *worker)
+{
+ static guint i = 0;
+ i++;
+ guint jid;
+ jid = gda_worker_submit_job (worker, NULL, (GdaWorkerFunc) test5_worker_func, NULL, NULL, NULL, NULL);
+ if (jid == 0) {
+ g_print ("gda_worker_submit_job() Failed!\n");
+ return FALSE;
+ }
+ else
+ g_print ("Pushed job %u\n", i);
+
+ return i == 5 ? FALSE : TRUE;
+}
+
+static void
+test5_worker_callback (GdaWorker *worker, guint job_id, gpointer result_data, GError *error, GMainLoop *loop)
+{
+ static guint i = 0;
+ i++;
+ g_print ("test5_worker_callback called for job %u\n", job_id);
+ if (i == 5) {
+ g_print ("Requesting loop quit, from thread %p\n", g_thread_self ());
+ g_main_loop_quit (loop);
+ }
+}
+
+int
+test5 (void)
+{
+ g_print ("Test5 started, main thread is %p\n", g_thread_self ());
+ GdaWorker *worker;
+ gint nfailed = 0;
+
+ worker = gda_worker_new ();
+ GError *error = NULL;
+
+ GMainLoop *loop;
+ loop = g_main_loop_new (NULL, FALSE);
+ if (! gda_worker_set_callback (worker, NULL, (GdaWorkerCallback) test5_worker_callback, loop,
&error)) {
+ g_print ("gda_worker_set_callback() error: %s\n", error && error->message ? error->message :
"no detail");
+ nfailed++;
+ }
+ else {
+ g_assert (g_idle_add ((GSourceFunc) test5_idle_push_jobs, worker) != 0);
+ }
+ g_main_loop_run (loop);
+ g_main_loop_unref (loop);
+ gda_worker_unref (worker);
+ g_print ("Test 5 done\n");
+
+ return nfailed;
+}
+
+/*
+ * Test 6: gda_worker_do_job()
+ * - A ticker is run to make sure the events are handled while in gda_worker_do_job()
+ * - a simple job is run
+ * - job finishes before timer
+ */
+static gpointer
+test6_worker_func (gint *timeout_ms, GError **error)
+{
+ if (*timeout_ms > 0)
+ g_usleep ((gulong) *timeout_ms * 1000);
+ return g_strdup ("Test6Done");
+}
+
+static void
+test6_string_free (gchar *str)
+{
+ g_print ("%s (%s)\n", __FUNCTION__, str);
+ g_free (str);
+}
+
+static gboolean
+test6_timer_cb (guint *nticks)
+{
+ (*nticks) ++;
+ return TRUE; /* keep timer */
+}
+
+int
+test6 (void)
+{
+ g_print ("%s started, main thread is %p\n", __FUNCTION__, g_thread_self ());
+ GdaWorker *worker;
+ gint nfailed = 0;
+
+ worker = gda_worker_new ();
+ GError *error = NULL;
+
+ guint nticks = 0;
+ guint timer;
+ timer = g_timeout_add (10, (GSourceFunc) test6_timer_cb, &nticks);
+
+ guint jid;
+ gpointer out;
+ gint wait;
+ wait = 50;
+ if (gda_worker_do_job (worker, NULL, 100, &out, &jid,
+ (GdaWorkerFunc) test6_worker_func, (gpointer) &wait, NULL,
+ (GDestroyNotify) test6_string_free, &error)) {
+ if (!out || strcmp (out, "Test6Done")) {
+ g_print ("Expected out to be [Test6Done] and got [%s]\n", (gchar*) out);
+ nfailed++;
+ }
+ g_free (out);
+ if (jid != 0) {
+ g_print ("Expected JID to be 0 and got %u\n", jid);
+ nfailed++;
+ }
+ }
+ else {
+ g_print ("gda_worker_do_job() failed: %s\n", error && error->message ? error->message : "No
detail");
+ g_clear_error (&error);
+ nfailed ++;
+ }
+ g_source_remove (timer);
+
+ if (nticks < 3) {
+ g_print ("Tick timer was not called while in gda_worker_do_job()\n");
+ nfailed++;
+ }
+ g_print ("Unref worker...\n");
+
+ gda_worker_unref (worker);
+ g_print ("%s done\n", __FUNCTION__);
+
+ return nfailed;
+}
+
+/*
+ * Test 7: gda_worker_do_job()
+ * - A ticker is run to make sure the events are handled while in gda_worker_do_job()
+ * - a simple job is run
+ * - job finishes after timer
+ */
+int
+test7 (void)
+{
+ g_print ("%s started, main thread is %p\n", __FUNCTION__, g_thread_self ());
+ GdaWorker *worker;
+ gint nfailed = 0;
+
+ worker = gda_worker_new ();
+ GError *error = NULL;
+
+ guint nticks = 0;
+ guint timer;
+ timer = g_timeout_add (10, (GSourceFunc) test6_timer_cb, &nticks);
+
+ guint jid;
+ gpointer out;
+ gint wait;
+ wait = 150;
+ if (gda_worker_do_job (worker, NULL, 100, &out, &jid,
+ (GdaWorkerFunc) test6_worker_func, (gpointer) &wait, NULL,
+ (GDestroyNotify) test6_string_free, &error)) {
+ g_print ("out: [%s], JID: %u\n", (gchar*) out, jid);
+ if (out) {
+ g_print ("Expected out to be NULL and got [%s]\n", (gchar*) out);
+ nfailed++;
+ g_free (out);
+ }
+ if (jid == 0) {
+ g_print ("Expected JID to be > 0 and got %u\n", jid);
+ nfailed++;
+ }
+
+ while (1) {
+ g_print ("Waiting for result using gda_worker_fetch_job_result()\n");
+ if (gda_worker_fetch_job_result (worker, jid, &out, &error)) {
+ if (!out || strcmp (out, "Test6Done")) {
+ g_print ("Expected out to be [Test6Done] and got [%s]\n", (gchar*)
out);
+ nfailed++;
+ }
+ g_free (out);
+ break;
+ }
+ else
+ g_clear_error (&error);
+ g_usleep (100000);
+ }
+ }
+ else {
+ g_print ("gda_worker_do_job() failed: %s\n", error && error->message ? error->message : "No
detail");
+ g_clear_error (&error);
+ nfailed ++;
+ }
+ g_source_remove (timer);
+
+ if (nticks < 3) {
+ g_print ("Tick timer was not called while in gda_worker_do_job()\n");
+ nfailed++;
+ }
+ g_print ("Unref worker...\n");
+
+ gda_worker_unref (worker);
+ g_print ("%s done\n", __FUNCTION__);
+
+ return nfailed;
+}
+
+/*
+ * Test 8: submit a job from within the worker thread
+ */
+static gpointer
+test8_sub_func (gpointer unused_data, GError **error)
+{
+ g_print ("%s() called in thread %p\n", __FUNCTION__, g_thread_self());
+ return "test8_sub_func";
+}
+
+static gpointer
+test8_func (GdaWorker *worker, GError **error)
+{
+ guint jid;
+ jid = gda_worker_submit_job (worker, NULL, (GdaWorkerFunc) test8_sub_func, NULL, NULL, NULL, error);
+ if (jid == 0)
+ return NULL;
+ else {
+ g_print ("%s() submitted job %u with thread %p\n", __FUNCTION__, jid, g_thread_self ());
+ while (1) {
+ gpointer out;
+ GError *lerror = NULL;
+ g_print ("Waiting for result...\n");
+ if (gda_worker_fetch_job_result (worker, jid, &out, &lerror)) {
+ if (lerror)
+ g_propagate_error (error, lerror);
+ return out;
+ }
+ else
+ g_clear_error (&lerror);
+ g_usleep (100000);
+ }
+ }
+}
+
+int
+test8 (void)
+{
+ g_print ("%s started, main thread is %p\n", __FUNCTION__, g_thread_self ());
+ GdaWorker *worker;
+ gint nfailed = 0;
+
+ worker = gda_worker_new ();
+ GError *error = NULL;
+
+ guint jid;
+ jid = gda_worker_submit_job (worker, NULL, (GdaWorkerFunc) test8_func, worker, NULL, NULL, &error);
+ if (jid == 0) {
+ g_print ("gda_worker_submit_job() failed: %s\n", error && error->message ? error->message :
"No detail");
+ g_clear_error (&error);
+ nfailed ++;
+ }
+ else {
+ while (1) {
+ gpointer out;
+ g_print ("Waiting for result using gda_worker_fetch_job_result()\n");
+ if (gda_worker_fetch_job_result (worker, jid, &out, &error)) {
+ if (!out || strcmp (out, "test8_sub_func")) {
+ g_print ("Expected out to be [test8_sub_func] and got %s\n", (gchar*)
out);
+ nfailed++;
+ }
+ if (error) {
+ g_print ("Got error: %s\n", error && error->message ? error->message
: "No detail");
+ g_clear_error (&error);
+ nfailed++;
+ }
+ break;
+ }
+ else
+ g_clear_error (&error);
+ g_usleep (100000);
+ }
+ }
+
+ g_print ("Unref worker...\n");
+
+ gda_worker_unref (worker);
+ g_print ("%s done\n", __FUNCTION__);
+
+ return nfailed;
+}
+
+/*
+ * test 9: gda_worker_set_callback() with multiple threads submitting jobs and retreiving them
+ */
+typedef struct {
+ guint in;
+ guint out;
+
+ GMainLoop *loop;
+} Test9Data;
+
+static void
+test9data_free (Test9Data *data)
+{
+ /* should not be called by GdaWorker, instead it is freed manually using g_free() */
+ g_assert_not_reached ();
+}
+
+/* function run by the worker thread */
+static gpointer
+test9_job_func (Test9Data *data, GError **error)
+{
+ g_print ("job_func (thread => %p, data => %p)\n", g_thread_self(), data);
+ data->out = data->in;
+ return data;
+}
+
+/* function called back in the context which submitted the jobs */
+static void
+test9_worker_cb (GdaWorker *worker, guint job_id, Test9Data *data, GError *error, GThread *thread)
+{
+ g_print ("%s (thread => %p, result_data => %p)\n", __FUNCTION__, g_thread_self(), data);
+
+ if (thread != g_thread_self()) {
+ g_print ("callback from gda_worker_set_callback() called in thread %p, expected in thread
%p\n",
+ g_thread_self(), thread);
+ exit (1);
+ }
+ else if (data->in != data->out) {
+ g_print ("Expected data->out[%u] to be equal to data->in[%u]\n", data->out, data->in);
+ exit (1);
+ }
+
+ if (data->loop)
+ g_main_loop_quit (data->loop);
+ g_free (data);
+}
+
+/* main function run by each thread, which submit jobs */
+static gpointer
+test9_main_func (GdaWorker *worker)
+{
+ GError *error = NULL;
+ GMainContext *context = NULL;
+ static guint counter = 0;
+
+ context = g_main_context_new ();
+
+ if (! gda_worker_set_callback (worker, context, (GdaWorkerCallback) test9_worker_cb, g_thread_self
(), &error)) {
+ g_print ("gda_worker_set_callback() from thread %p error: %s\n", g_thread_self (),
+ error && error->message ? error->message : "No detail");
+ g_clear_error (&error);
+ return (gpointer) 0x01;
+ }
+
+ GMainLoop *loop;
+ loop = g_main_loop_new (context, FALSE);
+#define N_JOBS 2
+ guint i;
+ for (i = 0; i < N_JOBS; i++) {
+ guint jid;
+ Test9Data *data;
+ data = g_new (Test9Data, 1);
+ data->in = (guint) GPOINTER_TO_INT (g_thread_self ()) + (counter++);
+ data->out = 0;
+ data->loop = (i == N_JOBS - 1) ? loop : NULL;
+ jid = gda_worker_submit_job (worker, context, (GdaWorkerFunc) test9_job_func, data,
+ NULL, (GDestroyNotify) test9data_free, &error);
+ if (jid == 0) {
+ g_print ("gda_worker_submit_job() from thread %p error: %s\n", g_thread_self (),
+ error && error->message ? error->message : "No detail");
+ g_clear_error (&error);
+ return (gpointer) 0x01;
+ }
+ else
+ g_print ("Submitted job %u from thread %p, with data %p\n", jid, g_thread_self(),
data);
+ }
+
+ g_main_loop_run (loop);
+ g_main_loop_unref (loop);
+
+ g_main_context_unref (context);
+ return NULL;
+}
+
+int
+test9 (void)
+{
+ g_print ("%s started, main thread is %p\n", __FUNCTION__, g_thread_self ());
+ GdaWorker *worker;
+ gint nfailed = 0;
+
+ worker = gda_worker_new ();
+ GError *error = NULL;
+
+#define NB_THREADS 2
+ GThread *threads[NB_THREADS];
+ guint i;
+ for (i = 0; i < NB_THREADS; i++) {
+ gchar *name;
+ name = g_strdup_printf ("th%u", i);
+ threads[i] = g_thread_new (name, (GThreadFunc) test9_main_func, worker);
+ g_free (name);
+ }
+
+ for (i = 0; i < NB_THREADS; i++) {
+ if (g_thread_join (threads[i]))
+ nfailed++;
+ }
+
+ g_print ("Unref worker...\n");
+
+ gda_worker_unref (worker);
+ g_print ("%s done\n", __FUNCTION__);
+
+ return nfailed;
+}
+
+/*
+ * Test 10: test gda_worker_wait_job()
+ */
+static gpointer
+test10_func_slow (gpointer data, GError **error)
+{
+ g_print ("In %s()...\n", __FUNCTION__);
+ g_usleep (500000); /* wait half a second */
+ g_print ("Leaving %s()\n", __FUNCTION__);
+ return (gpointer) 0x01;
+}
+
+static gpointer
+test10_func_fast (gpointer data, GError **error)
+{
+ g_print ("Passed through %s()...\n", __FUNCTION__);
+ return (gpointer) 0x02;
+}
+
+int
+test10 (void)
+{
+ g_print ("%s started, main thread is %p\n", __FUNCTION__, g_thread_self ());
+ GdaWorker *worker;
+ gint nfailed = 0;
+
+ worker = gda_worker_new ();
+ GError *error = NULL;
+
+ g_print ("Waiting for test10_func() to execute\n");
+ if (gda_worker_wait_job (worker, (GdaWorkerFunc) test10_func_slow, NULL, NULL, &error) != (gpointer)
0x01) {
+ g_print ("gda_worker_wait_job() failed: %s\n", error && error->message ? error->message : "No
detail");
+ g_clear_error (&error);
+ nfailed ++;
+ }
+ else {
+ if (gda_worker_wait_job (worker, (GdaWorkerFunc) test10_func_fast, NULL, NULL, &error) !=
(gpointer) 0x02) {
+ g_print ("gda_worker_wait_job() failed: %s\n", error && error->message ?
error->message : "No detail");
+ g_clear_error (&error);
+ nfailed ++;
+ }
+ }
+
+ g_print ("Unref worker...\n");
+
+ gda_worker_unref (worker);
+ g_print ("%s done\n", __FUNCTION__);
+
+ return nfailed;
+}
+
+/*
+ * Test 11: test gda_worker_do_job(), no timeout
+ */
+static gpointer
+test11_func (gpointer data, GError **error)
+{
+ g_print ("In %s()...\n", __FUNCTION__);
+ g_usleep (500000); /* wait half a second */
+ g_print ("Leaving %s()\n", __FUNCTION__);
+ return (gpointer) 0x01;
+}
+
+static gpointer
+test11_func_e (gpointer data, GError **error)
+{
+ g_print ("In %s()...\n", __FUNCTION__);
+ g_usleep (500000); /* wait half a second */
+ g_print ("Leaving %s()\n", __FUNCTION__);
+ g_set_error (error, 1, 1,
+ "Expected test11_func_e");
+ return NULL;
+}
+
+int
+test11 (void)
+{
+ g_print ("%s started, main thread is %p\n", __FUNCTION__, g_thread_self ());
+ GdaWorker *worker;
+ gint nfailed = 0;
+
+ worker = gda_worker_new ();
+ GError *error = NULL;
+
+ g_print ("Waiting for test11_func() to execute\n");
+ gpointer result;
+ if (!gda_worker_do_job (worker, NULL, 0, &result, NULL,
+ (GdaWorkerFunc) test11_func, NULL, NULL,
+ NULL, &error) ||
+ (result != (gpointer) 0x01)) {
+ g_print ("gda_worker_do_job() failed: %s\n", error && error->message ? error->message : "No
detail");
+ g_clear_error (&error);
+ nfailed ++;
+ }
+ if (!gda_worker_do_job (worker, NULL, 0, &result, NULL,
+ (GdaWorkerFunc) test11_func_e, NULL, NULL,
+ NULL, &error) ||
+ result) {
+ g_print ("gda_worker_do_job() failed: %s\n", error && error->message ? error->message : "No
detail");
+ g_clear_error (&error);
+ nfailed ++;
+ }
+ else if (!error || (error->domain != 1) || (error->code != 1)) {
+ g_print ("gda_worker_do_job() failed: unexpected empty error, or wrong error domain or
code%s\n",
+ error && error->message ? error->message : "No detail");
+ g_clear_error (&error);
+ nfailed ++;
+ }
+
+ g_print ("Unref worker...\n");
+
+ gda_worker_unref (worker);
+ g_print ("%s done\n", __FUNCTION__);
+
+ return nfailed;
+}
+
+/*
+ * Test 12: gda_worker_do_job() for quick jobs
+ */
+static gpointer
+test12_func (gpointer data, GError **error)
+{
+ /* make it as quick as possible */
+ return (gpointer) 0x02;
+}
+
+int
+test12 (void)
+{
+ g_print ("%s started, main thread is %p\n", __FUNCTION__, g_thread_self ());
+ GdaWorker *worker;
+ gint nfailed = 0;
+
+ worker = gda_worker_new ();
+ GError *error = NULL;
+
+ g_print ("Waiting for test12_func() to execute\n");
+ gpointer result;
+ if (!gda_worker_do_job (worker, NULL, 0, &result, NULL,
+ (GdaWorkerFunc) test12_func, NULL, NULL,
+ NULL, &error) ||
+ (result != (gpointer) 0x02)) {
+ g_print ("gda_worker_do_job() failed: %s\n", error && error->message ? error->message : "No
detail");
+ g_clear_error (&error);
+ nfailed ++;
+ }
+
+ g_print ("Unref worker...\n");
+
+ gda_worker_unref (worker);
+ g_print ("%s done\n", __FUNCTION__);
+
+ return nfailed;
+}
diff --git a/m4/java.m4 b/m4/java.m4
index dc1e121..3fa9a86 100644
--- a/m4/java.m4
+++ b/m4/java.m4
@@ -175,6 +175,11 @@ m4_define([_JAVA_CHECK_INTERNAL],
JTYPE="Sun JRE 1.7"
JFLAGS="-Xlint:unchecked -Xlint:deprecation"
;;
+ JRE1.8.*)
+ try_java=true
+ JTYPE="Sun JRE 1.8"
+ JFLAGS="-Xlint:unchecked -Xlint:deprecation"
+ ;;
JREgcj-4*)
try_java=true
JTYPE="GCJ"
@@ -226,7 +231,7 @@ m4_define([_JAVA_CHECK_INTERNAL],
fi
else
AC_MSG_RESULT([no])
- AC_MSG_WARN([Java not found. Please install JDK 1.4 or later, make sure that the binaries are on
the PATH and re-try. If that doesn't work, set JAVA_HOME correspondingly.])
+ AC_MSG_WARN([Java not found. Please install JDK 1.5 or later, make sure that the binaries are on
the PATH and re-try. If that doesn't work, set JAVA_HOME correspondingly.])
try_java=false
fi
fi
diff --git a/m4/misc.m4 b/m4/misc.m4
new file mode 100644
index 0000000..9fcd440
--- /dev/null
+++ b/m4/misc.m4
@@ -0,0 +1,21 @@
+dnl
+dnl CHECK_FD_CLOEXEC([action-if-found], [action-if-not-found])
+dnl Check if FD_CLOEXEC is supported
+dnl
+AC_DEFUN([CHECK_FD_CLOEXEC], [{
+ AC_MSG_CHECKING(whether FD_CLOEXEC is supported)
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([
+#include <unistd.h>
+#include <fcntl.h>
+int main (int argc, char *argv [])
+{
+ int fds[[2]];
+ int res = pipe (fds);
+ fcntl(fds[[0]], F_SETFD, fcntl(fds[[0]], F_GETFD) | FD_CLOEXEC);
+ return 0;
+}
+])],
+ [AC_MSG_RESULT(yes) ; $1],
+ [AC_MSG_RESULT(no) ; $2])
+}])
+
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 76d0a0f..f713390 100755
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -82,8 +82,7 @@ libgda/sql-parser/gda-statement-struct-insert.c
libgda/sql-parser/gda-statement-struct-parts.c
libgda/sql-parser/gda-statement-struct-select.c
libgda/sql-parser/gda-statement-struct-update.c
-libgda/thread-wrapper/gda-thread-provider.c
-libgda/thread-wrapper/gda-thread-wrapper.c
+libgda/thread-wrapper/gda-worker.c
libgda-ui/data-entries/common-bin.c
libgda-ui/data-entries/gdaui-data-cell-renderer-bin.c
libgda-ui/data-entries/gdaui-data-cell-renderer-boolean.c
diff --git a/providers/bdb/gda-bdb-provider.c b/providers/bdb/gda-bdb-provider.c
index 301fe59..794ad19 100644
--- a/providers/bdb/gda-bdb-provider.c
+++ b/providers/bdb/gda-bdb-provider.c
@@ -25,6 +25,7 @@
#include <glib/gi18n-lib.h>
#include <libgda/gda-data-model-bdb.h>
#include <virtual/gda-vconnection-data-model.h>
+#include <libgda/gda-server-provider-impl.h>
#include <libgda/gda-connection-private.h>
#include "gda-bdb.h"
#include "gda-bdb-provider.h"
@@ -37,11 +38,9 @@ static void gda_bdb_provider_finalize (GObject *object);
static const gchar *gda_bdb_provider_get_name (GdaServerProvider *provider);
static const gchar *gda_bdb_provider_get_version (GdaServerProvider *provider);
-static gboolean gda_bdb_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- guint *task_id, GdaServerProviderAsyncCallback async_cb,
gpointer cb_data);
+static gboolean gda_bdb_provider_prepare_connection (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaQuarkList *params, GdaQuarkList *auth);
static const gchar *gda_bdb_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc);
-static const gchar *gda_bdb_provider_get_database (GdaServerProvider *provider, GdaConnection *cnc);
static GObjectClass *parent_class = NULL;
@@ -53,6 +52,41 @@ static void gda_bdb_free_cnc_data (BdbConnectionData *cdata);
/*
* GdaBdbProvider class implementation
*/
+GdaServerProviderBase data_model_base_functions = {
+ gda_bdb_provider_get_name,
+ gda_bdb_provider_get_version,
+ gda_bdb_provider_get_server_version,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ gda_bdb_provider_prepare_connection,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ NULL, NULL, NULL, NULL, /* padding */
+};
+
static void
gda_bdb_provider_class_init (GdaBdbProviderClass *klass)
{
@@ -61,13 +95,12 @@ gda_bdb_provider_class_init (GdaBdbProviderClass *klass)
parent_class = g_type_class_peek_parent (klass);
- object_class->finalize = gda_bdb_provider_finalize;
+ /* set virtual functions */
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_BASE,
+ (gpointer) &data_model_base_functions);
- provider_class->get_name = gda_bdb_provider_get_name;
- provider_class->get_version = gda_bdb_provider_get_version;
- provider_class->open_connection = gda_bdb_provider_open_connection;
- provider_class->get_server_version = gda_bdb_provider_get_server_version;
- provider_class->get_database = gda_bdb_provider_get_database;
+ object_class->finalize = gda_bdb_provider_finalize;
}
static void
@@ -132,13 +165,11 @@ gda_bdb_provider_get_version (G_GNUC_UNUSED GdaServerProvider *provider)
}
/*
- * Open connection request
+ * Prepare connection request
*/
static gboolean
-gda_bdb_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
- GdaQuarkList *params, G_GNUC_UNUSED GdaQuarkList *auth,
- G_GNUC_UNUSED guint *task_id, GdaServerProviderAsyncCallback async_cb,
- G_GNUC_UNUSED gpointer cb_data)
+gda_bdb_provider_prepare_connection (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaQuarkList *params, G_GNUC_UNUSED GdaQuarkList *auth)
{
BdbConnectionData *cdata;
gchar *bdb_file, *bdb_db, *dirname;
@@ -150,11 +181,6 @@ gda_bdb_provider_open_connection (GdaServerProvider *provider, GdaConnection *cn
g_return_val_if_fail (GDA_IS_BDB_PROVIDER (provider), FALSE);
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
- if (async_cb) {
- gda_connection_add_event_string (cnc, _("Provider does not support asynchronous connection
open"));
- return FALSE;
- }
-
/* parse connection string */
dirname = g_strdup (gda_quark_list_find (params, "DB_DIR"));
bdb_file = g_strdup (gda_quark_list_find (params, "DB_NAME"));
@@ -195,20 +221,12 @@ gda_bdb_provider_open_connection (GdaServerProvider *provider, GdaConnection *cn
return FALSE;
}
- /* open virtual connection */
- if (! GDA_SERVER_PROVIDER_CLASS (parent_class)->open_connection (GDA_SERVER_PROVIDER (provider), cnc,
params,
- NULL, NULL, NULL, NULL)) {
- gda_connection_add_event_string (cnc, _("Can't open virtual connection"));
- return FALSE;
- }
-
/* add the BDB data model as table "data" */
if (!gda_vconnection_data_model_add_model (GDA_VCONNECTION_DATA_MODEL (cnc), model, bdb_db ? bdb_db :
"data", &error)) {
gda_connection_add_event_string (cnc,
_("Could not add BDB data model to connection: %s"),
error && error->message ? error->message : _("no detail"));
g_error_free (error);
- gda_connection_close_no_warning (cnc);
g_object_unref (model);
retval = FALSE;
@@ -242,30 +260,13 @@ gda_bdb_provider_get_server_version (GdaServerProvider *provider, GdaConnection
}
/*
- * Get database request
- */
-static const gchar *
-gda_bdb_provider_get_database (GdaServerProvider *provider, GdaConnection *cnc)
-{
- BdbConnectionData *cdata;
-
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
-
- cdata = gda_virtual_connection_internal_get_provider_data (GDA_VIRTUAL_CONNECTION (cnc));
- if (!cdata)
- return NULL;
-
- return cdata->dbname;
-}
-
-/*
* Free connection's specific data
*/
static void
gda_bdb_free_cnc_data (BdbConnectionData *cdata)
{
- g_object_unref (cdata->table_model);
+ if (cdata->table_model)
+ g_object_unref (cdata->table_model);
g_free (cdata->dbname);
g_free (cdata);
}
diff --git a/providers/bdb/gda-bdb-test.c b/providers/bdb/gda-bdb-test.c
index 173f702..ffcc46f 100644
--- a/providers/bdb/gda-bdb-test.c
+++ b/providers/bdb/gda-bdb-test.c
@@ -91,9 +91,17 @@ gda_stuff (gpointer filename)
cncstring = g_strdup_printf ("DB_NAME=%s", (gchar *) filename);
/* connect to the db */
- cnc = gda_connection_open_from_string ("Berkeley-DB", cncstring, NULL, 0, &error);
+ cnc = gda_connection_new_from_string ("Berkeley-DB", cncstring, NULL, 0, &error);
if (!cnc) {
+ g_print ("Could not create connection; %s\n", error && error->message ? error->message : "no
detail");
+ g_clear_error (&error);
+ exit (1);
+ }
+
+ if (! gda_connection_open (cnc, &error)) {
g_print ("Could not open connection; %s\n", error && error->message ? error->message : "no
detail");
+ g_clear_error (&error);
+ g_object_unref (cnc);
exit (1);
}
@@ -143,7 +151,7 @@ gda_stuff (gpointer filename)
#endif
/* disconnect, remove dsn & quit */
- gda_connection_close (cnc);
+ gda_connection_close (cnc, NULL);
}
int main (G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv)
diff --git a/providers/firebird/gda-firebird-blob-op.c b/providers/firebird/gda-firebird-blob-op.c
index e2d9e8d..be2eeeb 100644
--- a/providers/firebird/gda-firebird-blob-op.c
+++ b/providers/firebird/gda-firebird-blob-op.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 - 2011 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2007 - 2014 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 Lesser General Public
@@ -22,6 +22,7 @@
#include <libgda/libgda.h>
#include "gda-firebird.h"
#include "gda-firebird-blob-op.h"
+#include <libgda/gda-blob-op-impl.h>
#include <libgda/gda-debug-macros.h>
struct _GdaFirebirdBlobOpPrivate {
@@ -95,9 +96,9 @@ gda_firebird_blob_op_class_init (GdaFirebirdBlobOpClass *klass)
parent_class = g_type_class_peek_parent (klass);
object_class->finalize = gda_firebird_blob_op_finalize;
- blob_class->get_length = gda_firebird_blob_op_get_length;
- blob_class->read = gda_firebird_blob_op_read;
- blob_class->write = gda_firebird_blob_op_write;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->get_length = gda_firebird_blob_op_get_length;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->read = gda_firebird_blob_op_read;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->write = gda_firebird_blob_op_write;
}
static void
@@ -123,7 +124,7 @@ gda_firebird_blob_op_new (GdaConnection *cnc)
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- pgop = g_object_new (GDA_TYPE_FIREBIRD_BLOB_OP, NULL);
+ pgop = g_object_new (GDA_TYPE_FIREBIRD_BLOB_OP, "connection", cnc, NULL);
pgop->priv->cnc = cnc;
return GDA_BLOB_OP (pgop);
diff --git a/providers/firebird/gda-firebird-provider.c b/providers/firebird/gda-firebird-provider.c
index 3cd51fd..16e0d9e 100644
--- a/providers/firebird/gda-firebird-provider.c
+++ b/providers/firebird/gda-firebird-provider.c
@@ -32,6 +32,7 @@
#include <libgda/libgda.h>
#include <libgda/gda-data-model-private.h>
#include <libgda/gda-server-provider-extra.h>
+#include <libgda/gda-server-provider-impl.h>
#include <libgda/binreloc/gda-binreloc.h>
#include <libgda/gda-statement-extra.h>
#include <sql-parser/gda-sql-parser.h>
@@ -63,10 +64,7 @@ static GObjectClass *parent_class = NULL;
static gboolean gda_firebird_provider_open_connection (GdaServerProvider *provider,
GdaConnection *cnc,
GdaQuarkList *params,
- GdaQuarkList *auth,
- guint *task_id,
- GdaServerProviderAsyncCallback async_cb,
- gpointer cb_data);
+ GdaQuarkList *auth);
static gboolean gda_firebird_provider_close_connection (GdaServerProvider *provider,
GdaConnection *cnc);
static const gchar *gda_firebird_provider_get_server_version (GdaServerProvider *provider,
GdaConnection *cnc);
static const gchar *gda_firebird_provider_get_database (GdaServerProvider *provider, GdaConnection
*cnc);
@@ -81,9 +79,7 @@ static gchar *gda_firebird_provider_render_operation (GdaServerProv
GdaServerOperation *op, GError **error);
static gboolean gda_firebird_provider_perform_operation (GdaServerProvider *provider,
GdaConnection *cnc,
- GdaServerOperation *op, guint *task_id,
- GdaServerProviderAsyncCallback async_cb,
gpointer cb_data,
- GError **error);
+ GdaServerOperation *op, GError **error);
/* transactions */
static gboolean gda_firebird_provider_begin_transaction (GdaServerProvider *provider,
GdaConnection *cnc,
const gchar *name,
GdaTransactionIsolation level, GError **error);
@@ -103,6 +99,7 @@ static const gchar *gda_firebird_provider_get_version (GdaServerProvider
static gboolean gda_firebird_provider_supports_feature (GdaServerProvider *provider,
GdaConnection *cnc,
GdaConnectionFeature feature);
+static GdaWorker *gda_firebird_provider_create_worker (GdaServerProvider *provider);
static const gchar *gda_firebird_provider_get_name (GdaServerProvider *provider);
static GdaDataHandler *gda_firebird_provider_get_data_handler (GdaServerProvider *provider,
GdaConnection *cnc,
@@ -129,10 +126,7 @@ static GObject *gda_firebird_provider_statement_execute (GdaServerPr
GdaSet *params,
GdaStatementModelUsage model_usage,
GType *col_types,
- GdaSet **last_inserted_row,
- guint *task_id,
- GdaServerProviderExecCallback async_cb,
- gpointer cb_data, GError **error);
+ GdaSet **last_inserted_row, GError
**error);
/* distributed transactions */
static gboolean gda_firebird_provider_xa_start (GdaServerProvider *provider,
@@ -195,6 +189,103 @@ gchar *internal_sql[] = {
/*
* GdaFirebirdProvider class implementation
*/
+GdaServerProviderBase firebird_base_functions = {
+ gda_firebird_provider_get_name,
+ gda_firebird_provider_get_version,
+ gda_firebird_provider_get_server_version,
+ gda_firebird_provider_supports_feature,
+ gda_firebird_provider_create_worker,
+ NULL,
+ gda_firebird_provider_create_parser,
+ gda_firebird_provider_get_data_handler,
+ gda_firebird_provider_get_default_dbms_type,
+ gda_firebird_provider_supports_operation,
+ gda_firebird_provider_create_operation,
+ gda_firebird_provider_render_operation,
+ gda_firebird_provider_statement_to_sql,
+ NULL,
+ NULL,
+ gda_firebird_provider_open_connection,
+ NULL,
+ gda_firebird_provider_close_connection,
+ NULL,
+ NULL,
+ gda_firebird_provider_get_database,
+ gda_firebird_provider_perform_operation,
+ gda_firebird_provider_begin_transaction,
+ gda_firebird_provider_commit_transaction,
+ gda_firebird_provider_rollback_transaction,
+ gda_firebird_provider_add_savepoint,
+ gda_firebird_provider_rollback_savepoint,
+ gda_firebird_provider_delete_savepoint,
+ gda_firebird_provider_statement_prepare,
+ gda_firebird_provider_statement_execute,
+
+ NULL, NULL, NULL, NULL, /* padding */
+};
+
+GdaServerProviderMeta firebird_meta_functions = {
+ _gda_firebird_meta__info,
+ _gda_firebird_meta__btypes,
+ _gda_firebird_meta__udt,
+ _gda_firebird_meta_udt,
+ _gda_firebird_meta__udt_cols,
+ _gda_firebird_meta_udt_cols,
+ _gda_firebird_meta__enums,
+ _gda_firebird_meta_enums,
+ _gda_firebird_meta__domains,
+ _gda_firebird_meta_domains,
+ _gda_firebird_meta__constraints_dom,
+ _gda_firebird_meta_constraints_dom,
+ _gda_firebird_meta__el_types,
+ _gda_firebird_meta_el_types,
+ _gda_firebird_meta__collations,
+ _gda_firebird_meta_collations,
+ _gda_firebird_meta__character_sets,
+ _gda_firebird_meta_character_sets,
+ _gda_firebird_meta__schemata,
+ _gda_firebird_meta_schemata,
+ _gda_firebird_meta__tables_views,
+ _gda_firebird_meta_tables_views,
+ _gda_firebird_meta__columns,
+ _gda_firebird_meta_columns,
+ _gda_firebird_meta__view_cols,
+ _gda_firebird_meta_view_cols,
+ _gda_firebird_meta__constraints_tab,
+ _gda_firebird_meta_constraints_tab,
+ _gda_firebird_meta__constraints_ref,
+ _gda_firebird_meta_constraints_ref,
+ _gda_firebird_meta__key_columns,
+ _gda_firebird_meta_key_columns,
+ _gda_firebird_meta__check_columns,
+ _gda_firebird_meta_check_columns,
+ _gda_firebird_meta__triggers,
+ _gda_firebird_meta_triggers,
+ _gda_firebird_meta__routines,
+ _gda_firebird_meta_routines,
+ _gda_firebird_meta__routine_col,
+ _gda_firebird_meta_routine_col,
+ _gda_firebird_meta__routine_par,
+ _gda_firebird_meta_routine_par,
+ _gda_firebird_meta__indexes_tab,
+ _gda_firebird_meta_indexes_tab,
+ _gda_firebird_meta__index_cols,
+ _gda_firebird_meta_index_cols,
+
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* padding */
+};
+
+GdaServerProviderXa firebird_xa_functions = {
+ gda_firebird_provider_xa_start,
+ gda_firebird_provider_xa_end,
+ gda_firebird_provider_xa_prepare,
+ gda_firebird_provider_xa_commit,
+ gda_firebird_provider_xa_rollback,
+ gda_firebird_provider_xa_recover,
+
+ NULL, NULL, NULL, NULL, /* padding */
+};
+
static void
gda_firebird_provider_class_init (GdaFirebirdProviderClass *klass)
{
@@ -202,98 +293,16 @@ gda_firebird_provider_class_init (GdaFirebirdProviderClass *klass)
parent_class = g_type_class_peek_parent (klass);
- provider_class->get_version = gda_firebird_provider_get_version;
- provider_class->get_server_version = gda_firebird_provider_get_server_version;
- provider_class->get_name = gda_firebird_provider_get_name;
- provider_class->supports_feature = gda_firebird_provider_supports_feature;
-
- provider_class->get_data_handler = gda_firebird_provider_get_data_handler;
- provider_class->get_def_dbms_type = gda_firebird_provider_get_default_dbms_type;
-
- provider_class->open_connection = gda_firebird_provider_open_connection;
- provider_class->close_connection = gda_firebird_provider_close_connection;
- provider_class->get_database = gda_firebird_provider_get_database;
-
- provider_class->supports_operation = gda_firebird_provider_supports_operation;
- provider_class->create_operation = gda_firebird_provider_create_operation;
- provider_class->render_operation = gda_firebird_provider_render_operation;
- provider_class->perform_operation = gda_firebird_provider_perform_operation;
-
- provider_class->begin_transaction = gda_firebird_provider_begin_transaction;
- provider_class->commit_transaction = gda_firebird_provider_commit_transaction;
- provider_class->rollback_transaction = gda_firebird_provider_rollback_transaction;
- provider_class->add_savepoint = NULL /*gda_firebird_provider_add_savepoint*/;
- provider_class->rollback_savepoint = NULL /*gda_firebird_provider_rollback_savepoint*/;
- provider_class->delete_savepoint = NULL /*gda_firebird_provider_delete_savepoint*/;
-
- provider_class->create_parser = gda_firebird_provider_create_parser;
- provider_class->statement_to_sql = gda_firebird_provider_statement_to_sql;
- provider_class->statement_prepare = gda_firebird_provider_statement_prepare;
- provider_class->statement_execute = gda_firebird_provider_statement_execute;
-
- provider_class->is_busy = NULL;
- provider_class->cancel = NULL;
- provider_class->create_connection = NULL;
-
- memset (&(provider_class->meta_funcs), 0, sizeof (GdaServerProviderMeta));
- provider_class->meta_funcs._info = _gda_firebird_meta__info;
- provider_class->meta_funcs._btypes = _gda_firebird_meta__btypes;
- provider_class->meta_funcs._udt = _gda_firebird_meta__udt;
- provider_class->meta_funcs.udt = _gda_firebird_meta_udt;
- provider_class->meta_funcs._udt_cols = _gda_firebird_meta__udt_cols;
- provider_class->meta_funcs.udt_cols = _gda_firebird_meta_udt_cols;
- provider_class->meta_funcs._enums = _gda_firebird_meta__enums;
- provider_class->meta_funcs.enums = _gda_firebird_meta_enums;
- provider_class->meta_funcs._domains = _gda_firebird_meta__domains;
- provider_class->meta_funcs.domains = _gda_firebird_meta_domains;
- provider_class->meta_funcs._constraints_dom = _gda_firebird_meta__constraints_dom;
- provider_class->meta_funcs.constraints_dom = _gda_firebird_meta_constraints_dom;
- provider_class->meta_funcs._el_types = _gda_firebird_meta__el_types;
- provider_class->meta_funcs.el_types = _gda_firebird_meta_el_types;
- provider_class->meta_funcs._collations = _gda_firebird_meta__collations;
- provider_class->meta_funcs.collations = _gda_firebird_meta_collations;
- provider_class->meta_funcs._character_sets = _gda_firebird_meta__character_sets;
- provider_class->meta_funcs.character_sets = _gda_firebird_meta_character_sets;
- provider_class->meta_funcs._schemata = _gda_firebird_meta__schemata;
- provider_class->meta_funcs.schemata = _gda_firebird_meta_schemata;
- provider_class->meta_funcs._tables_views = _gda_firebird_meta__tables_views;
- provider_class->meta_funcs.tables_views = _gda_firebird_meta_tables_views;
- provider_class->meta_funcs._columns = _gda_firebird_meta__columns;
- provider_class->meta_funcs.columns = _gda_firebird_meta_columns;
- provider_class->meta_funcs._view_cols = _gda_firebird_meta__view_cols;
- provider_class->meta_funcs.view_cols = _gda_firebird_meta_view_cols;
- provider_class->meta_funcs._constraints_tab = _gda_firebird_meta__constraints_tab;
- provider_class->meta_funcs.constraints_tab = _gda_firebird_meta_constraints_tab;
- provider_class->meta_funcs._constraints_ref = _gda_firebird_meta__constraints_ref;
- provider_class->meta_funcs.constraints_ref = _gda_firebird_meta_constraints_ref;
- provider_class->meta_funcs._key_columns = _gda_firebird_meta__key_columns;
- provider_class->meta_funcs.key_columns = _gda_firebird_meta_key_columns;
- provider_class->meta_funcs._check_columns = _gda_firebird_meta__check_columns;
- provider_class->meta_funcs.check_columns = _gda_firebird_meta_check_columns;
- provider_class->meta_funcs._triggers = _gda_firebird_meta__triggers;
- provider_class->meta_funcs.triggers = _gda_firebird_meta_triggers;
- provider_class->meta_funcs._routines = _gda_firebird_meta__routines;
- provider_class->meta_funcs.routines = _gda_firebird_meta_routines;
- provider_class->meta_funcs._routine_col = _gda_firebird_meta__routine_col;
- provider_class->meta_funcs.routine_col = _gda_firebird_meta_routine_col;
- provider_class->meta_funcs._routine_par = _gda_firebird_meta__routine_par;
- provider_class->meta_funcs.routine_par = _gda_firebird_meta_routine_par;
- provider_class->meta_funcs._indexes_tab = _gda_firebird_meta__indexes_tab;
- provider_class->meta_funcs.indexes_tab = _gda_firebird_meta_indexes_tab;
- provider_class->meta_funcs._index_cols = _gda_firebird_meta__index_cols;
- provider_class->meta_funcs.index_cols = _gda_firebird_meta_index_cols;
-
- /* distributed transactions: if not supported, then provider_class->xa_funcs should be set to NULL */
- provider_class->xa_funcs = NULL;
- /*
- provider_class->xa_funcs = g_new0 (GdaServerProviderXa, 1);
- provider_class->xa_funcs->xa_start = gda_firebird_provider_xa_start;
- provider_class->xa_funcs->xa_end = gda_firebird_provider_xa_end;
- provider_class->xa_funcs->xa_prepare = gda_firebird_provider_xa_prepare;
- provider_class->xa_funcs->xa_commit = gda_firebird_provider_xa_commit;
- provider_class->xa_funcs->xa_rollback = gda_firebird_provider_xa_rollback;
- provider_class->xa_funcs->xa_recover = gda_firebird_provider_xa_recover;
- */
+ /* set virtual functions */
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_BASE,
+ (gpointer) &firebird_base_functions);
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_META,
+ (gpointer) &firebird_meta_functions);
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_XA,
+ (gpointer) &firebird_xa_functions);
}
static void
@@ -350,6 +359,20 @@ gda_firebird_provider_get_type (void)
return type;
}
+static GdaWorker *
+gda_firebird_provider_create_worker (GdaServerProvider *provider)
+{
+ static GdaWorker *unique_worker = NULL;
+ if (unique_worker)
+ return gda_worker_ref (unique_worker);
+
+ if (0) /* We need to determine if the Firebird API is thread safe */
+ return gda_worker_new ();
+ else {
+ unique_worker = gda_worker_new ();
+ return gda_worker_ref (unique_worker);
+ }
+}
/*
* Get provider name request
@@ -382,18 +405,11 @@ gda_firebird_provider_get_version (GdaServerProvider *provider)
*/
static gboolean
gda_firebird_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- guint *task_id, GdaServerProviderAsyncCallback async_cb, gpointer
cb_data)
+ GdaQuarkList *params, GdaQuarkList *auth)
{
g_return_val_if_fail (GDA_IS_FIREBIRD_PROVIDER (provider), FALSE);
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
- /* If asynchronous connection opening is not supported, then exit now */
- if (async_cb) {
- gda_connection_add_event_string (cnc, _("Provider does not support asynchronous connection
open"));
- return FALSE;
- }
-
/* Check for connection parameters */
const gchar *fb_db, *fb_dir, *fb_user, *fb_password, *fb_host;
gchar *fb_conn;
@@ -493,7 +509,8 @@ gda_firebird_provider_open_connection (GdaServerProvider *provider, GdaConnectio
cdata->dbname = fb_conn;
cdata->server_version = fb_server_get_version (cdata);
- gda_connection_internal_set_provider_data (cnc, cdata, (GDestroyNotify) gda_firebird_free_cnc_data);
+ gda_connection_internal_set_provider_data (cnc, (GdaServerProviderConnectionData*) cdata,
+ (GDestroyNotify) gda_firebird_free_cnc_data);
return TRUE;
}
@@ -516,7 +533,7 @@ gda_firebird_provider_close_connection (GdaServerProvider *provider, GdaConnecti
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
/* Close the connection using the C API */
- cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return FALSE;
@@ -544,7 +561,7 @@ gda_firebird_provider_get_server_version (GdaServerProvider *provider, GdaConnec
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
- cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return FALSE;
@@ -564,7 +581,7 @@ gda_firebird_provider_get_database (GdaServerProvider *provider, GdaConnection *
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
- cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
@@ -722,18 +739,10 @@ gda_firebird_provider_render_operation (GdaServerProvider *provider, GdaConnecti
*/
static gboolean
gda_firebird_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
- GdaServerOperation *op, guint *task_id,
- GdaServerProviderAsyncCallback async_cb, gpointer cb_data, GError
**error)
+ GdaServerOperation *op, GError **error)
{
GdaServerOperationType optype;
- /* If asynchronous connection opening is not supported, then exit now */
- if (async_cb) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
- "%s", _("Provider does not support asynchronous server operation"));
- return FALSE;
- }
-
if (cnc) {
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
@@ -1156,7 +1165,7 @@ gda_firebird_provider_statement_prepare (GdaServerProvider *provider, GdaConnect
goto out_err;
/* get private connection data */
- cdata = (FirebirdConnectionData *) gda_connection_internal_get_provider_data (cnc);
+ cdata = (FirebirdConnectionData *) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
goto out_err;
@@ -1369,9 +1378,6 @@ gda_firebird_provider_statement_execute (GdaServerProvider *provider,
GdaStatementModelUsage model_usage,
GType *col_types,
GdaSet **last_inserted_row,
- guint *task_id,
- GdaServerProviderExecCallback async_cb,
- gpointer cb_data,
GError **error)
{
GdaFirebirdPStmt *ps;
@@ -1383,13 +1389,6 @@ gda_firebird_provider_statement_execute (GdaServerProvider *provider,
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
- /* If asynchronous connection opening is not supported, then exit now */
- if (async_cb) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
- "%s", _("Provider does not support asynchronous statement execution"));
- return FALSE;
- }
-
cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
if (!cdata)
return FALSE;
diff --git a/providers/firebird/gda-firebird-recordset.c b/providers/firebird/gda-firebird-recordset.c
index 336c5c5..fb16eeb 100644
--- a/providers/firebird/gda-firebird-recordset.c
+++ b/providers/firebird/gda-firebird-recordset.c
@@ -553,7 +553,7 @@ gda_firebird_recordset_new (GdaConnection *cnc,
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (ps, NULL);
- cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
diff --git a/providers/firebird/gda-firebird-util.c b/providers/firebird/gda-firebird-util.c
index cd42229..c414f03 100644
--- a/providers/firebird/gda-firebird-util.c
+++ b/providers/firebird/gda-firebird-util.c
@@ -28,7 +28,7 @@ _gda_firebird_make_error (GdaConnection *cnc, const gint statement_type)
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
diff --git a/providers/firebird/gda-firebird.h b/providers/firebird/gda-firebird.h
index 78987dc..27a00d0 100644
--- a/providers/firebird/gda-firebird.h
+++ b/providers/firebird/gda-firebird.h
@@ -51,14 +51,16 @@
#define FIREBIRD_PROVIDER_NAME "Firebird"
#include <libgda/libgda.h>
+#include <libgda/gda-connection-private.h>
#include <ibase.h>
-
+
/*
* Provider's specific connection data
*/
typedef struct
{
+ GdaServerProviderConnectionData parent;
gchar *dpb;
isc_db_handle handle;
diff --git a/providers/jdbc/gda-jdbc-blob-op.c b/providers/jdbc/gda-jdbc-blob-op.c
index c7f9781..dfdf501 100644
--- a/providers/jdbc/gda-jdbc-blob-op.c
+++ b/providers/jdbc/gda-jdbc-blob-op.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 - 2011 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2008 - 2014 Vivien Malerba <malerba gnome-db org>
* Copyright (C) 2010 David King <davidk openismus com>
*
* This library is free software; you can redistribute it and/or
@@ -24,6 +24,7 @@
#include "gda-jdbc.h"
#include "gda-jdbc-util.h"
#include "gda-jdbc-blob-op.h"
+#include <libgda/gda-blob-op-impl.h>
#include "jni-globals.h"
struct _GdaJdbcBlobOpPrivate {
@@ -91,9 +92,9 @@ gda_jdbc_blob_op_class_init (GdaJdbcBlobOpClass *klass)
parent_class = g_type_class_peek_parent (klass);
object_class->finalize = gda_jdbc_blob_op_finalize;
- blob_class->get_length = gda_jdbc_blob_op_get_length;
- blob_class->read = gda_jdbc_blob_op_read;
- blob_class->write = gda_jdbc_blob_op_write;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->get_length = gda_jdbc_blob_op_get_length;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->read = gda_jdbc_blob_op_read;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->write = gda_jdbc_blob_op_write;
}
static void
@@ -129,7 +130,7 @@ gda_jdbc_blob_op_new_with_jblob (GdaConnection *cnc, JNIEnv *jenv, jobject blob_
if ((*jenv)->GetJavaVM (jenv, &jvm))
g_error ("Could not attach JAVA virtual machine's current thread");
- bop = g_object_new (GDA_TYPE_JDBC_BLOB_OP, NULL);
+ bop = g_object_new (GDA_TYPE_JDBC_BLOB_OP, "connection", cnc, NULL);
bop->priv->cnc = cnc;
bop->priv->blob_obj = gda_value_new_jni_object (jvm, jenv, blob_obj);
diff --git a/providers/jdbc/gda-jdbc-provider.c b/providers/jdbc/gda-jdbc-provider.c
index fcca2f9..20c2ba8 100644
--- a/providers/jdbc/gda-jdbc-provider.c
+++ b/providers/jdbc/gda-jdbc-provider.c
@@ -29,6 +29,7 @@
#include <libgda/libgda.h>
#include <libgda/gda-data-model-private.h>
#include <libgda/gda-server-provider-extra.h>
+#include <libgda/gda-server-provider-impl.h>
#include <libgda/binreloc/gda-binreloc.h>
#include <libgda/gda-statement-extra.h>
#include <sql-parser/gda-sql-parser.h>
@@ -58,8 +59,7 @@ static GObjectClass *parent_class = NULL;
*/
/* connection management */
static gboolean gda_jdbc_provider_open_connection (GdaServerProvider *provider, GdaConnection
*cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- guint *task_id, GdaServerProviderAsyncCallback
async_cb, gpointer cb_data);
+ GdaQuarkList *params, GdaQuarkList *auth);
static gboolean gda_jdbc_provider_close_connection (GdaServerProvider *provider, GdaConnection
*cnc);
static const gchar *gda_jdbc_provider_get_server_version (GdaServerProvider *provider, GdaConnection
*cnc);
@@ -73,9 +73,7 @@ static gchar *gda_jdbc_provider_render_operation (GdaServerProvider
GdaServerOperation *op, GError **error);
static gboolean gda_jdbc_provider_perform_operation (GdaServerProvider *provider, GdaConnection
*cnc,
- GdaServerOperation *op, guint *task_id,
- GdaServerProviderAsyncCallback async_cb,
gpointer cb_data,
- GError **error);
+ GdaServerOperation *op, GError **error);
/* transactions */
static gboolean gda_jdbc_provider_begin_transaction (GdaServerProvider *provider, GdaConnection
*cnc,
const gchar *name, GdaTransactionIsolation
level, GError **error);
@@ -112,29 +110,27 @@ static gboolean gda_jdbc_provider_statement_prepare (GdaServerProvid
static GObject *gda_jdbc_provider_statement_execute (GdaServerProvider *provider, GdaConnection
*cnc,
GdaStatement *stmt, GdaSet *params,
GdaStatementModelUsage model_usage,
- GType *col_types, GdaSet
**last_inserted_row,
- guint *task_id,
GdaServerProviderExecCallback async_cb,
- gpointer cb_data, GError **error);
-static GdaSqlStatement *gda_jdbc_statement_rewrite (GdaServerProvider *provider, GdaConnection
*cnc,
+ GType *col_types, GdaSet
**last_inserted_row, GError **error);
+static GdaSqlStatement *gda_jdbc_provider_statement_rewrite (GdaServerProvider *provider, GdaConnection
*cnc,
GdaStatement *stmt, GdaSet *params, GError
**error);
/* distributed transactions */
static gboolean gda_jdbc_provider_xa_start (GdaServerProvider *provider, GdaConnection *cnc,
- const GdaXaTransactionId *xid, GError **error);
+ const GdaXaTransactionId *xid, GError **error);
static gboolean gda_jdbc_provider_xa_end (GdaServerProvider *provider, GdaConnection *cnc,
- const GdaXaTransactionId *xid, GError **error);
+ const GdaXaTransactionId *xid, GError **error);
static gboolean gda_jdbc_provider_xa_prepare (GdaServerProvider *provider, GdaConnection *cnc,
- const GdaXaTransactionId *xid, GError **error);
+ const GdaXaTransactionId *xid, GError **error);
static gboolean gda_jdbc_provider_xa_commit (GdaServerProvider *provider, GdaConnection *cnc,
- const GdaXaTransactionId *xid, GError **error);
+ const GdaXaTransactionId *xid, GError **error);
static gboolean gda_jdbc_provider_xa_rollback (GdaServerProvider *provider, GdaConnection *cnc,
- const GdaXaTransactionId *xid, GError **error);
+ const GdaXaTransactionId *xid, GError **error);
static GList *gda_jdbc_provider_xa_recover (GdaServerProvider *provider, GdaConnection *cnc,
- GError **error);
+ GError **error);
/*
* private connection data destroy
@@ -161,6 +157,103 @@ static gchar *internal_sql[] = {
/*
* GdaJdbcProvider class implementation
*/
+GdaServerProviderBase jdbc_base_functions = {
+ gda_jdbc_provider_get_name,
+ gda_jdbc_provider_get_version,
+ gda_jdbc_provider_get_server_version,
+ gda_jdbc_provider_supports_feature,
+ NULL,
+ NULL,
+ NULL,
+ gda_jdbc_provider_get_data_handler,
+ gda_jdbc_provider_get_default_dbms_type,
+ gda_jdbc_provider_supports_operation,
+ gda_jdbc_provider_create_operation,
+ gda_jdbc_provider_render_operation,
+ gda_jdbc_provider_statement_to_sql,
+ NULL,
+ gda_jdbc_provider_statement_rewrite,
+ gda_jdbc_provider_open_connection,
+ NULL,
+ gda_jdbc_provider_close_connection,
+ NULL,
+ NULL,
+ NULL,
+ gda_jdbc_provider_perform_operation,
+ gda_jdbc_provider_begin_transaction,
+ gda_jdbc_provider_commit_transaction,
+ gda_jdbc_provider_rollback_transaction,
+ gda_jdbc_provider_add_savepoint,
+ gda_jdbc_provider_rollback_savepoint,
+ gda_jdbc_provider_delete_savepoint,
+ gda_jdbc_provider_statement_prepare,
+ gda_jdbc_provider_statement_execute,
+
+ NULL, NULL, NULL, NULL, /* padding */
+};
+
+GdaServerProviderMeta jdbc_meta_functions = {
+ _gda_jdbc_meta__info,
+ _gda_jdbc_meta__btypes,
+ _gda_jdbc_meta__udt,
+ _gda_jdbc_meta_udt,
+ _gda_jdbc_meta__udt_cols,
+ _gda_jdbc_meta_udt_cols,
+ _gda_jdbc_meta__enums,
+ _gda_jdbc_meta_enums,
+ _gda_jdbc_meta__domains,
+ _gda_jdbc_meta_domains,
+ _gda_jdbc_meta__constraints_dom,
+ _gda_jdbc_meta_constraints_dom,
+ _gda_jdbc_meta__el_types,
+ _gda_jdbc_meta_el_types,
+ _gda_jdbc_meta__collations,
+ _gda_jdbc_meta_collations,
+ _gda_jdbc_meta__character_sets,
+ _gda_jdbc_meta_character_sets,
+ _gda_jdbc_meta__schemata,
+ _gda_jdbc_meta_schemata,
+ _gda_jdbc_meta__tables_views,
+ _gda_jdbc_meta_tables_views,
+ _gda_jdbc_meta__columns,
+ _gda_jdbc_meta_columns,
+ _gda_jdbc_meta__view_cols,
+ _gda_jdbc_meta_view_cols,
+ _gda_jdbc_meta__constraints_tab,
+ _gda_jdbc_meta_constraints_tab,
+ _gda_jdbc_meta__constraints_ref,
+ _gda_jdbc_meta_constraints_ref,
+ _gda_jdbc_meta__key_columns,
+ _gda_jdbc_meta_key_columns,
+ _gda_jdbc_meta__check_columns,
+ _gda_jdbc_meta_check_columns,
+ _gda_jdbc_meta__triggers,
+ _gda_jdbc_meta_triggers,
+ _gda_jdbc_meta__routines,
+ _gda_jdbc_meta_routines,
+ _gda_jdbc_meta__routine_col,
+ _gda_jdbc_meta_routine_col,
+ _gda_jdbc_meta__routine_par,
+ _gda_jdbc_meta_routine_par,
+ _gda_jdbc_meta__indexes_tab,
+ _gda_jdbc_meta_indexes_tab,
+ _gda_jdbc_meta__index_cols,
+ _gda_jdbc_meta_index_cols,
+
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* padding */
+};
+
+GdaServerProviderXa jdbc_xa_functions = {
+ gda_jdbc_provider_xa_start,
+ gda_jdbc_provider_xa_end,
+ gda_jdbc_provider_xa_prepare,
+ gda_jdbc_provider_xa_commit,
+ gda_jdbc_provider_xa_rollback,
+ gda_jdbc_provider_xa_recover,
+
+ NULL, NULL, NULL, NULL, /* padding */
+};
+
static void
gda_jdbc_provider_class_init (GdaJdbcProviderClass *klass)
{
@@ -168,100 +261,16 @@ gda_jdbc_provider_class_init (GdaJdbcProviderClass *klass)
parent_class = g_type_class_peek_parent (klass);
- provider_class->get_version = gda_jdbc_provider_get_version;
- provider_class->get_server_version = gda_jdbc_provider_get_server_version;
- provider_class->get_name = gda_jdbc_provider_get_name;
- provider_class->supports_feature = gda_jdbc_provider_supports_feature;
-
- provider_class->get_data_handler = gda_jdbc_provider_get_data_handler;
- provider_class->get_def_dbms_type = gda_jdbc_provider_get_default_dbms_type;
-
- provider_class->open_connection = gda_jdbc_provider_open_connection;
- provider_class->close_connection = gda_jdbc_provider_close_connection;
- provider_class->get_database = NULL;
-
- provider_class->supports_operation = gda_jdbc_provider_supports_operation;
- provider_class->create_operation = gda_jdbc_provider_create_operation;
- provider_class->render_operation = gda_jdbc_provider_render_operation;
- provider_class->perform_operation = gda_jdbc_provider_perform_operation;
-
- provider_class->begin_transaction = gda_jdbc_provider_begin_transaction;
- provider_class->commit_transaction = gda_jdbc_provider_commit_transaction;
- provider_class->rollback_transaction = gda_jdbc_provider_rollback_transaction;
- provider_class->add_savepoint = gda_jdbc_provider_add_savepoint;
- provider_class->rollback_savepoint = gda_jdbc_provider_rollback_savepoint;
- provider_class->delete_savepoint = gda_jdbc_provider_delete_savepoint;
-
- provider_class->create_parser = NULL;
- provider_class->statement_to_sql = NULL; /* don't use gda_jdbc_provider_statement_to_sql()
- * because it only calls gda_statement_to_sql_extended() */
- provider_class->statement_prepare = gda_jdbc_provider_statement_prepare;
- provider_class->statement_execute = gda_jdbc_provider_statement_execute;
- provider_class->statement_rewrite = gda_jdbc_statement_rewrite;
-
- provider_class->is_busy = NULL;
- provider_class->cancel = NULL;
- provider_class->create_connection = NULL;
-
- memset (&(provider_class->meta_funcs), 0, sizeof (GdaServerProviderMeta));
- provider_class->meta_funcs._info = _gda_jdbc_meta__info;
- provider_class->meta_funcs._btypes = _gda_jdbc_meta__btypes;
- provider_class->meta_funcs._udt = _gda_jdbc_meta__udt;
- provider_class->meta_funcs.udt = _gda_jdbc_meta_udt;
- provider_class->meta_funcs._udt_cols = _gda_jdbc_meta__udt_cols;
- provider_class->meta_funcs.udt_cols = _gda_jdbc_meta_udt_cols;
- provider_class->meta_funcs._enums = _gda_jdbc_meta__enums;
- provider_class->meta_funcs.enums = _gda_jdbc_meta_enums;
- provider_class->meta_funcs._domains = _gda_jdbc_meta__domains;
- provider_class->meta_funcs.domains = _gda_jdbc_meta_domains;
- provider_class->meta_funcs._constraints_dom = _gda_jdbc_meta__constraints_dom;
- provider_class->meta_funcs.constraints_dom = _gda_jdbc_meta_constraints_dom;
- provider_class->meta_funcs._el_types = _gda_jdbc_meta__el_types;
- provider_class->meta_funcs.el_types = _gda_jdbc_meta_el_types;
- provider_class->meta_funcs._collations = _gda_jdbc_meta__collations;
- provider_class->meta_funcs.collations = _gda_jdbc_meta_collations;
- provider_class->meta_funcs._character_sets = _gda_jdbc_meta__character_sets;
- provider_class->meta_funcs.character_sets = _gda_jdbc_meta_character_sets;
- provider_class->meta_funcs._schemata = _gda_jdbc_meta__schemata;
- provider_class->meta_funcs.schemata = _gda_jdbc_meta_schemata;
- provider_class->meta_funcs._tables_views = _gda_jdbc_meta__tables_views;
- provider_class->meta_funcs.tables_views = _gda_jdbc_meta_tables_views;
- provider_class->meta_funcs._columns = _gda_jdbc_meta__columns;
- provider_class->meta_funcs.columns = _gda_jdbc_meta_columns;
- provider_class->meta_funcs._view_cols = _gda_jdbc_meta__view_cols;
- provider_class->meta_funcs.view_cols = _gda_jdbc_meta_view_cols;
- provider_class->meta_funcs._constraints_tab = _gda_jdbc_meta__constraints_tab;
- provider_class->meta_funcs.constraints_tab = _gda_jdbc_meta_constraints_tab;
- provider_class->meta_funcs._constraints_ref = _gda_jdbc_meta__constraints_ref;
- provider_class->meta_funcs.constraints_ref = _gda_jdbc_meta_constraints_ref;
- provider_class->meta_funcs._key_columns = _gda_jdbc_meta__key_columns;
- provider_class->meta_funcs.key_columns = _gda_jdbc_meta_key_columns;
- provider_class->meta_funcs._check_columns = _gda_jdbc_meta__check_columns;
- provider_class->meta_funcs.check_columns = _gda_jdbc_meta_check_columns;
- provider_class->meta_funcs._triggers = _gda_jdbc_meta__triggers;
- provider_class->meta_funcs.triggers = _gda_jdbc_meta_triggers;
- provider_class->meta_funcs._routines = _gda_jdbc_meta__routines;
- provider_class->meta_funcs.routines = _gda_jdbc_meta_routines;
- provider_class->meta_funcs._routine_col = _gda_jdbc_meta__routine_col;
- provider_class->meta_funcs.routine_col = _gda_jdbc_meta_routine_col;
- provider_class->meta_funcs._routine_par = _gda_jdbc_meta__routine_par;
- provider_class->meta_funcs.routine_par = _gda_jdbc_meta_routine_par;
- provider_class->meta_funcs._indexes_tab = _gda_jdbc_meta__indexes_tab;
- provider_class->meta_funcs.indexes_tab = _gda_jdbc_meta_indexes_tab;
- provider_class->meta_funcs._index_cols = _gda_jdbc_meta__index_cols;
- provider_class->meta_funcs.index_cols = _gda_jdbc_meta_index_cols;
-
- /* distributed transactions: if not supported, then provider_class->xa_funcs should be set to NULL */
- provider_class->xa_funcs = g_new0 (GdaServerProviderXa, 1);
- provider_class->xa_funcs->xa_start = gda_jdbc_provider_xa_start;
- provider_class->xa_funcs->xa_end = gda_jdbc_provider_xa_end;
- provider_class->xa_funcs->xa_prepare = gda_jdbc_provider_xa_prepare;
- provider_class->xa_funcs->xa_commit = gda_jdbc_provider_xa_commit;
- provider_class->xa_funcs->xa_rollback = gda_jdbc_provider_xa_rollback;
- provider_class->xa_funcs->xa_recover = gda_jdbc_provider_xa_recover;
-
- /* not limiting to current thread */
- provider_class->limiting_thread = NULL;
+ /* set virtual functions */
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_BASE,
+ (gpointer) &jdbc_base_functions);
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_META,
+ (gpointer) &jdbc_meta_functions);
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_XA,
+ (gpointer) &jdbc_xa_functions);
}
extern JavaVM *_jdbc_provider_java_vm;
@@ -287,8 +296,6 @@ gda_jdbc_provider_init (GdaJdbcProvider *jdbc_prv, G_GNUC_UNUSED GdaJdbcProvider
/* meta data init */
_gda_jdbc_provider_meta_init ((GdaServerProvider*) jdbc_prv);
- /* TO_ADD: any other provider's init should be added here */
-
g_mutex_unlock (&init_mutex);
}
@@ -466,21 +473,13 @@ make_url_from_params (GdaServerProvider *provider, GdaConnection *cnc,
*/
static gboolean
gda_jdbc_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- G_GNUC_UNUSED guint *task_id, GdaServerProviderAsyncCallback async_cb,
- G_GNUC_UNUSED gpointer cb_data)
+ GdaQuarkList *params, GdaQuarkList *auth)
{
GdaJdbcProvider *jprov;
g_return_val_if_fail (GDA_IS_JDBC_PROVIDER (provider), FALSE);
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
jprov = (GdaJdbcProvider*) provider;
- /* If asynchronous connection opening is not supported, then exit now */
- if (async_cb) {
- gda_connection_add_event_string (cnc, _("Provider does not support asynchronous connection
open"));
- return FALSE;
- }
-
/* Check for connection parameters */
gchar *url;
const gchar *cstr;
@@ -556,7 +555,8 @@ gda_jdbc_provider_open_connection (GdaServerProvider *provider, GdaConnection *c
* and set its contents */
JdbcConnectionData *cdata;
cdata = g_new0 (JdbcConnectionData, 1);
- gda_connection_internal_set_provider_data (cnc, cdata, (GDestroyNotify) gda_jdbc_free_cnc_data);
+ gda_connection_internal_set_provider_data (cnc, (GdaServerProviderConnectionData*) cdata,
+ (GDestroyNotify) gda_jdbc_free_cnc_data);
cdata->jcnc_obj = obj_value;
_gda_jdbc_release_jenv (jni_detach);
@@ -581,7 +581,7 @@ gda_jdbc_provider_close_connection (GdaServerProvider *provider, GdaConnection *
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
/* Close the connection using the C API */
- cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return FALSE;
@@ -605,7 +605,7 @@ gda_jdbc_provider_get_server_version (GdaServerProvider *provider, GdaConnection
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
- cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return FALSE;
@@ -705,17 +705,8 @@ gda_jdbc_provider_render_operation (GdaServerProvider *provider, GdaConnection *
*/
static gboolean
gda_jdbc_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
- G_GNUC_UNUSED GdaServerOperation *op, G_GNUC_UNUSED guint *task_id,
- GdaServerProviderAsyncCallback async_cb, G_GNUC_UNUSED gpointer cb_data,
- GError **error)
+ G_GNUC_UNUSED GdaServerOperation *op, GError **error)
{
- /* If asynchronous connection opening is not supported, then exit now */
- if (async_cb) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
- "%s", _("Provider does not support asynchronous server operation"));
- return FALSE;
- }
-
if (cnc) {
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
@@ -1334,9 +1325,7 @@ static GObject *
gda_jdbc_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
GdaStatement *stmt, GdaSet *params,
GdaStatementModelUsage model_usage,
- GType *col_types, GdaSet **last_inserted_row,
- guint *task_id,
- GdaServerProviderExecCallback async_cb, gpointer cb_data, GError **error)
+ GType *col_types, GdaSet **last_inserted_row, GError **error)
{
GdaJdbcPStmt *ps;
JdbcConnectionData *cdata;
@@ -1350,13 +1339,6 @@ gda_jdbc_provider_statement_execute (GdaServerProvider *provider, GdaConnection
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
- /* If asynchronous connection opening is not supported, then exit now */
- if (async_cb) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
- "%s", _("Provider does not support asynchronous statement execution"));
- return NULL;
- }
-
if (! (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS) &&
! (model_usage & GDA_STATEMENT_MODEL_CURSOR_FORWARD))
model_usage |= GDA_STATEMENT_MODEL_RANDOM_ACCESS;
@@ -1536,9 +1518,7 @@ gda_jdbc_provider_statement_execute (GdaServerProvider *provider, GdaConnection
res = gda_jdbc_provider_statement_execute (provider, cnc,
rstmt, params,
model_usage,
- col_types, last_inserted_row,
- task_id,
- async_cb, cb_data, error);
+ col_types, last_inserted_row, error);
g_object_unref (rstmt);
return res;
}
@@ -1598,9 +1578,7 @@ gda_jdbc_provider_statement_execute (GdaServerProvider *provider, GdaConnection
rstmt, params,
model_usage,
col_types,
- last_inserted_row,
- task_id, async_cb,
- cb_data, error);
+ last_inserted_row, error);
/* clear original @param_ids and restore copied one */
g_slist_foreach (prep_param_ids, (GFunc) g_free, NULL);
g_slist_free (prep_param_ids);
@@ -1763,8 +1741,8 @@ gda_jdbc_provider_statement_execute (GdaServerProvider *provider, GdaConnection
* Safely removes any default value inserted or updated
*/
static GdaSqlStatement *
-gda_jdbc_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
- GdaStatement *stmt, GdaSet *params, GError **error)
+gda_jdbc_provider_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error)
{
if (cnc) {
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
diff --git a/providers/jdbc/gda-jdbc-recordset.c b/providers/jdbc/gda-jdbc-recordset.c
index c682a60..28db28e 100644
--- a/providers/jdbc/gda-jdbc-recordset.c
+++ b/providers/jdbc/gda-jdbc-recordset.c
@@ -247,7 +247,7 @@ gda_jdbc_recordset_new (GdaConnection *cnc, GdaJdbcPStmt *ps, GdaSet *exec_param
else
ps = gda_jdbc_pstmt_new (NULL);
- cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
diff --git a/providers/jdbc/gda-jdbc-test.c b/providers/jdbc/gda-jdbc-test.c
index fb0b342..0e74f6e 100644
--- a/providers/jdbc/gda-jdbc-test.c
+++ b/providers/jdbc/gda-jdbc-test.c
@@ -97,15 +97,21 @@ test_h2 (void)
tmp = gda_rfc1738_encode (H2_USERNAME);
real_auth = g_strdup_printf ("USERNAME=%s", tmp);
g_free (tmp);
- cnc = gda_connection_open_from_string (H2_PROVNAME, "URL=" H2_CNCSTRING, real_auth,
- GDA_CONNECTION_OPTIONS_NONE, &error);
+ cnc = gda_connection_new_from_string (H2_PROVNAME, "URL=" H2_CNCSTRING, real_auth,
+ GDA_CONNECTION_OPTIONS_NONE, &error);
g_free (real_auth);
if (!cnc) {
- g_print ("Could open connection with the '%s' provider: %s\n", "org.h2.Driver",
+ g_print ("Could create connection with the '%s' provider: %s\n", "org.h2.Driver",
error && error->message ? error->message : "No detail");
exit (1);
}
+ if (!gda_connection_open (cnc, &error)) {
+ g_print ("Could open connection with the '%s' provider: %s\n", "org.h2.Driver",
+ error && error->message ? error->message : "No detail");
+ g_object_unref (cnc);
+ exit (1);
+ }
run_select (cnc, "SELECT * FROM t_string");
run_select (cnc, "SELECT * FROM t_numbers");
run_select (cnc, "SELECT * FROM t_misc");
@@ -133,14 +139,14 @@ test_generic (const gchar *prov_name, const gchar *cnc_string, const gchar *user
}
/* open connection - failure */
- g_print ("TEST: Connection opening with failure...\n");
- cnc = gda_connection_open_from_string (prov_name, "URL=hello", NULL,
- GDA_CONNECTION_OPTIONS_NONE, &error);
+ g_print ("TEST: Connection creating with failure...\n");
+ cnc = gda_connection_new_from_string (prov_name, "URL=hello", NULL,
+ GDA_CONNECTION_OPTIONS_NONE, &error);
if (cnc) {
- g_print ("Connection opening should have failed...\n");
+ g_print ("Connection creating should have failed...\n");
exit (1);
}
- g_print ("Connection opening error: %s\n",
+ g_print ("Connection creating error: %s\n",
error && error->message ? error->message : "No detail");
if (error) {
g_error_free (error);
@@ -160,16 +166,27 @@ test_generic (const gchar *prov_name, const gchar *cnc_string, const gchar *user
g_free (tmp);
g_print ("CNC STRING: %s\n", real_cnc_string);
- cnc = gda_connection_open_from_string (prov_name, real_cnc_string, real_auth,
- GDA_CONNECTION_OPTIONS_NONE, &error);
+ cnc = gda_connection_new_from_string (prov_name, real_cnc_string, real_auth,
+ GDA_CONNECTION_OPTIONS_NONE, &error);
g_free (real_cnc_string);
g_free (real_auth);
if (!cnc) {
+ g_print ("Could create connection with the '%s' provider: %s\n", prov_name,
+ error && error->message ? error->message : "No detail");
+ exit (1);
+ }
+ if (! gda_connection_open (cnc, &error)) {
g_print ("Could open connection with the '%s' provider: %s\n", prov_name,
error && error->message ? error->message : "No detail");
exit (1);
}
- gda_connection_close (cnc);
+
+ if (! gda_connection_close (cnc, &error)) {
+ g_print ("Connection closing error: %s\n",
+ error && error->message ? error->message : "No detail");
+ exit (1);
+ }
+
if (! gda_connection_open (cnc, &error)) {
g_print ("Connection re-opening error: %s\n",
error && error->message ? error->message : "No detail");
diff --git a/providers/jdbc/gda-jdbc.h b/providers/jdbc/gda-jdbc.h
index 728d26c..63c80cf 100644
--- a/providers/jdbc/gda-jdbc.h
+++ b/providers/jdbc/gda-jdbc.h
@@ -32,11 +32,13 @@
/* headers necessary for the C API */
#include <jni.h>
#include <glib-object.h>
+#include <libgda/gda-connection-private.h>
/*
* Provider's specific connection data
*/
typedef struct {
+ GdaServerProviderConnectionData parent;
gchar *server_version;
GValue *jcnc_obj; /* JAVA GdaJConnection object */
GValue *jmeta_obj; /* JAVA GdaJMeta object */
diff --git a/providers/ldap/gda-ldap-provider.c b/providers/ldap/gda-ldap-provider.c
index 11ddcb4..9f0fee1 100644
--- a/providers/ldap/gda-ldap-provider.c
+++ b/providers/ldap/gda-ldap-provider.c
@@ -28,7 +28,7 @@
#include <string.h>
#include <glib/gi18n-lib.h>
#include <virtual/gda-ldap-connection.h>
-#include <libgda/gda-connection-private.h>
+#include <libgda/gda-server-provider-impl.h>
#include <libgda/gda-data-model-iter.h>
#include <libgda/gda-util.h>
#include <libgda/gda-data-model-array.h>
@@ -46,15 +46,12 @@ static void gda_ldap_provider_finalize (GObject *object);
static const gchar *gda_ldap_provider_get_name (GdaServerProvider *provider);
static const gchar *gda_ldap_provider_get_version (GdaServerProvider *provider);
static GdaConnection *gda_ldap_provider_create_connection (GdaServerProvider *provider);
-static gboolean gda_ldap_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- guint *task_id, GdaServerProviderAsyncCallback async_cb,
gpointer cb_data);
+static gboolean gda_ldap_provider_prepare_connection (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaQuarkList *params, GdaQuarkList *auth);
static GObject *gda_ldap_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
GdaStatement *stmt, GdaSet *params,
GdaStatementModelUsage model_usage,
- GType *col_types, GdaSet **last_inserted_row,
- guint *task_id, GdaServerProviderExecCallback async_cb,
- gpointer cb_data, GError **error);
+ GType *col_types, GdaSet **last_inserted_row, GError
**error);
static const gchar *gda_ldap_provider_get_server_version (GdaServerProvider *provider,
GdaConnection *cnc);
static const gchar *gda_ldap_provider_get_database (GdaServerProvider *provider, GdaConnection *cnc);
@@ -69,23 +66,62 @@ static void gda_ldap_free_cnc_data (LdapConnectionData *cdata);
/*
* GdaLdapProvider class implementation
*/
+GdaServerProviderBase ldap_base_functions = {
+ gda_ldap_provider_get_name,
+ gda_ldap_provider_get_version,
+ gda_ldap_provider_get_server_version,
+ NULL,
+ NULL,
+ gda_ldap_provider_create_connection,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ gda_ldap_provider_prepare_connection,
+ NULL,
+ NULL,
+ NULL,
+ gda_ldap_provider_get_database,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ gda_ldap_provider_statement_execute,
+
+ NULL, NULL, NULL, NULL, /* padding */
+};
+
static void
gda_ldap_provider_class_init (GdaLdapProviderClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GdaServerProviderClass *provider_class = GDA_SERVER_PROVIDER_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
+ /* set virtual functions */
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_BASE,
+ (gpointer) &ldap_base_functions);
+
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_META,
+ (gpointer) NULL);
+
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_XA,
+ (gpointer) NULL);
+
object_class->finalize = gda_ldap_provider_finalize;
- provider_class->create_connection = gda_ldap_provider_create_connection;
-
- provider_class->get_name = gda_ldap_provider_get_name;
- provider_class->get_version = gda_ldap_provider_get_version;
- provider_class->open_connection = gda_ldap_provider_open_connection;
- provider_class->get_server_version = gda_ldap_provider_get_server_version;
- provider_class->get_database = gda_ldap_provider_get_database;
- provider_class->statement_execute = gda_ldap_provider_statement_execute;
}
static void
@@ -327,33 +363,24 @@ fetch_user_dn (const gchar *url, const gchar *base, const gchar *username, LdapA
}
/*
- * Open connection request
+ * Prepare connection request
*
* In this function, the following _must_ be done:
* - check for the presence and validify of the parameters required to actually open a connection,
* using @params
* - open the real connection to the database using the parameters previously checked, create one or
* more GdaDataModel objects and declare them to the virtual connection with table names
- * - open virtual (SQLite) connection
* - create a LdapConnectionData structure and associate it to @cnc
*
* Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR connection event must be added to
@cnc)
*/
static gboolean
-gda_ldap_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- G_GNUC_UNUSED guint *task_id, GdaServerProviderAsyncCallback async_cb,
- G_GNUC_UNUSED gpointer cb_data)
+gda_ldap_provider_prepare_connection (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaQuarkList *params, GdaQuarkList *auth)
{
g_return_val_if_fail (GDA_IS_LDAP_PROVIDER (provider), FALSE);
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
- /* Don't allow asynchronous connection opening for virtual providers */
- if (async_cb) {
- gda_connection_add_event_string (cnc, _("Provider does not support asynchronous connection
open"));
- return FALSE;
- }
-
/* Check for connection parameters */
const gchar *base_dn;
const gchar *host;
@@ -598,14 +625,6 @@ gda_ldap_provider_open_connection (GdaServerProvider *provider, GdaConnection *c
g_object_set_data ((GObject*) cnc, "__gda_connection_LDAP", (gpointer) 0x01);
gda_virtual_connection_internal_set_provider_data (GDA_VIRTUAL_CONNECTION (cnc),
cdata, (GDestroyNotify) gda_ldap_free_cnc_data);
- if (! GDA_SERVER_PROVIDER_CLASS (parent_class)->open_connection (GDA_SERVER_PROVIDER (provider), cnc,
params,
- NULL, NULL, NULL, NULL)) {
- gda_virtual_connection_internal_set_provider_data (GDA_VIRTUAL_CONNECTION (cnc), NULL, NULL);
- gda_connection_add_event_string (cnc, _("Can't open virtual connection"));
- gda_ldap_free_cnc_data (cdata);
- return FALSE;
- }
-
gda_ldap_may_unbind (cdata);
return TRUE;
}
@@ -792,15 +811,8 @@ static GObject *
gda_ldap_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
GdaStatement *stmt, GdaSet *params,
GdaStatementModelUsage model_usage,
- GType *col_types, GdaSet **last_inserted_row,
- guint *task_id, GdaServerProviderExecCallback async_cb,
- gpointer cb_data, GError **error)
+ GType *col_types, GdaSet **last_inserted_row, GError **error)
{
- if (async_cb) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
- "%s", _("Provider does not support asynchronous statement execution"));
- return NULL;
- }
gchar *sql;
sql = gda_statement_to_sql (stmt, params, NULL);
if (sql) {
@@ -964,10 +976,12 @@ gda_ldap_provider_statement_execute (GdaServerProvider *provider, GdaConnection
}
g_free (sql);
}
- return GDA_SERVER_PROVIDER_CLASS (parent_class)->statement_execute (provider, cnc, stmt, params,
- model_usage, col_types,
- last_inserted_row, task_id,
- async_cb, cb_data, error);
+
+ GdaServerProviderBase *fset;
+ fset = gda_server_provider_get_impl_functions_for_class (parent_class,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+ return fset->statement_execute (provider, cnc, stmt, params,
+ model_usage, col_types,
+ last_inserted_row, error);
}
/*
diff --git a/providers/ldap/gda-ldap.h b/providers/ldap/gda-ldap.h
index 8dbd5bc..e815082 100644
--- a/providers/ldap/gda-ldap.h
+++ b/providers/ldap/gda-ldap.h
@@ -32,11 +32,13 @@
#include <ldap_schema.h>
#include <glib.h>
#include <libgda/libgda.h>
+#include <libgda/gda-connection-private.h>
/*
* Provider's specific connection data
*/
typedef struct {
+ GdaServerProviderConnectionData parent;
guint keep_bound_count; /* set to >0 if connection must remain opened */
LDAP *handle;
diff --git a/providers/mdb/gda-mdb-provider.c b/providers/mdb/gda-mdb-provider.c
index 67c33e9..8c0027d 100644
--- a/providers/mdb/gda-mdb-provider.c
+++ b/providers/mdb/gda-mdb-provider.c
@@ -31,6 +31,7 @@
#include <virtual/gda-vconnection-data-model.h>
#include <libgda/gda-connection-private.h>
#include <libgda/gda-server-provider-extra.h>
+#include <libgda/gda-server-provider-impl.h>
#include <libgda/gda-data-model-array.h>
#include <libgda/gda-data-model-private.h>
#include <glib/gi18n-lib.h>
@@ -53,14 +54,9 @@ static void gda_mdb_provider_finalize (GObject *object);
static const gchar *gda_mdb_provider_get_name (GdaServerProvider *provider);
static const gchar *gda_mdb_provider_get_version (GdaServerProvider *provider);
-static gboolean gda_mdb_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- guint *task_id, GdaServerProviderAsyncCallback async_cb,
gpointer cb_data);
+static gboolean gda_mdb_provider_prepare_connection (GdaServerProvider *provider, GdaConnection *cnc,
GdaQuarkList *params, GdaQuarkList *auth);
static const gchar *gda_mdb_provider_get_server_version (GdaServerProvider *provider,
GdaConnection *cnc);
-static const gchar *gda_mdb_provider_get_database (GdaServerProvider *provider,
- GdaConnection *cnc);
-
static GObjectClass *parent_class = NULL;
static GMutex mdb_init_mutex;
@@ -75,6 +71,41 @@ static void gda_mdb_free_cnc_data (MdbConnectionData *cdata);
/*
* GdaMdbProvider class implementation
*/
+GdaServerProviderBase data_model_base_functions = {
+ gda_mdb_provider_get_name,
+ gda_mdb_provider_get_version,
+ gda_mdb_provider_get_server_version,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ gda_mdb_provider_prepare_connection,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ NULL, NULL, NULL, NULL, /* padding */
+};
+
static void
gda_mdb_provider_class_init (GdaMdbProviderClass *klass)
{
@@ -83,13 +114,12 @@ gda_mdb_provider_class_init (GdaMdbProviderClass *klass)
parent_class = g_type_class_peek_parent (klass);
- object_class->finalize = gda_mdb_provider_finalize;
+ /* set virtual functions */
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_BASE,
+ (gpointer) &data_model_base_functions);
- provider_class->get_name = gda_mdb_provider_get_name;
- provider_class->get_version = gda_mdb_provider_get_version;
- provider_class->open_connection = gda_mdb_provider_open_connection;
- provider_class->get_server_version = gda_mdb_provider_get_server_version;
- provider_class->get_database = gda_mdb_provider_get_database;
+ object_class->finalize = gda_mdb_provider_finalize;
}
static void
@@ -215,12 +245,11 @@ static GList *table_create_columns_func (LocalSpec *spec);
static GdaDataModel *table_create_model_func (LocalSpec *spec);
/*
- * Open connection request
+ * Prapare connection request
*/
static gboolean
-gda_mdb_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- guint *task_id, GdaServerProviderAsyncCallback async_cb, gpointer cb_data)
+gda_mdb_provider_prepare_connection (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaQuarkList *params, G_GNUC_UNUSED GdaQuarkList *auth)
{
gchar *filename = NULL, *tmp;
const gchar *dirname = NULL, *dbname = NULL;
@@ -232,11 +261,6 @@ gda_mdb_provider_open_connection (GdaServerProvider *provider, GdaConnection *cn
g_return_val_if_fail (GDA_IS_MDB_PROVIDER (mdb_prv), FALSE);
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
- if (async_cb) {
- gda_connection_add_event_string (cnc, _("Provider does not support asynchronous connection
open"));
- return FALSE;
- }
-
/* look for parameters */
dirname = gda_quark_list_find (params, "DB_DIR");
if (!dirname)
@@ -315,14 +339,6 @@ gda_mdb_provider_open_connection (GdaServerProvider *provider, GdaConnection *cn
return FALSE;
}
- /* open virtual connection */
- if (! GDA_SERVER_PROVIDER_CLASS (parent_class)->open_connection (GDA_SERVER_PROVIDER (provider),
cnc, params,
- NULL, NULL, NULL, NULL)) {
- gda_connection_add_event_string (cnc, _("Can't open virtual connection"));
- gda_mdb_free_cnc_data (cdata);
- return FALSE;
- }
-
mdb_read_catalog (cdata->mdb, MDB_ANY);
gda_virtual_connection_internal_set_provider_data (GDA_VIRTUAL_CONNECTION (cnc),
cdata, (GDestroyNotify) gda_mdb_free_cnc_data);
@@ -563,29 +579,13 @@ gda_mdb_provider_get_server_version (GdaServerProvider *provider,
}
/*
- * Get database request
- */
-static const gchar *
-gda_mdb_provider_get_database (GdaServerProvider *provider, GdaConnection *cnc)
-{
- MdbConnectionData *cdata;
-
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
-
- cdata = gda_virtual_connection_internal_get_provider_data (GDA_VIRTUAL_CONNECTION (cnc));
- if (!cdata)
- return NULL;
-
- return (const gchar *) cdata->mdb->f->filename;
-}
-
-/*
* Free connection's specific data
*/
static void
gda_mdb_free_cnc_data (MdbConnectionData *cdata)
{
+ if (cdata->mdb)
+ mdb_close (cdata->mdb);
g_free (cdata->server_version);
g_free (cdata);
}
diff --git a/providers/mysql/gda-mysql-blob-op.c b/providers/mysql/gda-mysql-blob-op.c
index 01901fb..224d212 100644
--- a/providers/mysql/gda-mysql-blob-op.c
+++ b/providers/mysql/gda-mysql-blob-op.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 - 2011 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2008 - 2014 Vivien Malerba <malerba gnome-db org>
* Copyright (C) 2011 Murray Cumming <murrayc murrayc com>
*
* This library is free software; you can redistribute it and/or
@@ -23,6 +23,7 @@
#include <libgda/libgda.h>
#include "gda-mysql.h"
#include "gda-mysql-blob-op.h"
+#include <libgda/gda-blob-op-impl.h>
#include <libgda/gda-debug-macros.h>
struct _GdaMysqlBlobOpPrivate {
@@ -92,9 +93,9 @@ gda_mysql_blob_op_class_init (GdaMysqlBlobOpClass *klass)
parent_class = g_type_class_peek_parent (klass);
object_class->finalize = gda_mysql_blob_op_finalize;
- blob_class->get_length = gda_mysql_blob_op_get_length;
- blob_class->read = gda_mysql_blob_op_read;
- blob_class->write = gda_mysql_blob_op_write;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->get_length = gda_mysql_blob_op_get_length;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->read = gda_mysql_blob_op_read;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->write = gda_mysql_blob_op_write;
}
static void
@@ -120,7 +121,7 @@ gda_mysql_blob_op_new (GdaConnection *cnc)
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- pgop = g_object_new (GDA_TYPE_MYSQL_BLOB_OP, NULL);
+ pgop = g_object_new (GDA_TYPE_MYSQL_BLOB_OP, "connection", cnc, NULL);
pgop->priv->cnc = cnc;
return GDA_BLOB_OP (pgop);
diff --git a/providers/mysql/gda-mysql-provider.c b/providers/mysql/gda-mysql-provider.c
index 4f8b856..6bf9c1d 100644
--- a/providers/mysql/gda-mysql-provider.c
+++ b/providers/mysql/gda-mysql-provider.c
@@ -91,10 +91,11 @@ enum
static gboolean gda_mysql_provider_open_connection (GdaServerProvider *provider,
GdaConnection *cnc,
GdaQuarkList *params,
- GdaQuarkList *auth,
- guint *task_id,
- GdaServerProviderAsyncCallback async_cb,
- gpointer cb_data);
+ GdaQuarkList *aut);
+static gboolean gda_mysql_provider_prepare_connection (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GdaQuarkList *params,
+ GdaQuarkList *aut);
static gboolean gda_mysql_provider_close_connection (GdaServerProvider *provider,
GdaConnection *cnc);
static const gchar *gda_mysql_provider_get_server_version (GdaServerProvider *provider,
@@ -120,9 +121,6 @@ static gchar *gda_mysql_provider_render_operation (GdaServerProvide
static gboolean gda_mysql_provider_perform_operation (GdaServerProvider *provider,
GdaConnection *cnc,
GdaServerOperation *op,
- guint *task_id,
- GdaServerProviderAsyncCallback async_cb,
- gpointer cb_data,
GError **error);
/* transactions */
static gboolean gda_mysql_provider_begin_transaction (GdaServerProvider *provider,
@@ -156,6 +154,8 @@ static gboolean gda_mysql_provider_supports_feature (GdaServerProvide
GdaConnection *cnc,
GdaConnectionFeature feature);
+static GdaWorker *gda_mysql_provider_create_worker (GdaServerProvider *provider);
+
static const gchar *gda_mysql_provider_get_name (GdaServerProvider *provider);
static GdaDataHandler *gda_mysql_provider_get_data_handler (GdaServerProvider *provider,
@@ -186,19 +186,16 @@ static GObject *gda_mysql_provider_statement_execute (GdaServerProvi
GdaSet *params,
GdaStatementModelUsage
model_usage,
GType *col_types,
- GdaSet
**last_inserted_row,
- guint *task_id,
- GdaServerProviderExecCallback async_cb,
- gpointer cb_data,
+ GdaSet
**last_inserted_row,
GError **error);
-static GdaSqlStatement *gda_mysql_statement_rewrite (GdaServerProvider *provider, GdaConnection
*cnc,
+static GdaSqlStatement *gda_mysql_provider_statement_rewrite (GdaServerProvider *provider, GdaConnection
*cnc,
GdaStatement *stmt, GdaSet *params, GError
**error);
/* Quoting */
-static gchar *gda_mysql_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
- const gchar *id,
- gboolean meta_store_convention, gboolean
force_quotes);
+static gchar *gda_mysql_provider_identifier_quote (GdaServerProvider *provider, GdaConnection
*cnc,
+ const gchar *id,
+ gboolean meta_store_convention, gboolean
force_quotes);
/* distributed transactions */
static gboolean gda_mysql_provider_xa_start (GdaServerProvider *provider,
@@ -254,6 +251,52 @@ gchar *internal_sql[] = {
/*
* GdaMysqlProvider class implementation
*/
+GdaServerProviderBase mysql_base_functions = {
+ gda_mysql_provider_get_name,
+ gda_mysql_provider_get_version,
+ gda_mysql_provider_get_server_version,
+ gda_mysql_provider_supports_feature,
+ gda_mysql_provider_create_worker,
+ NULL,
+ gda_mysql_provider_create_parser,
+ gda_mysql_provider_get_data_handler,
+ gda_mysql_provider_get_default_dbms_type,
+ gda_mysql_provider_supports_operation,
+ gda_mysql_provider_create_operation,
+ gda_mysql_provider_render_operation,
+ gda_mysql_provider_statement_to_sql,
+ gda_mysql_provider_identifier_quote,
+ gda_mysql_provider_statement_rewrite,
+ gda_mysql_provider_open_connection,
+ gda_mysql_provider_prepare_connection,
+ gda_mysql_provider_close_connection,
+ NULL,
+ NULL,
+ gda_mysql_provider_get_database,
+ gda_mysql_provider_perform_operation,
+ gda_mysql_provider_begin_transaction,
+ gda_mysql_provider_commit_transaction,
+ gda_mysql_provider_rollback_transaction,
+ gda_mysql_provider_add_savepoint,
+ gda_mysql_provider_rollback_savepoint,
+ gda_mysql_provider_delete_savepoint,
+ gda_mysql_provider_statement_prepare,
+ gda_mysql_provider_statement_execute,
+
+ NULL, NULL, NULL, NULL, /* padding */
+};
+
+GdaServerProviderXa mysql_xa_functions = {
+ gda_mysql_provider_xa_start,
+ gda_mysql_provider_xa_end,
+ gda_mysql_provider_xa_prepare,
+ gda_mysql_provider_xa_commit,
+ gda_mysql_provider_xa_rollback,
+ gda_mysql_provider_xa_recover,
+
+ NULL, NULL, NULL, NULL, /* padding */
+};
+
static void
gda_mysql_provider_class_init (GdaMysqlProviderClass *klass)
{
@@ -270,108 +313,19 @@ gda_mysql_provider_class_init (GdaMysqlProviderClass *klass)
g_param_spec_boolean ("identifiers-case-sensitive", NULL, NULL,
TRUE,
G_PARAM_READABLE | G_PARAM_WRITABLE));
+ /* set virtual functions */
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_BASE,
+ (gpointer) &mysql_base_functions);
+ GdaProviderReuseableOperations *ops;
+ ops = _gda_mysql_reuseable_get_ops ();
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_META,
+ (gpointer) &(ops->re_meta_funcs));
- /* virtual methods */
- provider_class->get_version = gda_mysql_provider_get_version;
- provider_class->get_server_version = gda_mysql_provider_get_server_version;
- provider_class->get_name = gda_mysql_provider_get_name;
- provider_class->supports_feature = gda_mysql_provider_supports_feature;
-
- provider_class->get_data_handler = gda_mysql_provider_get_data_handler;
- provider_class->get_def_dbms_type = gda_mysql_provider_get_default_dbms_type;
-
- provider_class->open_connection = gda_mysql_provider_open_connection;
- provider_class->close_connection = gda_mysql_provider_close_connection;
- provider_class->get_database = gda_mysql_provider_get_database;
-
- provider_class->supports_operation = gda_mysql_provider_supports_operation;
- provider_class->create_operation = gda_mysql_provider_create_operation;
- provider_class->render_operation = gda_mysql_provider_render_operation;
- provider_class->perform_operation = gda_mysql_provider_perform_operation;
-
- provider_class->begin_transaction = gda_mysql_provider_begin_transaction;
- provider_class->commit_transaction = gda_mysql_provider_commit_transaction;
- provider_class->rollback_transaction = gda_mysql_provider_rollback_transaction;
- provider_class->add_savepoint = gda_mysql_provider_add_savepoint;
- provider_class->rollback_savepoint = gda_mysql_provider_rollback_savepoint;
- provider_class->delete_savepoint = gda_mysql_provider_delete_savepoint;
-
- provider_class->create_parser = gda_mysql_provider_create_parser;
- provider_class->statement_to_sql = gda_mysql_provider_statement_to_sql;
- provider_class->statement_prepare = gda_mysql_provider_statement_prepare;
- provider_class->statement_execute = gda_mysql_provider_statement_execute;
- provider_class->statement_rewrite = gda_mysql_statement_rewrite;
-
- provider_class->is_busy = NULL;
- provider_class->cancel = NULL;
- provider_class->create_connection = NULL;
-
- provider_class->identifier_quote = gda_mysql_identifier_quote;
-
- memset (&(provider_class->meta_funcs), 0, sizeof (GdaServerProviderMeta));
- provider_class->meta_funcs._info = _gda_mysql_meta__info;
- provider_class->meta_funcs._btypes = _gda_mysql_meta__btypes;
- provider_class->meta_funcs._udt = _gda_mysql_meta__udt;
- provider_class->meta_funcs.udt = _gda_mysql_meta_udt;
- provider_class->meta_funcs._udt_cols = _gda_mysql_meta__udt_cols;
- provider_class->meta_funcs.udt_cols = _gda_mysql_meta_udt_cols;
- provider_class->meta_funcs._enums = _gda_mysql_meta__enums;
- provider_class->meta_funcs.enums = _gda_mysql_meta_enums;
- provider_class->meta_funcs._domains = _gda_mysql_meta__domains;
- provider_class->meta_funcs.domains = _gda_mysql_meta_domains;
- provider_class->meta_funcs._constraints_dom = _gda_mysql_meta__constraints_dom;
- provider_class->meta_funcs.constraints_dom = _gda_mysql_meta_constraints_dom;
- provider_class->meta_funcs._el_types = _gda_mysql_meta__el_types;
- provider_class->meta_funcs._collations = _gda_mysql_meta__collations;
- provider_class->meta_funcs.collations = _gda_mysql_meta_collations;
- provider_class->meta_funcs._character_sets = _gda_mysql_meta__character_sets;
- provider_class->meta_funcs.character_sets = _gda_mysql_meta_character_sets;
- provider_class->meta_funcs._schemata = _gda_mysql_meta__schemata;
- provider_class->meta_funcs.schemata = _gda_mysql_meta_schemata;
- provider_class->meta_funcs._tables_views = _gda_mysql_meta__tables_views;
- provider_class->meta_funcs.tables_views = _gda_mysql_meta_tables_views;
- provider_class->meta_funcs._columns = _gda_mysql_meta__columns;
- provider_class->meta_funcs.columns = _gda_mysql_meta_columns;
- provider_class->meta_funcs._view_cols = _gda_mysql_meta__view_cols;
- provider_class->meta_funcs.view_cols = _gda_mysql_meta_view_cols;
- provider_class->meta_funcs._constraints_tab = _gda_mysql_meta__constraints_tab;
- provider_class->meta_funcs.constraints_tab = _gda_mysql_meta_constraints_tab;
- provider_class->meta_funcs._constraints_ref = _gda_mysql_meta__constraints_ref;
- provider_class->meta_funcs.constraints_ref = _gda_mysql_meta_constraints_ref;
- provider_class->meta_funcs._key_columns = _gda_mysql_meta__key_columns;
- provider_class->meta_funcs.key_columns = _gda_mysql_meta_key_columns;
- provider_class->meta_funcs._check_columns = _gda_mysql_meta__check_columns;
- provider_class->meta_funcs.check_columns = _gda_mysql_meta_check_columns;
- provider_class->meta_funcs._triggers = _gda_mysql_meta__triggers;
- provider_class->meta_funcs.triggers = _gda_mysql_meta_triggers;
- provider_class->meta_funcs._routines = _gda_mysql_meta__routines;
- provider_class->meta_funcs.routines = _gda_mysql_meta_routines;
- provider_class->meta_funcs._routine_col = _gda_mysql_meta__routine_col;
- provider_class->meta_funcs.routine_col = _gda_mysql_meta_routine_col;
- provider_class->meta_funcs._routine_par = _gda_mysql_meta__routine_par;
- provider_class->meta_funcs.routine_par = _gda_mysql_meta_routine_par;
- provider_class->meta_funcs._indexes_tab = _gda_mysql_meta__indexes_tab;
- provider_class->meta_funcs.indexes_tab = _gda_mysql_meta_indexes_tab;
- provider_class->meta_funcs._index_cols = _gda_mysql_meta__index_cols;
- provider_class->meta_funcs.index_cols = _gda_mysql_meta_index_cols;
-
- /* distributed transactions: if not supported, then provider_class->xa_funcs should be set to NULL */
- provider_class->xa_funcs = g_new0 (GdaServerProviderXa, 1);
- provider_class->xa_funcs->xa_start = gda_mysql_provider_xa_start;
- provider_class->xa_funcs->xa_end = gda_mysql_provider_xa_end;
- provider_class->xa_funcs->xa_prepare = gda_mysql_provider_xa_prepare;
- provider_class->xa_funcs->xa_commit = gda_mysql_provider_xa_commit;
- provider_class->xa_funcs->xa_rollback = gda_mysql_provider_xa_rollback;
- provider_class->xa_funcs->xa_recover = gda_mysql_provider_xa_recover;
-
- if (!mysql_thread_safe ()) {
- gda_log_message ("MySQL was not compiled with the --enable-thread-safe-client flag, "
- "only one thread can access the provider");
- provider_class->limiting_thread = GDA_SERVER_PROVIDER_UNDEFINED_LIMITING_THREAD;
- }
- else
- provider_class->limiting_thread = NULL;
-
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_XA,
+ (gpointer) &mysql_xa_functions);
}
static void
@@ -461,6 +415,24 @@ gda_mysql_provider_get_property (GObject *object,
}
}
+static GdaWorker *
+gda_mysql_provider_create_worker (GdaServerProvider *provider)
+{
+ /* If PostgreSQL was not compiled with the --enable-thread-safe-client, then it's
+ * considered thread safe, and we limit the usage of the provider to one single thread */
+
+ static GdaWorker *unique_worker = NULL;
+ if (unique_worker)
+ return gda_worker_ref (unique_worker);
+
+ if (mysql_thread_safe ())
+ return gda_worker_new ();
+ else {
+ unique_worker = gda_worker_new ();
+ return gda_worker_ref (unique_worker);
+ }
+}
+
/*
* Get provider name request
*/
@@ -626,22 +598,12 @@ static gboolean
gda_mysql_provider_open_connection (GdaServerProvider *provider,
GdaConnection *cnc,
GdaQuarkList *params,
- GdaQuarkList *auth,
- G_GNUC_UNUSED guint *task_id,
- GdaServerProviderAsyncCallback async_cb,
- gpointer cb_data)
+ GdaQuarkList *auth)
{
g_return_val_if_fail (GDA_IS_MYSQL_PROVIDER (provider), FALSE);
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
- /* If asynchronous connection opening is not supported, then exit now */
- if (async_cb) {
- gda_connection_add_event_string (cnc, _("Provider does not support asynchronous connection
open"));
- return FALSE;
- }
-
/* Check for connection parameters */
- /* TO_ADD: your own connection parameters */
const gchar *db_name;
db_name = gda_quark_list_find (params, "DB_NAME");
if (!db_name) {
@@ -667,12 +629,7 @@ gda_mysql_provider_open_connection (GdaServerProvider *provider,
use_ssl = gda_quark_list_find (params, "USE_SSL");
compress = gda_quark_list_find (params, "COMPRESS");
proto = gda_quark_list_find (params, "PROTOCOL");
-
- /* open the real connection to the database */
- /* TO_ADD: C API specific function calls;
- * if it fails, add a connection event and return FALSE */
- // TO_IMPLEMENT;
-
+
GError *error = NULL;
MYSQL *mysql = real_open_connection (host, (port != NULL) ? atoi (port) : -1,
unix_socket, db_name,
@@ -708,14 +665,33 @@ gda_mysql_provider_open_connection (GdaServerProvider *provider,
* and set its contents */
MysqlConnectionData *cdata;
cdata = g_new0 (MysqlConnectionData, 1);
- gda_connection_internal_set_provider_data (cnc, cdata, (GDestroyNotify) gda_mysql_free_cnc_data);
+ gda_connection_internal_set_provider_data (cnc, (GdaServerProviderConnectionData*) cdata,
+ (GDestroyNotify) gda_mysql_free_cnc_data);
cdata->cnc = cnc;
cdata->mysql = mysql;
+ return TRUE;
+}
+
+static gboolean
+gda_mysql_provider_prepare_connection (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GdaQuarkList *params,
+ G_GNUC_UNUSED GdaQuarkList *aut)
+{
+ g_return_val_if_fail (GDA_IS_MYSQL_PROVIDER (provider), FALSE);
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+
+ MysqlConnectionData *cdata;
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata)
+ return FALSE;
+
/* handle the reuseable part */
GdaProviderReuseableOperations *ops;
ops = _gda_mysql_reuseable_get_ops ();
cdata->reuseable = (GdaMysqlReuseable*) ops->re_new_data ();
+ GError *error = NULL;
if (! _gda_mysql_compute_version (cnc, cdata->reuseable, &error)) {
GdaConnectionEvent *event_error = gda_connection_point_available_event (cnc,
GDA_CONNECTION_EVENT_ERROR);
gda_connection_event_set_sqlstate (event_error, _("Unknown"));
@@ -727,11 +703,8 @@ gda_mysql_provider_open_connection (GdaServerProvider *provider,
gda_connection_add_event (cnc, event_error);
g_clear_error (&error);
- gda_mysql_free_cnc_data (cdata);
- gda_connection_internal_set_provider_data (cnc, NULL, NULL);
return FALSE;
}
-
return TRUE;
}
@@ -754,7 +727,7 @@ gda_mysql_provider_close_connection (GdaServerProvider *provider,
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
/* Close the connection using the C API */
- cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return FALSE;
// TO_IMPLEMENT;
@@ -780,7 +753,7 @@ gda_mysql_provider_get_server_version (GdaServerProvider *provider,
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
- cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return FALSE;
if (! ((GdaProviderReuseable*)cdata->reuseable)->server_version)
@@ -802,7 +775,7 @@ gda_mysql_provider_get_database (GdaServerProvider *provider,
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
- cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
TO_IMPLEMENT;
@@ -991,20 +964,10 @@ static gboolean
gda_mysql_provider_perform_operation (GdaServerProvider *provider,
GdaConnection *cnc,
GdaServerOperation *op,
- G_GNUC_UNUSED guint *task_id,
- GdaServerProviderAsyncCallback async_cb,
- gpointer cb_data,
GError **error)
{
GdaServerOperationType optype;
- /* If asynchronous connection opening is not supported, then exit now */
- if (async_cb) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
- "%s", _("Provider does not support asynchronous server operation"));
- return FALSE;
- }
-
if (cnc) {
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
@@ -1286,8 +1249,6 @@ gda_mysql_provider_supports_feature (GdaServerProvider *provider,
switch (feature) {
case GDA_CONNECTION_FEATURE_SQL :
return TRUE;
- case GDA_CONNECTION_FEATURE_MULTI_THREADING:
- return mysql_thread_safe () ? TRUE : FALSE;
default:
return FALSE;
}
@@ -1985,7 +1946,7 @@ make_last_inserted_set (GdaConnection *cnc, GdaStatement *stmt, my_ulonglong las
gint rc;
gchar *sql;
MysqlConnectionData *cdata;
- cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
sql = g_strdup_printf ("DESCRIBE %s", insert->table->table_name);
@@ -2167,10 +2128,7 @@ gda_mysql_provider_statement_execute (GdaServerProvider *provider,
GdaSet *params,
GdaStatementModelUsage model_usage,
GType *col_types,
- GdaSet **last_inserted_row,
- guint *task_id,
- GdaServerProviderExecCallback async_cb,
- gpointer cb_data,
+ GdaSet **last_inserted_row,
GError **error)
{
GdaMysqlPStmt *ps;
@@ -2183,13 +2141,6 @@ gda_mysql_provider_statement_execute (GdaServerProvider *provider,
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
- /* If asynchronous connection opening is not supported, then exit now */
- if (async_cb) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
- "%s", _("Provider does not support asynchronous statement execution"));
- return FALSE;
- }
-
allow_noparam = (model_usage & GDA_STATEMENT_MODEL_ALLOW_NOPARAM) &&
(gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT);
@@ -2385,9 +2336,7 @@ gda_mysql_provider_statement_execute (GdaServerProvider *provider,
res = gda_mysql_provider_statement_execute (provider, cnc,
rstmt, params,
model_usage,
- col_types, last_inserted_row,
- task_id,
- async_cb, cb_data, error);
+ col_types, last_inserted_row, error);
g_object_unref (rstmt);
return res;
}
@@ -2437,9 +2386,7 @@ gda_mysql_provider_statement_execute (GdaServerProvider *provider,
rstmt, params,
model_usage,
col_types,
- last_inserted_row,
- task_id, async_cb,
- cb_data, error);
+ last_inserted_row, error);
/* clear original @param_ids and restore copied one */
g_slist_foreach (prep_param_ids, (GFunc) g_free, NULL);
g_slist_free (prep_param_ids);
@@ -2837,8 +2784,8 @@ gda_mysql_provider_statement_execute (GdaServerProvider *provider,
* Rewrites a statement in case some parameters in @params are set to DEFAULT, for INSERT or UPDATE
statements
*/
static GdaSqlStatement *
-gda_mysql_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
- GdaStatement *stmt, GdaSet *params, GError **error)
+gda_mysql_provider_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error)
{
if (cnc) {
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
@@ -3107,16 +3054,16 @@ my_remove_quotes (gchar *str)
}
static gchar *
-gda_mysql_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
- const gchar *id,
- gboolean for_meta_store, gboolean force_quotes)
+gda_mysql_provider_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
+ const gchar *id,
+ gboolean for_meta_store, gboolean force_quotes)
{
GdaSqlReservedKeywordsFunc kwfunc;
MysqlConnectionData *cdata = NULL;
gboolean case_sensitive = TRUE;
if (cnc) {
- cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (cdata)
case_sensitive = cdata->reuseable->identifiers_case_sensitive;
}
diff --git a/providers/mysql/gda-mysql-recordset.c b/providers/mysql/gda-mysql-recordset.c
index 8193877..299a31d 100644
--- a/providers/mysql/gda-mysql-recordset.c
+++ b/providers/mysql/gda-mysql-recordset.c
@@ -408,7 +408,7 @@ gda_mysql_recordset_new_direct (GdaConnection *cnc, GdaDataModelAccessFlags flag
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
@@ -546,7 +546,7 @@ gda_mysql_recordset_new (GdaConnection *cnc,
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (ps != NULL, NULL);
- cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
diff --git a/providers/mysql/gda-mysql.h b/providers/mysql/gda-mysql.h
index 63398ad..6d20011 100644
--- a/providers/mysql/gda-mysql.h
+++ b/providers/mysql/gda-mysql.h
@@ -32,6 +32,7 @@
#define MYSQL_PROVIDER_NAME "MySQL"
#include <libgda/libgda.h>
+#include <libgda/gda-connection-private.h>
#ifdef G_OS_WIN32
#include <winsock.h>
#endif
@@ -43,6 +44,7 @@
* Provider's specific connection data
*/
typedef struct {
+ GdaServerProviderConnectionData parent;
GdaMysqlReuseable *reuseable;
GdaConnection *cnc;
MYSQL *mysql;
diff --git a/providers/oracle/gda-oracle-blob-op.c b/providers/oracle/gda-oracle-blob-op.c
index 49f444f..daf328a 100644
--- a/providers/oracle/gda-oracle-blob-op.c
+++ b/providers/oracle/gda-oracle-blob-op.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 - 2011 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2007 - 2014 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 Lesser General Public
@@ -22,6 +22,7 @@
#include <libgda/libgda.h>
#include "gda-oracle.h"
#include "gda-oracle-blob-op.h"
+#include <libgda/gda-blob-op-impl.h>
#include <libgda/gda-debug-macros.h>
struct _GdaOracleBlobOpPrivate {
@@ -91,9 +92,9 @@ gda_oracle_blob_op_class_init (GdaOracleBlobOpClass *klass)
parent_class = g_type_class_peek_parent (klass);
object_class->finalize = gda_oracle_blob_op_finalize;
- blob_class->get_length = gda_oracle_blob_op_get_length;
- blob_class->read = gda_oracle_blob_op_read;
- blob_class->write = gda_oracle_blob_op_write;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->get_length = gda_oracle_blob_op_get_length;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->read = gda_oracle_blob_op_read;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->write = gda_oracle_blob_op_write;
}
static void
@@ -119,7 +120,7 @@ gda_oracle_blob_op_new (GdaConnection *cnc, OCILobLocator *lobloc)
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- bop = g_object_new (GDA_TYPE_ORACLE_BLOB_OP, NULL);
+ bop = g_object_new (GDA_TYPE_ORACLE_BLOB_OP, "connection", cnc, NULL);
bop->priv->cnc = cnc;
return GDA_BLOB_OP (bop);
diff --git a/providers/oracle/gda-oracle-provider.c b/providers/oracle/gda-oracle-provider.c
index fd5638e..69d3b92 100644
--- a/providers/oracle/gda-oracle-provider.c
+++ b/providers/oracle/gda-oracle-provider.c
@@ -36,6 +36,7 @@
#include <libgda/libgda.h>
#include <libgda/gda-data-model-private.h>
#include <libgda/gda-server-provider-extra.h>
+#include <libgda/gda-server-provider-impl.h>
#include <libgda/binreloc/gda-binreloc.h>
#include <libgda/gda-statement-extra.h>
#include <sql-parser/gda-sql-parser.h>
@@ -63,8 +64,9 @@ static GObjectClass *parent_class = NULL;
*/
/* connection management */
static gboolean gda_oracle_provider_open_connection (GdaServerProvider *provider, GdaConnection
*cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- guint *task_id,
GdaServerProviderAsyncCallback async_cb, gpointer cb_data);
+ GdaQuarkList *params, GdaQuarkList *auth);
+static gboolean gda_oracle_provider_prepare_connection (GdaServerProvider *provider,
GdaConnection *cnc,
+ GdaQuarkList *params, GdaQuarkList *auth);
static gboolean gda_oracle_provider_close_connection (GdaServerProvider *provider, GdaConnection
*cnc);
static const gchar *gda_oracle_provider_get_server_version (GdaServerProvider *provider,
GdaConnection *cnc);
static const gchar *gda_oracle_provider_get_database (GdaServerProvider *provider, GdaConnection
*cnc);
@@ -79,9 +81,7 @@ static gchar *gda_oracle_provider_render_operation (GdaServerProvid
GdaServerOperation *op, GError **error);
static gboolean gda_oracle_provider_perform_operation (GdaServerProvider *provider, GdaConnection
*cnc,
- GdaServerOperation *op, guint *task_id,
- GdaServerProviderAsyncCallback async_cb,
gpointer cb_data,
- GError **error);
+ GdaServerOperation *op, GError **error);
/* transactions */
static gboolean gda_oracle_provider_begin_transaction (GdaServerProvider *provider, GdaConnection
*cnc,
const gchar *name, GdaTransactionIsolation
level, GError **error);
@@ -101,6 +101,7 @@ static const gchar *gda_oracle_provider_get_version (GdaServerProvider *p
static gboolean gda_oracle_provider_supports_feature (GdaServerProvider *provider, GdaConnection
*cnc,
GdaConnectionFeature feature);
+static GdaWorker *gda_oracle_provider_create_worker (GdaServerProvider *provider);
static const gchar *gda_oracle_provider_get_name (GdaServerProvider *provider);
static GdaDataHandler *gda_oracle_provider_get_data_handler (GdaServerProvider *provider, GdaConnection
*cnc,
@@ -119,16 +120,14 @@ static gboolean gda_oracle_provider_statement_prepare (GdaServerProv
static GObject *gda_oracle_provider_statement_execute (GdaServerProvider *provider,
GdaConnection *cnc,
GdaStatement *stmt, GdaSet *params,
GdaStatementModelUsage model_usage,
- GType *col_types, GdaSet
**last_inserted_row,
- guint *task_id,
GdaServerProviderExecCallback async_cb,
- gpointer cb_data, GError **error);
-static GdaSqlStatement *gda_oracle_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
- GdaStatement *stmt, GdaSet *params, GError **error);
+ GType *col_types, GdaSet
**last_inserted_row, GError **error);
+static GdaSqlStatement *gda_oracle_provider_statement_rewrite (GdaServerProvider *provider,
GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError
**error);
/* Quoting */
-static gchar *gda_oracle_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
- const gchar *id,
- gboolean meta_store_convention, gboolean
force_quotes);
+static gchar *gda_oracle_provider_identifier_quote (GdaServerProvider *provider,
GdaConnection *cnc,
+ const gchar *id,
+ gboolean meta_store_convention, gboolean
force_quotes);
/* distributed transactions */
static gboolean gda_oracle_provider_xa_start (GdaServerProvider *provider, GdaConnection *cnc,
@@ -172,6 +171,103 @@ static gchar *internal_sql[] = {
/*
* GdaOracleProvider class implementation
*/
+GdaServerProviderBase oracle_base_functions = {
+ gda_oracle_provider_get_name,
+ gda_oracle_provider_get_version,
+ gda_oracle_provider_get_server_version,
+ gda_oracle_provider_supports_feature,
+ gda_oracle_provider_create_worker,
+ NULL,
+ gda_oracle_provider_create_parser,
+ gda_oracle_provider_get_data_handler,
+ gda_oracle_provider_get_default_dbms_type,
+ gda_oracle_provider_supports_operation,
+ gda_oracle_provider_create_operation,
+ gda_oracle_provider_render_operation,
+ gda_oracle_provider_statement_to_sql,
+ gda_oracle_provider_identifier_quote,
+ gda_oracle_provider_statement_rewrite,
+ gda_oracle_provider_open_connection,
+ gda_oracle_provider_prepare_connection,
+ gda_oracle_provider_close_connection,
+ NULL,
+ NULL,
+ gda_oracle_provider_get_database,
+ gda_oracle_provider_perform_operation,
+ gda_oracle_provider_begin_transaction,
+ gda_oracle_provider_commit_transaction,
+ gda_oracle_provider_rollback_transaction,
+ gda_oracle_provider_add_savepoint,
+ gda_oracle_provider_rollback_savepoint,
+ gda_oracle_provider_delete_savepoint,
+ gda_oracle_provider_statement_prepare,
+ gda_oracle_provider_statement_execute,
+
+ NULL, NULL, NULL, NULL, /* padding */
+};
+
+GdaServerProviderMeta oracle_meta_functions = {
+ _gda_oracle_meta__info,
+ _gda_oracle_meta__btypes,
+ _gda_oracle_meta__udt,
+ _gda_oracle_meta_udt,
+ _gda_oracle_meta__udt_cols,
+ _gda_oracle_meta_udt_cols,
+ _gda_oracle_meta__enums,
+ _gda_oracle_meta_enums,
+ _gda_oracle_meta__domains,
+ _gda_oracle_meta_domains,
+ _gda_oracle_meta__constraints_dom,
+ _gda_oracle_meta_constraints_dom,
+ _gda_oracle_meta__el_types,
+ _gda_oracle_meta_el_types,
+ _gda_oracle_meta__collations,
+ _gda_oracle_meta_collations,
+ _gda_oracle_meta__character_sets,
+ _gda_oracle_meta_character_sets,
+ _gda_oracle_meta__schemata,
+ _gda_oracle_meta_schemata,
+ _gda_oracle_meta__tables_views,
+ _gda_oracle_meta_tables_views,
+ _gda_oracle_meta__columns,
+ _gda_oracle_meta_columns,
+ _gda_oracle_meta__view_cols,
+ _gda_oracle_meta_view_cols,
+ _gda_oracle_meta__constraints_tab,
+ _gda_oracle_meta_constraints_tab,
+ _gda_oracle_meta__constraints_ref,
+ _gda_oracle_meta_constraints_ref,
+ _gda_oracle_meta__key_columns,
+ _gda_oracle_meta_key_columns,
+ _gda_oracle_meta__check_columns,
+ _gda_oracle_meta_check_columns,
+ _gda_oracle_meta__triggers,
+ _gda_oracle_meta_triggers,
+ _gda_oracle_meta__routines,
+ _gda_oracle_meta_routines,
+ _gda_oracle_meta__routine_col,
+ _gda_oracle_meta_routine_col,
+ _gda_oracle_meta__routine_par,
+ _gda_oracle_meta_routine_par,
+ _gda_oracle_meta__indexes_tab,
+ _gda_oracle_meta_indexes_tab,
+ _gda_oracle_meta__index_cols,
+ _gda_oracle_meta_index_cols,
+
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* padding */
+};
+
+GdaServerProviderXa oracle_xa_functions = {
+ gda_oracle_provider_xa_start,
+ gda_oracle_provider_xa_end,
+ gda_oracle_provider_xa_prepare,
+ gda_oracle_provider_xa_commit,
+ gda_oracle_provider_xa_rollback,
+ gda_oracle_provider_xa_recover,
+
+ NULL, NULL, NULL, NULL, /* padding */
+};
+
static void
gda_oracle_provider_class_init (GdaOracleProviderClass *klass)
{
@@ -179,100 +275,16 @@ gda_oracle_provider_class_init (GdaOracleProviderClass *klass)
parent_class = g_type_class_peek_parent (klass);
- provider_class->get_version = gda_oracle_provider_get_version;
- provider_class->get_server_version = gda_oracle_provider_get_server_version;
- provider_class->get_name = gda_oracle_provider_get_name;
- provider_class->supports_feature = gda_oracle_provider_supports_feature;
-
- provider_class->get_data_handler = gda_oracle_provider_get_data_handler;
- provider_class->get_def_dbms_type = gda_oracle_provider_get_default_dbms_type;
-
- provider_class->open_connection = gda_oracle_provider_open_connection;
- provider_class->close_connection = gda_oracle_provider_close_connection;
- provider_class->get_database = gda_oracle_provider_get_database;
-
- provider_class->supports_operation = gda_oracle_provider_supports_operation;
- provider_class->create_operation = gda_oracle_provider_create_operation;
- provider_class->render_operation = gda_oracle_provider_render_operation;
- provider_class->perform_operation = gda_oracle_provider_perform_operation;
-
- provider_class->begin_transaction = gda_oracle_provider_begin_transaction;
- provider_class->commit_transaction = gda_oracle_provider_commit_transaction;
- provider_class->rollback_transaction = gda_oracle_provider_rollback_transaction;
- provider_class->add_savepoint = gda_oracle_provider_add_savepoint;
- provider_class->rollback_savepoint = gda_oracle_provider_rollback_savepoint;
- provider_class->delete_savepoint = gda_oracle_provider_delete_savepoint;
-
- provider_class->create_parser = gda_oracle_provider_create_parser;
- provider_class->statement_to_sql = gda_oracle_provider_statement_to_sql;
- provider_class->statement_prepare = gda_oracle_provider_statement_prepare;
- provider_class->statement_execute = gda_oracle_provider_statement_execute;
- provider_class->statement_rewrite = gda_oracle_statement_rewrite;
-
- provider_class->is_busy = NULL;
- provider_class->cancel = NULL;
- provider_class->create_connection = NULL;
- provider_class->identifier_quote = gda_oracle_identifier_quote;
-
- memset (&(provider_class->meta_funcs), 0, sizeof (GdaServerProviderMeta));
- provider_class->meta_funcs._info = _gda_oracle_meta__info;
- provider_class->meta_funcs._btypes = _gda_oracle_meta__btypes;
- provider_class->meta_funcs._udt = _gda_oracle_meta__udt;
- provider_class->meta_funcs.udt = _gda_oracle_meta_udt;
- provider_class->meta_funcs._udt_cols = _gda_oracle_meta__udt_cols;
- provider_class->meta_funcs.udt_cols = _gda_oracle_meta_udt_cols;
- provider_class->meta_funcs._enums = _gda_oracle_meta__enums;
- provider_class->meta_funcs.enums = _gda_oracle_meta_enums;
- provider_class->meta_funcs._domains = _gda_oracle_meta__domains;
- provider_class->meta_funcs.domains = _gda_oracle_meta_domains;
- provider_class->meta_funcs._constraints_dom = _gda_oracle_meta__constraints_dom;
- provider_class->meta_funcs.constraints_dom = _gda_oracle_meta_constraints_dom;
- provider_class->meta_funcs._el_types = _gda_oracle_meta__el_types;
- provider_class->meta_funcs.el_types = _gda_oracle_meta_el_types;
- provider_class->meta_funcs._collations = _gda_oracle_meta__collations;
- provider_class->meta_funcs.collations = _gda_oracle_meta_collations;
- provider_class->meta_funcs._character_sets = _gda_oracle_meta__character_sets;
- provider_class->meta_funcs.character_sets = _gda_oracle_meta_character_sets;
- provider_class->meta_funcs._schemata = _gda_oracle_meta__schemata;
- provider_class->meta_funcs.schemata = _gda_oracle_meta_schemata;
- provider_class->meta_funcs._tables_views = _gda_oracle_meta__tables_views;
- provider_class->meta_funcs.tables_views = _gda_oracle_meta_tables_views;
- provider_class->meta_funcs._columns = _gda_oracle_meta__columns;
- provider_class->meta_funcs.columns = _gda_oracle_meta_columns;
- provider_class->meta_funcs._view_cols = _gda_oracle_meta__view_cols;
- provider_class->meta_funcs.view_cols = _gda_oracle_meta_view_cols;
- provider_class->meta_funcs._constraints_tab = _gda_oracle_meta__constraints_tab;
- provider_class->meta_funcs.constraints_tab = _gda_oracle_meta_constraints_tab;
- provider_class->meta_funcs._constraints_ref = _gda_oracle_meta__constraints_ref;
- provider_class->meta_funcs.constraints_ref = _gda_oracle_meta_constraints_ref;
- provider_class->meta_funcs._key_columns = _gda_oracle_meta__key_columns;
- provider_class->meta_funcs.key_columns = _gda_oracle_meta_key_columns;
- provider_class->meta_funcs._check_columns = _gda_oracle_meta__check_columns;
- provider_class->meta_funcs.check_columns = _gda_oracle_meta_check_columns;
- provider_class->meta_funcs._triggers = _gda_oracle_meta__triggers;
- provider_class->meta_funcs.triggers = _gda_oracle_meta_triggers;
- provider_class->meta_funcs._routines = _gda_oracle_meta__routines;
- provider_class->meta_funcs.routines = _gda_oracle_meta_routines;
- provider_class->meta_funcs._routine_col = _gda_oracle_meta__routine_col;
- provider_class->meta_funcs.routine_col = _gda_oracle_meta_routine_col;
- provider_class->meta_funcs._routine_par = _gda_oracle_meta__routine_par;
- provider_class->meta_funcs.routine_par = _gda_oracle_meta_routine_par;
- provider_class->meta_funcs._indexes_tab = _gda_oracle_meta__indexes_tab;
- provider_class->meta_funcs.indexes_tab = _gda_oracle_meta_indexes_tab;
- provider_class->meta_funcs._index_cols = _gda_oracle_meta__index_cols;
- provider_class->meta_funcs.index_cols = _gda_oracle_meta_index_cols;
-
- /* distributed transactions: if not supported, then provider_class->xa_funcs should be set to NULL */
- provider_class->xa_funcs = g_new0 (GdaServerProviderXa, 1);
- provider_class->xa_funcs->xa_start = gda_oracle_provider_xa_start;
- provider_class->xa_funcs->xa_end = gda_oracle_provider_xa_end;
- provider_class->xa_funcs->xa_prepare = gda_oracle_provider_xa_prepare;
- provider_class->xa_funcs->xa_commit = gda_oracle_provider_xa_commit;
- provider_class->xa_funcs->xa_rollback = gda_oracle_provider_xa_rollback;
- provider_class->xa_funcs->xa_recover = gda_oracle_provider_xa_recover;
-
- /* thread safe */
- provider_class->limiting_thread = NULL;
+ /* set virtual functions */
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_BASE,
+ (gpointer) &oracle_base_functions);
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_META,
+ (gpointer) &(oracle_meta_functions));
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_XA,
+ (gpointer) &oracle_xa_functions);
/* static types */
static_types = g_new (GType, GDA_STYPE_NULL + 1);
@@ -350,6 +362,18 @@ gda_oracle_provider_get_type (void)
return type;
}
+static GdaWorker *
+gda_oracle_provider_create_worker (GdaServerProvider *provider)
+{
+ /* See http://docs.oracle.com/cd/B10501_01/appdev.920/a96584/oci09adv.htm */
+ static GdaWorker *unique_worker = NULL;
+ if (unique_worker)
+ return gda_worker_ref (unique_worker);
+ else {
+ unique_worker = gda_worker_new ();
+ return gda_worker_ref (unique_worker);
+ }
+}
/*
* Get provider name request
@@ -379,7 +403,7 @@ execute_raw_command (GdaConnection *cnc, const gchar *sql)
OCIStmt *hstmt = NULL;
int result;
- cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return FALSE;
@@ -452,20 +476,12 @@ execute_raw_command (GdaConnection *cnc, const gchar *sql)
*/
static gboolean
gda_oracle_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- G_GNUC_UNUSED guint *task_id, GdaServerProviderAsyncCallback async_cb,
- G_GNUC_UNUSED gpointer cb_data)
+ GdaQuarkList *params, GdaQuarkList *auth)
{
OracleConnectionData *cdata;
g_return_val_if_fail (GDA_IS_ORACLE_PROVIDER (provider), FALSE);
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
- /* If asynchronous connection opening is not supported, then exit now */
- if (async_cb) {
- gda_connection_add_event_string (cnc, _("Provider does not support asynchronous connection
open"));
- return FALSE;
- }
-
/* Check for connection parameters */
const gchar *tnsname, *username, *password, *schema;
gchar *easy = NULL;
@@ -692,13 +708,30 @@ gda_oracle_provider_open_connection (GdaServerProvider *provider, GdaConnection
else
cdata->schema = g_ascii_strup (username, -1);
- gda_connection_internal_set_provider_data (cnc, cdata, (GDestroyNotify) gda_oracle_free_cnc_data);
+ gda_connection_internal_set_provider_data (cnc, (GdaServerProviderConnectionData*) cdata,
+ (GDestroyNotify) gda_oracle_free_cnc_data);
+ return TRUE;
+}
+static gboolean
+gda_oracle_provider_prepare_connection (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaQuarkList *params, G_GNUC_UNUSED GdaQuarkList *auth)
+{
+ OracleConnectionData *cdata;
+ cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata)
+ return FALSE;
+
+ const gchar *schema;
+ schema = gda_quark_list_find (params, "SCHEMA");
+
/* get version */
gchar version [512];
cdata->version = NULL;
cdata->major_version = 8;
cdata->minor_version = 0;
+
+ gint result;
result = OCIServerVersion (cdata->hservice, cdata->herr, (text*) version, 511, OCI_HTYPE_SVCCTX);
if ((result == OCI_SUCCESS) || (result = OCI_SUCCESS_WITH_INFO)) {
cdata->version = g_strdup (version);
@@ -726,11 +759,8 @@ gda_oracle_provider_open_connection (GdaServerProvider *provider, GdaConnection
/* Optionnally set some attributes for the newly opened connection (encoding to UTF-8 for example )*/
if (! execute_raw_command (cnc, "ALTER SESSION SET NLS_DATE_FORMAT = 'MM/DD/YYYY'") ||
! execute_raw_command (cnc, "ALTER SESSION SET NLS_NUMERIC_CHARACTERS = \". \"") ||
- (schema && ! execute_raw_command (cnc, g_strdup_printf ("ALTER SESSION SET CURRENT_SCHEMA =
\"%s\"", schema)))) {
- gda_connection_internal_set_provider_data (cnc, NULL, NULL);
- gda_oracle_free_cnc_data (cdata);
+ (schema && ! execute_raw_command (cnc, g_strdup_printf ("ALTER SESSION SET CURRENT_SCHEMA =
\"%s\"", schema))))
return FALSE;
- }
return TRUE;
}
@@ -754,7 +784,7 @@ gda_oracle_provider_close_connection (GdaServerProvider *provider, GdaConnection
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
/* Close the connection using the C API */
- cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return FALSE;
@@ -789,7 +819,7 @@ gda_oracle_provider_get_server_version (GdaServerProvider *provider, GdaConnecti
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
- cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
@@ -809,7 +839,7 @@ gda_oracle_provider_get_database (GdaServerProvider *provider, GdaConnection *cn
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
- cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
TO_IMPLEMENT;
@@ -968,19 +998,10 @@ gda_oracle_provider_render_operation (GdaServerProvider *provider, GdaConnection
*/
static gboolean
gda_oracle_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
- GdaServerOperation *op, G_GNUC_UNUSED guint *task_id,
- GdaServerProviderAsyncCallback async_cb, G_GNUC_UNUSED gpointer
cb_data,
- GError **error)
+ GdaServerOperation *op, GError **error)
{
GdaServerOperationType optype;
- /* If asynchronous connection opening is not supported, then exit now */
- if (async_cb) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
- "%s", _("Provider does not support asynchronous server operation"));
- return FALSE;
- }
-
if (cnc) {
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
@@ -1808,9 +1829,7 @@ static GObject *
gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
GdaStatement *stmt, GdaSet *params,
GdaStatementModelUsage model_usage,
- GType *col_types, GdaSet **last_inserted_row,
- guint *task_id,
- GdaServerProviderExecCallback async_cb, gpointer cb_data, GError
**error)
+ GType *col_types, GdaSet **last_inserted_row, GError **error)
{
GdaOraclePStmt *ps;
OracleConnectionData *cdata;
@@ -1822,13 +1841,6 @@ gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
- /* If asynchronous connection opening is not supported, then exit now */
- if (async_cb) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
- "%s", _("Provider does not support asynchronous statement execution"));
- return NULL;
- }
-
allow_noparam = (model_usage & GDA_STATEMENT_MODEL_ALLOW_NOPARAM) &&
(gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT);
@@ -1964,9 +1976,7 @@ gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
res = gda_oracle_provider_statement_execute (provider, cnc,
rstmt, params,
model_usage,
- col_types, last_inserted_row,
- task_id,
- async_cb, cb_data, error);
+ col_types, last_inserted_row, error);
g_object_unref (rstmt);
return res;
}
@@ -2037,9 +2047,7 @@ gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
rstmt, params,
model_usage,
col_types,
- last_inserted_row,
- task_id, async_cb,
- cb_data, error);
+ last_inserted_row, error);
/* clear original @param_ids and restore copied one */
g_slist_foreach (prep_param_ids, (GFunc) g_free, NULL);
g_slist_free (prep_param_ids);
@@ -2298,8 +2306,8 @@ gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
* Uses the DEFAULT keyword
*/
static GdaSqlStatement *
-gda_oracle_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
- GdaStatement *stmt, GdaSet *params, GError **error)
+gda_oracle_provider_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error)
{
if (cnc) {
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
@@ -2557,15 +2565,15 @@ ora_remove_quotes (gchar *str)
}
static gchar *
-gda_oracle_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
- const gchar *id,
- gboolean for_meta_store, gboolean force_quotes)
+gda_oracle_provider_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
+ const gchar *id,
+ gboolean for_meta_store, gboolean force_quotes)
{
GdaSqlReservedKeywordsFunc kwfunc;
OracleConnectionData *cdata = NULL;
if (cnc)
- cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
kwfunc = _gda_oracle_get_reserved_keyword_func (cdata);
diff --git a/providers/oracle/gda-oracle-recordset.c b/providers/oracle/gda-oracle-recordset.c
index c7d9634..b1b2eee 100644
--- a/providers/oracle/gda-oracle-recordset.c
+++ b/providers/oracle/gda-oracle-recordset.c
@@ -196,7 +196,7 @@ gda_oracle_recordset_new (GdaConnection *cnc, GdaOraclePStmt *ps, GdaSet *exec_p
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (ps != NULL, NULL);
- cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
diff --git a/providers/oracle/gda-oracle-util.c b/providers/oracle/gda-oracle-util.c
index cadec39..ee32cc3 100644
--- a/providers/oracle/gda-oracle-util.c
+++ b/providers/oracle/gda-oracle-util.c
@@ -621,7 +621,7 @@ _gda_oracle_set_value (GValue *value,
gint result;
/* REM: we need to make a "copy" of the lob locator to give to the GdaOracleblobOp object */
- cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata) {
gda_connection_add_event_string (cnc, _("Invalid Oracle handle"));
gda_value_set_null (value);
diff --git a/providers/oracle/gda-oracle.h b/providers/oracle/gda-oracle.h
index 3132591..cc96b16 100644
--- a/providers/oracle/gda-oracle.h
+++ b/providers/oracle/gda-oracle.h
@@ -31,12 +31,14 @@
/* headers necessary for the C or C++ API */
#include <libgda/libgda.h>
+#include <libgda/gda-connection-private.h>
#include <oci.h>
/*
* Provider's specific connection data
*/
typedef struct {
+ GdaServerProviderConnectionData parent;
OCIEnv *henv;
OCIError *herr;
OCIServer *hserver;
diff --git a/providers/postgres/gda-postgres-blob-op.c b/providers/postgres/gda-postgres-blob-op.c
index 951c66d..ef2c070 100644
--- a/providers/postgres/gda-postgres-blob-op.c
+++ b/providers/postgres/gda-postgres-blob-op.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Armin Burgmeier <armin openismus com>
- * Copyright (C) 2007 - 2011 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2007 - 2014 Vivien Malerba <malerba gnome-db org>
* Copyright (C) 2009 Bas Driessen <bas driessen xobas com>
* Copyright (C) 2010 David King <davidk openismus com>
* Copyright (C) 2011 Murray Cumming <murrayc murrayc com>
@@ -25,6 +25,7 @@
#include <string.h>
#include "gda-postgres.h"
#include "gda-postgres-blob-op.h"
+#include <libgda/gda-blob-op-impl.h>
#include "gda-postgres-util.h"
struct _GdaPostgresBlobOpPrivate {
@@ -94,9 +95,9 @@ gda_postgres_blob_op_class_init (GdaPostgresBlobOpClass *klass)
parent_class = g_type_class_peek_parent (klass);
object_class->finalize = gda_postgres_blob_op_finalize;
- blob_class->get_length = gda_postgres_blob_op_get_length;
- blob_class->read = gda_postgres_blob_op_read;
- blob_class->write = gda_postgres_blob_op_write;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->get_length = gda_postgres_blob_op_get_length;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->read = gda_postgres_blob_op_read;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->write = gda_postgres_blob_op_write;
}
static PGconn *
@@ -104,7 +105,7 @@ get_pconn (GdaConnection *cnc)
{
PostgresConnectionData *cdata;
- cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
@@ -169,7 +170,7 @@ gda_postgres_blob_op_new (GdaConnection *cnc)
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- pgop = g_object_new (GDA_TYPE_POSTGRES_BLOB_OP, NULL);
+ pgop = g_object_new (GDA_TYPE_POSTGRES_BLOB_OP, "connection", cnc, NULL);
pgop->priv->cnc = cnc;
return GDA_BLOB_OP (pgop);
@@ -182,7 +183,7 @@ gda_postgres_blob_op_new_with_id (GdaConnection *cnc, const gchar *sql_id)
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- pgop = g_object_new (GDA_TYPE_POSTGRES_BLOB_OP, NULL);
+ pgop = g_object_new (GDA_TYPE_POSTGRES_BLOB_OP, "connection", cnc, NULL);
pgop->priv->blobid = atoi (sql_id);
pgop->priv->cnc = cnc;
diff --git a/providers/postgres/gda-postgres-handler-bin.c b/providers/postgres/gda-postgres-handler-bin.c
index f3255b1..c246466 100644
--- a/providers/postgres/gda-postgres-handler-bin.c
+++ b/providers/postgres/gda-postgres-handler-bin.c
@@ -182,7 +182,7 @@ gda_postgres_handler_bin_get_sql_from_value (GdaDataHandler *iface, const GValue
if (hdl->priv->cnc) {
g_return_val_if_fail (GDA_IS_CONNECTION (hdl->priv->cnc), NULL);
- cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (hdl->priv->cnc);
+ cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data_error
(hdl->priv->cnc, NULL);
}
GdaBinary *data = (GdaBinary *) gda_value_get_binary ((GValue *) value);
diff --git a/providers/postgres/gda-postgres-provider.c b/providers/postgres/gda-postgres-provider.c
index 69b26fe..cfa1653 100644
--- a/providers/postgres/gda-postgres-provider.c
+++ b/providers/postgres/gda-postgres-provider.c
@@ -69,8 +69,9 @@ static GObjectClass *parent_class = NULL;
*/
/* connection management */
static gboolean gda_postgres_provider_open_connection (GdaServerProvider *provider, GdaConnection
*cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- guint *task_id,
GdaServerProviderAsyncCallback async_cb, gpointer cb_data);
+ GdaQuarkList *params, GdaQuarkList *auth);
+static gboolean gda_postgres_provider_prepare_connection (GdaServerProvider *provider,
GdaConnection *cnc,
+ GdaQuarkList *params, GdaQuarkList
*auth);
static gboolean gda_postgres_provider_close_connection (GdaServerProvider *provider,
GdaConnection *cnc);
static const gchar *gda_postgres_provider_get_server_version (GdaServerProvider *provider,
GdaConnection *cnc);
static const gchar *gda_postgres_provider_get_database (GdaServerProvider *provider, GdaConnection
*cnc);
@@ -85,9 +86,7 @@ static gchar *gda_postgres_provider_render_operation (GdaServerProv
GdaServerOperation *op, GError **error);
static gboolean gda_postgres_provider_perform_operation (GdaServerProvider *provider,
GdaConnection *cnc,
- GdaServerOperation *op, guint *task_id,
- GdaServerProviderAsyncCallback async_cb,
gpointer cb_data,
- GError **error);
+ GdaServerOperation *op, GError **error);
/* transactions */
static gboolean gda_postgres_provider_begin_transaction (GdaServerProvider *provider,
GdaConnection *cnc,
const gchar *name,
GdaTransactionIsolation level, GError **error);
@@ -107,6 +106,7 @@ static const gchar *gda_postgres_provider_get_version (GdaServerProvider
static gboolean gda_postgres_provider_supports_feature (GdaServerProvider *provider,
GdaConnection *cnc,
GdaConnectionFeature feature);
+static GdaWorker *gda_postgres_provider_create_worker (GdaServerProvider *provider);
static const gchar *gda_postgres_provider_get_name (GdaServerProvider *provider);
static GdaDataHandler *gda_postgres_provider_get_data_handler (GdaServerProvider *provider,
GdaConnection *cnc,
@@ -125,17 +125,19 @@ static gboolean gda_postgres_provider_statement_prepare (GdaServerPr
static GObject *gda_postgres_provider_statement_execute (GdaServerProvider *provider,
GdaConnection *cnc,
GdaStatement *stmt, GdaSet *params,
GdaStatementModelUsage model_usage,
- GType *col_types, GdaSet
**last_inserted_row,
- guint *task_id,
GdaServerProviderExecCallback async_cb,
- gpointer cb_data, GError **error);
+ GType *col_types, GdaSet
**last_inserted_row, GError **error);
/* Quoting */
-static gchar *gda_postgresql_identifier_quote (GdaServerProvider *provider, GdaConnection
*cnc,
- const gchar *id,
- gboolean meta_store_convention, gboolean
force_quotes);
+static gchar *gda_postgres_provider_identifier_quote (GdaServerProvider *provider,
GdaConnection *cnc,
+ const gchar *id,
+ gboolean meta_store_convention,
gboolean force_quotes);
-static GdaSqlStatement *gda_postgresql_statement_rewrite (GdaServerProvider *provider, GdaConnection
*cnc,
- GdaStatement *stmt, GdaSet *params, GError
**error);
+static GdaSqlStatement *gda_postgres_provider_statement_rewrite (GdaServerProvider *provider,
GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params,
GError **error);
+
+/* string escaping */
+static gchar *gda_postgres_provider_escape_string (GdaServerProvider *provider, GdaConnection
*cnc,
+ const gchar *string);
/* distributed transactions */
static gboolean gda_postgres_provider_xa_start (GdaServerProvider *provider, GdaConnection *cnc,
@@ -191,6 +193,52 @@ static gchar *internal_sql[] = {
/*
* GdaPostgresProvider class implementation
*/
+GdaServerProviderBase postgres_base_functions = {
+ gda_postgres_provider_get_name,
+ gda_postgres_provider_get_version,
+ gda_postgres_provider_get_server_version,
+ gda_postgres_provider_supports_feature,
+ gda_postgres_provider_create_worker,
+ NULL,
+ gda_postgres_provider_create_parser,
+ gda_postgres_provider_get_data_handler,
+ gda_postgres_provider_get_default_dbms_type,
+ gda_postgres_provider_supports_operation,
+ gda_postgres_provider_create_operation,
+ gda_postgres_provider_render_operation,
+ gda_postgres_provider_statement_to_sql,
+ gda_postgres_provider_identifier_quote,
+ gda_postgres_provider_statement_rewrite,
+ gda_postgres_provider_open_connection,
+ gda_postgres_provider_prepare_connection,
+ gda_postgres_provider_close_connection,
+ gda_postgres_provider_escape_string,
+ NULL,
+ gda_postgres_provider_get_database,
+ gda_postgres_provider_perform_operation,
+ gda_postgres_provider_begin_transaction,
+ gda_postgres_provider_commit_transaction,
+ gda_postgres_provider_rollback_transaction,
+ gda_postgres_provider_add_savepoint,
+ gda_postgres_provider_rollback_savepoint,
+ gda_postgres_provider_delete_savepoint,
+ gda_postgres_provider_statement_prepare,
+ gda_postgres_provider_statement_execute,
+
+ NULL, NULL, NULL, NULL, /* padding */
+};
+
+GdaServerProviderXa postgres_xa_functions = {
+ gda_postgres_provider_xa_start,
+ gda_postgres_provider_xa_end,
+ gda_postgres_provider_xa_prepare,
+ gda_postgres_provider_xa_commit,
+ gda_postgres_provider_xa_rollback,
+ gda_postgres_provider_xa_recover,
+
+ NULL, NULL, NULL, NULL, /* padding */
+};
+
static void
gda_postgres_provider_class_init (GdaPostgresProviderClass *klass)
{
@@ -198,105 +246,19 @@ gda_postgres_provider_class_init (GdaPostgresProviderClass *klass)
parent_class = g_type_class_peek_parent (klass);
- provider_class->get_version = gda_postgres_provider_get_version;
- provider_class->get_server_version = gda_postgres_provider_get_server_version;
- provider_class->get_name = gda_postgres_provider_get_name;
- provider_class->supports_feature = gda_postgres_provider_supports_feature;
-
- provider_class->get_data_handler = gda_postgres_provider_get_data_handler;
- provider_class->get_def_dbms_type = gda_postgres_provider_get_default_dbms_type;
-
- provider_class->create_connection = NULL;
- provider_class->identifier_quote = gda_postgresql_identifier_quote;
- provider_class->open_connection = gda_postgres_provider_open_connection;
- provider_class->close_connection = gda_postgres_provider_close_connection;
- provider_class->get_database = gda_postgres_provider_get_database;
-
- provider_class->supports_operation = gda_postgres_provider_supports_operation;
- provider_class->create_operation = gda_postgres_provider_create_operation;
- provider_class->render_operation = gda_postgres_provider_render_operation;
- provider_class->perform_operation = gda_postgres_provider_perform_operation;
-
- provider_class->begin_transaction = gda_postgres_provider_begin_transaction;
- provider_class->commit_transaction = gda_postgres_provider_commit_transaction;
- provider_class->rollback_transaction = gda_postgres_provider_rollback_transaction;
- provider_class->add_savepoint = gda_postgres_provider_add_savepoint;
- provider_class->rollback_savepoint = gda_postgres_provider_rollback_savepoint;
- provider_class->delete_savepoint = gda_postgres_provider_delete_savepoint;
-
- provider_class->create_parser = gda_postgres_provider_create_parser;
- provider_class->statement_to_sql = NULL; /* don't use gda_postgres_provider_statement_to_sql()
- * because it only calls gda_statement_to_sql_extended() */
- provider_class->statement_prepare = gda_postgres_provider_statement_prepare;
- provider_class->statement_execute = gda_postgres_provider_statement_execute;
-
- provider_class->statement_rewrite = gda_postgresql_statement_rewrite;
-
- memset (&(provider_class->meta_funcs), 0, sizeof (GdaServerProviderMeta));
- provider_class->meta_funcs._info = _gda_postgres_meta__info;
- provider_class->meta_funcs._btypes = _gda_postgres_meta__btypes;
- provider_class->meta_funcs._udt = _gda_postgres_meta__udt;
- provider_class->meta_funcs.udt = _gda_postgres_meta_udt;
- provider_class->meta_funcs._udt_cols = _gda_postgres_meta__udt_cols;
- provider_class->meta_funcs.udt_cols = _gda_postgres_meta_udt_cols;
- provider_class->meta_funcs._enums = _gda_postgres_meta__enums;
- provider_class->meta_funcs.enums = _gda_postgres_meta_enums;
- provider_class->meta_funcs._domains = _gda_postgres_meta__domains;
- provider_class->meta_funcs.domains = _gda_postgres_meta_domains;
- provider_class->meta_funcs._constraints_dom = _gda_postgres_meta__constraints_dom;
- provider_class->meta_funcs.constraints_dom = _gda_postgres_meta_constraints_dom;
- provider_class->meta_funcs._el_types = _gda_postgres_meta__el_types;
- provider_class->meta_funcs.el_types = _gda_postgres_meta_el_types;
- provider_class->meta_funcs._collations = _gda_postgres_meta__collations;
- provider_class->meta_funcs.collations = _gda_postgres_meta_collations;
- provider_class->meta_funcs._character_sets = _gda_postgres_meta__character_sets;
- provider_class->meta_funcs.character_sets = _gda_postgres_meta_character_sets;
- provider_class->meta_funcs._schemata = _gda_postgres_meta__schemata;
- provider_class->meta_funcs.schemata = _gda_postgres_meta_schemata;
- provider_class->meta_funcs._tables_views = _gda_postgres_meta__tables_views;
- provider_class->meta_funcs.tables_views = _gda_postgres_meta_tables_views;
- provider_class->meta_funcs._columns = _gda_postgres_meta__columns;
- provider_class->meta_funcs.columns = _gda_postgres_meta_columns;
- provider_class->meta_funcs._view_cols = _gda_postgres_meta__view_cols;
- provider_class->meta_funcs.view_cols = _gda_postgres_meta_view_cols;
- provider_class->meta_funcs._constraints_tab = _gda_postgres_meta__constraints_tab;
- provider_class->meta_funcs.constraints_tab = _gda_postgres_meta_constraints_tab;
- provider_class->meta_funcs._constraints_ref = _gda_postgres_meta__constraints_ref;
- provider_class->meta_funcs.constraints_ref = _gda_postgres_meta_constraints_ref;
- provider_class->meta_funcs._key_columns = _gda_postgres_meta__key_columns;
- provider_class->meta_funcs.key_columns = _gda_postgres_meta_key_columns;
- provider_class->meta_funcs._check_columns = _gda_postgres_meta__check_columns;
- provider_class->meta_funcs.check_columns = _gda_postgres_meta_check_columns;
- provider_class->meta_funcs._triggers = _gda_postgres_meta__triggers;
- provider_class->meta_funcs.triggers = _gda_postgres_meta_triggers;
- provider_class->meta_funcs._routines = _gda_postgres_meta__routines;
- provider_class->meta_funcs.routines = _gda_postgres_meta_routines;
- provider_class->meta_funcs._routine_col = _gda_postgres_meta__routine_col;
- provider_class->meta_funcs.routine_col = _gda_postgres_meta_routine_col;
- provider_class->meta_funcs._routine_par = _gda_postgres_meta__routine_par;
- provider_class->meta_funcs.routine_par = _gda_postgres_meta_routine_par;
- provider_class->meta_funcs._indexes_tab = _gda_postgres_meta__indexes_tab;
- provider_class->meta_funcs.indexes_tab = _gda_postgres_meta_indexes_tab;
- provider_class->meta_funcs._index_cols = _gda_postgres_meta__index_cols;
- provider_class->meta_funcs.index_cols = _gda_postgres_meta_index_cols;
-
- provider_class->xa_funcs = g_new0 (GdaServerProviderXa, 1);
- provider_class->xa_funcs->xa_start = gda_postgres_provider_xa_start;
- provider_class->xa_funcs->xa_end = gda_postgres_provider_xa_end;
- provider_class->xa_funcs->xa_prepare = gda_postgres_provider_xa_prepare;
- provider_class->xa_funcs->xa_commit = gda_postgres_provider_xa_commit;
- provider_class->xa_funcs->xa_rollback = gda_postgres_provider_xa_rollback;
- provider_class->xa_funcs->xa_recover = gda_postgres_provider_xa_recover;
+ /* set virtual functions */
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_BASE,
+ (gpointer) &postgres_base_functions);
+ GdaProviderReuseableOperations *ops;
+ ops = _gda_postgres_reuseable_get_ops ();
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_META,
+ (gpointer) &(ops->re_meta_funcs));
- /* If PostgreSQL was not compiled with the --enable-thread-safety flag, then libPQ is not
- * considered thread safe, and we limit the usage of the provider from the current thread */
- if (! PQisthreadsafe ()) {
- gda_log_message ("PostgreSQL was not compiled with the --enable-thread-safety flag, "
- "only one thread can access the provider");
- provider_class->limiting_thread = GDA_SERVER_PROVIDER_UNDEFINED_LIMITING_THREAD;
- }
- else
- provider_class->limiting_thread = NULL;
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_XA,
+ (gpointer) &postgres_xa_functions);
}
static void
@@ -350,6 +312,23 @@ gda_postgres_provider_get_type (void)
return type;
}
+static GdaWorker *
+gda_postgres_provider_create_worker (GdaServerProvider *provider)
+{
+ /* If PostgreSQL was not compiled with the --enable-thread-safety flag, then libPQ is not
+ * considered thread safe, and we limit the usage of the provider to one single thread */
+
+ static GdaWorker *unique_worker = NULL;
+ if (unique_worker)
+ return gda_worker_ref (unique_worker);
+
+ if (PQisthreadsafe ())
+ return gda_worker_new ();
+ else {
+ unique_worker = gda_worker_new ();
+ return gda_worker_ref (unique_worker);
+ }
+}
/*
* Get provider name request
@@ -378,7 +357,7 @@ pq_notice_processor (GdaConnection *cnc, const char *message)
if (!message)
return;
- cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return;
error = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_NOTICE);
@@ -475,9 +454,9 @@ determine_date_style (const gchar *str, guint year, guint month, guint day, GDat
*out_sep = sep;
/*g_print ("POSTGRESQL date format recognized for [%s] is: %s%c%s%c%s\n", str,
- (order [0] == G_DATE_DAY) ? "D" : ((order [0] == G_DATE_MONTH) ? "M" : "Y"), sep,
- (order [1] == G_DATE_DAY) ? "D" : ((order [1] == G_DATE_MONTH) ? "M" : "Y"), sep,
- (order [2] == G_DATE_DAY) ? "D" : ((order [2] == G_DATE_MONTH) ? "M" : "Y"));
+ (order [0] == G_DATE_DAY) ? "D" : ((order [0] == G_DATE_MONTH) ? "M" : "Y"), sep,
+ (order [1] == G_DATE_DAY) ? "D" : ((order [1] == G_DATE_MONTH) ? "M" : "Y"), sep,
+ (order [2] == G_DATE_DAY) ? "D" : ((order [2] == G_DATE_MONTH) ? "M" : "Y"));
*/
return TRUE;
@@ -492,7 +471,7 @@ adapt_to_date_format (GdaServerProvider *provider, GdaConnection *cnc, GError **
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 (cnc);
+ cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return FALSE;
@@ -542,23 +521,14 @@ adapt_to_date_format (GdaServerProvider *provider, GdaConnection *cnc, GError **
*/
static gboolean
gda_postgres_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- G_GNUC_UNUSED guint *task_id, GdaServerProviderAsyncCallback async_cb,
- G_GNUC_UNUSED gpointer cb_data)
+ GdaQuarkList *params, GdaQuarkList *auth)
{
g_return_val_if_fail (GDA_IS_POSTGRES_PROVIDER (provider), FALSE);
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
- /* If asynchronous connection opening is not supported, then exit now */
- if (async_cb) {
- gda_connection_add_event_string (cnc, _("Provider does not support asynchronous connection
open"));
- return FALSE;
- }
-
/* Check for connection parameters */
const gchar *pq_host;
const gchar *pq_db;
- const gchar *pg_searchpath;
const gchar *pq_port;
const gchar *pq_options;
const gchar *pq_tty;
@@ -586,7 +556,6 @@ gda_postgres_provider_open_connection (GdaServerProvider *provider, GdaConnectio
pq_db = str;
}
}
- pg_searchpath = gda_quark_list_find (params, "SEARCHPATH");
pq_port = gda_quark_list_find (params, "PORT");
pq_options = gda_quark_list_find (params, "OPTIONS");
pq_tty = gda_quark_list_find (params, "TTY");
@@ -659,7 +628,26 @@ gda_postgres_provider_open_connection (GdaServerProvider *provider, GdaConnectio
cdata->pconn = pconn;
/* attach connection data */
- gda_connection_internal_set_provider_data (cnc, cdata, (GDestroyNotify) gda_postgres_free_cnc_data);
+ gda_connection_internal_set_provider_data (cnc, (GdaServerProviderConnectionData*) cdata,
+ (GDestroyNotify) gda_postgres_free_cnc_data);
+
+ return TRUE;
+}
+
+static gboolean
+gda_postgres_provider_prepare_connection (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaQuarkList *params, G_GNUC_UNUSED GdaQuarkList *auth)
+{
+ g_return_val_if_fail (GDA_IS_POSTGRES_PROVIDER (provider), FALSE);
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+
+ PostgresConnectionData *cdata;
+ cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata)
+ return FALSE;
+
+ const gchar *pg_searchpath;
+ pg_searchpath = gda_quark_list_find (params, "SEARCHPATH");
/*
* Determine the date format
@@ -671,8 +659,6 @@ gda_postgres_provider_open_connection (GdaServerProvider *provider, GdaConnectio
gda_connection_add_event_string (cnc, "%s", lerror->message);
g_clear_error (&lerror);
}
- gda_postgres_free_cnc_data (cdata);
- gda_connection_internal_set_provider_data (cnc, NULL, NULL);
return FALSE;
}
@@ -680,20 +666,13 @@ gda_postgres_provider_open_connection (GdaServerProvider *provider, GdaConnectio
* Unicode is the default character set now
*/
PGresult *pg_res;
- pg_res = _gda_postgres_PQexec_wrap (cnc, pconn, "SET CLIENT_ENCODING TO 'UNICODE'");
- if (!pg_res) {
- gda_postgres_free_cnc_data (cdata);
- gda_connection_internal_set_provider_data (cnc, NULL, NULL);
+ pg_res = _gda_postgres_PQexec_wrap (cnc, cdata->pconn, "SET CLIENT_ENCODING TO 'UNICODE'");
+ if (!pg_res)
return FALSE;
- }
PQclear (pg_res);
- /*pg_res = _gda_postgres_PQexec_wrap (cnc, pconn, "SET DATESTYLE TO 'ISO'");
- g_assert (pg_res);
- PQclear (pg_res);*/
-
/* handle LibPQ's notices */
- PQsetNoticeProcessor (pconn, (PQnoticeProcessor) pq_notice_processor, cnc);
+ PQsetNoticeProcessor (cdata->pconn, (PQnoticeProcessor) pq_notice_processor, cnc);
/* handle the reuseable part */
GdaProviderReuseableOperations *ops;
@@ -717,22 +696,19 @@ gda_postgres_provider_open_connection (GdaServerProvider *provider, GdaConnectio
if (path_valid) {
gchar *query = g_strdup_printf ("SET search_path TO %s", pg_searchpath);
- pg_res = _gda_postgres_PQexec_wrap (cnc, pconn, query);
+ pg_res = _gda_postgres_PQexec_wrap (cnc, cdata->pconn, query);
g_free (query);
if (!pg_res || (PQresultStatus (pg_res) != PGRES_COMMAND_OK)) {
gda_connection_add_event_string (cnc, _("Could not set search_path to %s"),
pg_searchpath);
PQclear (pg_res);
- gda_postgres_free_cnc_data (cdata);
- gda_connection_internal_set_provider_data (cnc, NULL, NULL);
+
return FALSE;
}
PQclear (pg_res);
}
else {
gda_connection_add_event_string (cnc, _("Search path %s is invalid"), pg_searchpath);
- gda_postgres_free_cnc_data (cdata);
- gda_connection_internal_set_provider_data (cnc, NULL, NULL);
return FALSE;
}
}
@@ -740,6 +716,7 @@ gda_postgres_provider_open_connection (GdaServerProvider *provider, GdaConnectio
return TRUE;
}
+
/*
* Close connection request
*
@@ -758,7 +735,7 @@ gda_postgres_provider_close_connection (GdaServerProvider *provider, GdaConnecti
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
/* Close the connection using the C API */
- cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return FALSE;
@@ -783,7 +760,7 @@ gda_postgres_provider_get_server_version (GdaServerProvider *provider, GdaConnec
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
- cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
@@ -805,7 +782,7 @@ gda_postgres_provider_get_database (GdaServerProvider *provider, GdaConnection *
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
- cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
@@ -1022,19 +999,10 @@ gda_postgres_provider_render_operation (GdaServerProvider *provider, GdaConnecti
*/
static gboolean
gda_postgres_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
- GdaServerOperation *op, G_GNUC_UNUSED guint *task_id,
- GdaServerProviderAsyncCallback async_cb,
- G_GNUC_UNUSED gpointer cb_data, GError **error)
+ GdaServerOperation *op,GError **error)
{
GdaServerOperationType optype;
- /* If asynchronous connection opening is not supported, then exit now */
- if (async_cb) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
- "%s", _("Provider does not support asynchronous server operation"));
- return FALSE;
- }
-
if (cnc) {
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
@@ -1445,7 +1413,7 @@ gda_postgres_provider_supports_feature (GdaServerProvider *provider, GdaConnecti
if (cnc) {
PostgresConnectionData *cdata;
- cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data_error
(cnc, NULL);
if (!cdata)
return FALSE;
if (cdata->reuseable->version_float >= 7.3)
@@ -1453,8 +1421,6 @@ gda_postgres_provider_supports_feature (GdaServerProvider *provider, GdaConnecti
}
else
return TRUE;
- case GDA_CONNECTION_FEATURE_MULTI_THREADING:
- return PQisthreadsafe () ? TRUE : FALSE;
default:
break;
}
@@ -1863,7 +1829,7 @@ make_last_inserted_set (GdaConnection *cnc, GdaStatement *stmt, Oid last_id)
if (gda_sql_statement_check_structure (sql_statement, &lerror) == FALSE) {
g_warning (_("Can't build SELECT statement to get last inserted row: %s"),
- lerror && lerror->message ? lerror->message : _("No detail"));
+ lerror && lerror->message ? lerror->message : _("No detail"));
if (lerror)
g_error_free (lerror);
gda_sql_statement_free (sql_statement);
@@ -1972,9 +1938,7 @@ static GObject *
gda_postgres_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
GdaStatement *stmt, GdaSet *params,
GdaStatementModelUsage model_usage,
- GType *col_types, GdaSet **last_inserted_row,
- guint *task_id,
- GdaServerProviderExecCallback async_cb, gpointer cb_data, GError
**error)
+ GType *col_types, GdaSet **last_inserted_row, GError **error)
{
GdaPostgresPStmt *ps;
PostgresConnectionData *cdata;
@@ -1986,13 +1950,6 @@ gda_postgres_provider_statement_execute (GdaServerProvider *provider, GdaConnect
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
- /* If asynchronous connection opening is not supported, then exit now */
- if (async_cb) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
- "%s", _("Provider does not support asynchronous statement execution"));
- return NULL;
- }
-
g_assert ((model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS) ||
(model_usage & GDA_STATEMENT_MODEL_CURSOR_FORWARD));
@@ -2184,8 +2141,7 @@ gda_postgres_provider_statement_execute (GdaServerProvider *provider, GdaConnect
rstmt, params,
model_usage,
col_types, last_inserted_row,
- task_id,
- async_cb, cb_data, error);
+ error);
g_object_unref (rstmt);
return res;
}
@@ -2236,9 +2192,7 @@ gda_postgres_provider_statement_execute (GdaServerProvider *provider, GdaConnect
rstmt, params,
model_usage,
col_types,
- last_inserted_row,
- task_id, async_cb,
- cb_data, error);
+ last_inserted_row, error);
/* clear original @param_ids and restore copied one */
g_slist_foreach (prep_param_ids, (GFunc) g_free, NULL);
g_slist_free (prep_param_ids);
@@ -2457,8 +2411,8 @@ gda_postgres_provider_statement_execute (GdaServerProvider *provider, GdaConnect
* - if there is no default value anymore, it uses the "DEFAULT VALUES" syntax
*/
static GdaSqlStatement *
-gda_postgresql_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
- GdaStatement *stmt, GdaSet *params, GError **error)
+gda_postgres_provider_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error)
{
if (cnc) {
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
@@ -2767,15 +2721,15 @@ pg_remove_quotes (gchar *str)
}
static gchar *
-gda_postgresql_identifier_quote (G_GNUC_UNUSED GdaServerProvider *provider, GdaConnection *cnc,
- const gchar *id,
- gboolean for_meta_store, gboolean force_quotes)
+gda_postgres_provider_identifier_quote (G_GNUC_UNUSED GdaServerProvider *provider, GdaConnection *cnc,
+ const gchar *id,
+ gboolean for_meta_store, gboolean force_quotes)
{
GdaSqlReservedKeywordsFunc kwfunc;
PostgresConnectionData *cdata = NULL;
if (cnc)
- cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data_error (cnc,
NULL);
kwfunc = _gda_postgres_reuseable_get_reserved_keywords_func
(cdata ? (GdaProviderReuseable*) cdata->reuseable : NULL);
@@ -2861,3 +2815,22 @@ gda_postgres_free_cnc_data (PostgresConnectionData *cdata)
g_free (cdata);
}
+
+static gchar *
+gda_postgres_provider_escape_string (GdaServerProvider *provider, GdaConnection *cnc, const gchar *string)
+{
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ if (!string)
+ return NULL;
+
+ PostgresConnectionData *cdata = NULL;
+ cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
+
+ char *tmp;
+ gchar *retval;
+ tmp = PQescapeLiteral (cdata->pconn, string, strlen (string));
+ retval = g_strdup (tmp);
+ PQfreemem (tmp);
+ return retval;
+}
diff --git a/providers/postgres/gda-postgres-recordset.c b/providers/postgres/gda-postgres-recordset.c
index 9ddc645..34481cf 100644
--- a/providers/postgres/gda-postgres-recordset.c
+++ b/providers/postgres/gda-postgres-recordset.c
@@ -334,7 +334,7 @@ gda_postgres_recordset_new_random (GdaConnection *cnc, GdaPostgresPStmt *ps, Gda
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (ps, NULL);
- cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
@@ -365,7 +365,7 @@ gda_postgres_recordset_new_cursor (GdaConnection *cnc, GdaPostgresPStmt *ps, Gda
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (ps, NULL);
- cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
diff --git a/providers/postgres/gda-postgres.h b/providers/postgres/gda-postgres.h
index ec7ebbe..47398ec 100644
--- a/providers/postgres/gda-postgres.h
+++ b/providers/postgres/gda-postgres.h
@@ -30,6 +30,7 @@
#define POSTGRES_PROVIDER_NAME "PostgreSQL"
#include <libgda/libgda.h>
+#include <libgda/gda-connection-private.h>
#include <libpq-fe.h>
#include <libpq/libpq-fs.h>
#include <gda-postgres-reuseable.h>
@@ -49,6 +50,7 @@ typedef struct {
* Provider's specific connection data
*/
typedef struct {
+ GdaServerProviderConnectionData parent;
GdaPostgresReuseable *reuseable;
GdaConnection *cnc;
PGconn *pconn;
diff --git a/providers/reuseable/gda-provider-reuseable.h b/providers/reuseable/gda-provider-reuseable.h
index bf1fef1..a01aed3 100644
--- a/providers/reuseable/gda-provider-reuseable.h
+++ b/providers/reuseable/gda-provider-reuseable.h
@@ -23,7 +23,7 @@
#include <glib.h>
#include <glib-object.h>
#include <libgda/gda-decl.h>
-#include <libgda/gda-server-provider.h>
+#include <libgda/gda-server-provider-impl.h>
G_BEGIN_DECLS
diff --git a/providers/skel-implementation/capi/gda-capi-blob-op.c
b/providers/skel-implementation/capi/gda-capi-blob-op.c
index 66fcb4a..fc72351 100644
--- a/providers/skel-implementation/capi/gda-capi-blob-op.c
+++ b/providers/skel-implementation/capi/gda-capi-blob-op.c
@@ -26,6 +26,7 @@
#include <libgda/libgda.h>
#include "gda-capi.h"
#include "gda-capi-blob-op.h"
+#include <libgda/gda-blob-op-impl.h>
#include <libgda/gda-debug-macros.h>
struct _GdaCapiBlobOpPrivate {
@@ -95,9 +96,9 @@ gda_capi_blob_op_class_init (GdaCapiBlobOpClass *klass)
parent_class = g_type_class_peek_parent (klass);
object_class->finalize = gda_capi_blob_op_finalize;
- blob_class->get_length = gda_capi_blob_op_get_length;
- blob_class->read = gda_capi_blob_op_read;
- blob_class->write = gda_capi_blob_op_write;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->get_length = gda_capi_blob_op_get_length;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->read = gda_capi_blob_op_read;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->write = gda_capi_blob_op_write;
}
static void
@@ -123,7 +124,7 @@ gda_capi_blob_op_new (GdaConnection *cnc)
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- bop = g_object_new (GDA_TYPE_CAPI_BLOB_OP, NULL);
+ bop = g_object_new (GDA_TYPE_CAPI_BLOB_OP, "connection", cnc, NULL);
bop->priv->cnc = cnc;
return GDA_BLOB_OP (bop);
diff --git a/providers/skel-implementation/capi/gda-capi-provider.c
b/providers/skel-implementation/capi/gda-capi-provider.c
index 2742b64..6209b63 100644
--- a/providers/skel-implementation/capi/gda-capi-provider.c
+++ b/providers/skel-implementation/capi/gda-capi-provider.c
@@ -30,6 +30,7 @@
#include <libgda/libgda.h>
#include <libgda/gda-data-model-private.h>
#include <libgda/gda-server-provider-extra.h>
+#include <libgda/gda-server-provider-impl.h>
#include <libgda/binreloc/gda-binreloc.h>
#include <libgda/gda-statement-extra.h>
#include <sql-parser/gda-sql-parser.h>
@@ -54,9 +55,13 @@ static GObjectClass *parent_class = NULL;
*/
/* connection management */
static gboolean gda_capi_provider_open_connection (GdaServerProvider *provider, GdaConnection
*cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- guint *task_id, GdaServerProviderAsyncCallback
async_cb, gpointer cb_data);
+ GdaQuarkList *params, GdaQuarkList *auth);
+static gboolean gda_capi_provider_prepare_connection (GdaServerProvider *provider, GdaConnection
*cnc,
+ GdaQuarkList *params, GdaQuarkList *auth);
static gboolean gda_capi_provider_close_connection (GdaServerProvider *provider, GdaConnection
*cnc);
+static gchar *gda_capi_provider_escape_string (GdaServerProvider *provider, GdaConnection *cnc,
const gchar *str);
+static gchar *gda_capi_provider_unescape_string (GdaServerProvider *provider, GdaConnection
*cnc, const gchar *str);
+
static const gchar *gda_capi_provider_get_server_version (GdaServerProvider *provider, GdaConnection
*cnc);
static const gchar *gda_capi_provider_get_database (GdaServerProvider *provider, GdaConnection *cnc);
@@ -70,9 +75,7 @@ static gchar *gda_capi_provider_render_operation (GdaServerProvider
GdaServerOperation *op, GError **error);
static gboolean gda_capi_provider_perform_operation (GdaServerProvider *provider, GdaConnection
*cnc,
- GdaServerOperation *op, guint *task_id,
- GdaServerProviderAsyncCallback async_cb,
gpointer cb_data,
- GError **error);
+ GdaServerOperation *op, GError **error);
/* transactions */
static gboolean gda_capi_provider_begin_transaction (GdaServerProvider *provider, GdaConnection
*cnc,
const gchar *name, GdaTransactionIsolation
level, GError **error);
@@ -91,7 +94,8 @@ static gboolean gda_capi_provider_delete_savepoint (GdaServerProvider
static const gchar *gda_capi_provider_get_version (GdaServerProvider *provider);
static gboolean gda_capi_provider_supports_feature (GdaServerProvider *provider, GdaConnection
*cnc,
GdaConnectionFeature feature);
-
+static GdaWorker *gda_capi_provider_create_worker (GdaServerProvider *provider);
+static GdaConnection *gda_capi_provider_create_connection (GdaServerProvider *provider);
static const gchar *gda_capi_provider_get_name (GdaServerProvider *provider);
static GdaDataHandler *gda_capi_provider_get_data_handler (GdaServerProvider *provider, GdaConnection
*cnc,
@@ -101,18 +105,19 @@ static const gchar* gda_capi_provider_get_default_dbms_type (GdaServerPro
GType type);
/* statements */
static GdaSqlParser *gda_capi_provider_create_parser (GdaServerProvider *provider, GdaConnection
*cnc);
-static gchar *gda_capi_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection
*cnc,
- GdaStatement *stmt, GdaSet *params,
- GdaStatementSqlFlag flags,
- GSList **params_used, GError **error);
+static gchar *gda_capi_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection
*cnc,
+ GdaStatement *stmt, GdaSet *params,
+ GdaStatementSqlFlag flags,
+ GSList **params_used, GError **error);
+static gchar *gda_capi_provider_identifier_quote (GdaServerProvider *provider, GdaConnection
*cnc,
+ const gchar *id,
+ gboolean for_meta_store, gboolean
force_quotes);
static gboolean gda_capi_provider_statement_prepare (GdaServerProvider *provider, GdaConnection
*cnc,
GdaStatement *stmt, GError **error);
static GObject *gda_capi_provider_statement_execute (GdaServerProvider *provider, GdaConnection
*cnc,
GdaStatement *stmt, GdaSet *params,
GdaStatementModelUsage model_usage,
- GType *col_types, GdaSet
**last_inserted_row,
- guint *task_id,
GdaServerProviderExecCallback async_cb,
- gpointer cb_data, GError **error);
+ GType *col_types, GdaSet
**last_inserted_row, GError **error);
static GdaSqlStatement *gda_capi_statement_rewrite (GdaServerProvider *provider, GdaConnection
*cnc,
GdaStatement *stmt, GdaSet *params, GError
**error);
@@ -159,106 +164,118 @@ static gchar *internal_sql[] = {
/*
* GdaCapiProvider class implementation
*/
+
+GdaServerProviderBase base_functions = {
+ gda_capi_provider_get_name,
+ gda_capi_provider_get_version,
+ gda_capi_provider_get_server_version,
+ gda_capi_provider_supports_feature,
+ gda_capi_provider_create_worker,
+ gda_capi_provider_create_connection,
+ gda_capi_provider_create_parser,
+ gda_capi_provider_get_data_handler,
+ gda_capi_provider_get_default_dbms_type,
+ gda_capi_provider_supports_operation,
+ gda_capi_provider_create_operation,
+ gda_capi_provider_render_operation,
+ gda_capi_provider_statement_to_sql,
+ gda_capi_provider_identifier_quote,
+ gda_capi_statement_rewrite,
+ gda_capi_provider_open_connection,
+ gda_capi_provider_prepare_connection,
+ gda_capi_provider_close_connection,
+ gda_capi_provider_escape_string,
+ gda_capi_provider_unescape_string,
+ gda_capi_provider_get_database,
+ gda_capi_provider_perform_operation,
+ gda_capi_provider_begin_transaction,
+ gda_capi_provider_commit_transaction,
+ gda_capi_provider_rollback_transaction,
+ gda_capi_provider_add_savepoint,
+ gda_capi_provider_rollback_savepoint,
+ gda_capi_provider_delete_savepoint,
+ gda_capi_provider_statement_prepare,
+ gda_capi_provider_statement_execute,
+
+ NULL, NULL, NULL, NULL, /* padding */
+};
+
+GdaServerProviderMeta meta_functions = {
+ _gda_capi_meta__info,
+ _gda_capi_meta__btypes,
+ _gda_capi_meta__udt,
+ _gda_capi_meta_udt,
+ _gda_capi_meta__udt_cols,
+ _gda_capi_meta_udt_cols,
+ _gda_capi_meta__enums,
+ _gda_capi_meta_enums,
+ _gda_capi_meta__domains,
+ _gda_capi_meta_domains,
+ _gda_capi_meta__constraints_dom,
+ _gda_capi_meta_constraints_dom,
+ _gda_capi_meta__el_types,
+ _gda_capi_meta_el_types,
+ _gda_capi_meta__collations,
+ _gda_capi_meta_collations,
+ _gda_capi_meta__character_sets,
+ _gda_capi_meta_character_sets,
+ _gda_capi_meta__schemata,
+ _gda_capi_meta_schemata,
+ _gda_capi_meta__tables_views,
+ _gda_capi_meta_tables_views,
+ _gda_capi_meta__columns,
+ _gda_capi_meta_columns,
+ _gda_capi_meta__view_cols,
+ _gda_capi_meta_view_cols,
+ _gda_capi_meta__constraints_tab,
+ _gda_capi_meta_constraints_tab,
+ _gda_capi_meta__constraints_ref,
+ _gda_capi_meta_constraints_ref,
+ _gda_capi_meta__key_columns,
+ _gda_capi_meta_key_columns,
+ _gda_capi_meta__check_columns,
+ _gda_capi_meta_check_columns,
+ _gda_capi_meta__triggers,
+ _gda_capi_meta_triggers,
+ _gda_capi_meta__routines,
+ _gda_capi_meta_routines,
+ _gda_capi_meta__routine_col,
+ _gda_capi_meta_routine_col,
+ _gda_capi_meta__routine_par,
+ _gda_capi_meta_routine_par,
+ _gda_capi_meta__indexes_tab,
+ _gda_capi_meta_indexes_tab,
+ _gda_capi_meta__index_cols,
+ _gda_capi_meta_index_cols,
+
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* padding */
+};
+
+GdaServerProviderXa xa_functions = {
+ gda_capi_provider_xa_start,
+ gda_capi_provider_xa_end,
+ gda_capi_provider_xa_prepare,
+ gda_capi_provider_xa_commit,
+ gda_capi_provider_xa_rollback,
+ gda_capi_provider_xa_recover,
+
+ NULL, NULL, NULL, NULL, /* padding */
+};
+
static void
gda_capi_provider_class_init (GdaCapiProviderClass *klass)
{
GdaServerProviderClass *provider_class = GDA_SERVER_PROVIDER_CLASS (klass);
- parent_class = g_type_class_peek_parent (klass);
+ /* set virtual functions */
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_BASE, (gpointer)
&base_functions);
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_META, (gpointer)
&meta_functions);
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_XA, (gpointer) &xa_functions);
- provider_class->get_version = gda_capi_provider_get_version;
- provider_class->get_server_version = gda_capi_provider_get_server_version;
- provider_class->get_name = gda_capi_provider_get_name;
- provider_class->supports_feature = gda_capi_provider_supports_feature;
-
- provider_class->get_data_handler = gda_capi_provider_get_data_handler;
- provider_class->get_def_dbms_type = gda_capi_provider_get_default_dbms_type;
-
- provider_class->open_connection = gda_capi_provider_open_connection;
- provider_class->close_connection = gda_capi_provider_close_connection;
- provider_class->get_database = gda_capi_provider_get_database;
-
- provider_class->supports_operation = gda_capi_provider_supports_operation;
- provider_class->create_operation = gda_capi_provider_create_operation;
- provider_class->render_operation = gda_capi_provider_render_operation;
- provider_class->perform_operation = gda_capi_provider_perform_operation;
-
- provider_class->begin_transaction = gda_capi_provider_begin_transaction;
- provider_class->commit_transaction = gda_capi_provider_commit_transaction;
- provider_class->rollback_transaction = gda_capi_provider_rollback_transaction;
- provider_class->add_savepoint = gda_capi_provider_add_savepoint;
- provider_class->rollback_savepoint = gda_capi_provider_rollback_savepoint;
- provider_class->delete_savepoint = gda_capi_provider_delete_savepoint;
-
- provider_class->create_parser = gda_capi_provider_create_parser;
- provider_class->statement_to_sql = NULL; /* don't use gda_capi_provider_statement_to_sql()
- * because it only calls gda_statement_to_sql_extended().
- * Set it to gda_capi_provider_statement_to_sql() if it does
- * not call calls gda_statement_to_sql_extended() */
- provider_class->statement_prepare = gda_capi_provider_statement_prepare;
- provider_class->statement_execute = gda_capi_provider_statement_execute;
- provider_class->statement_rewrite = gda_capi_statement_rewrite;
-
- provider_class->is_busy = NULL;
- provider_class->cancel = NULL;
- provider_class->create_connection = NULL;
-
- memset (&(provider_class->meta_funcs), 0, sizeof (GdaServerProviderMeta));
- provider_class->meta_funcs._info = _gda_capi_meta__info;
- provider_class->meta_funcs._btypes = _gda_capi_meta__btypes;
- provider_class->meta_funcs._udt = _gda_capi_meta__udt;
- provider_class->meta_funcs.udt = _gda_capi_meta_udt;
- provider_class->meta_funcs._udt_cols = _gda_capi_meta__udt_cols;
- provider_class->meta_funcs.udt_cols = _gda_capi_meta_udt_cols;
- provider_class->meta_funcs._enums = _gda_capi_meta__enums;
- provider_class->meta_funcs.enums = _gda_capi_meta_enums;
- provider_class->meta_funcs._domains = _gda_capi_meta__domains;
- provider_class->meta_funcs.domains = _gda_capi_meta_domains;
- provider_class->meta_funcs._constraints_dom = _gda_capi_meta__constraints_dom;
- provider_class->meta_funcs.constraints_dom = _gda_capi_meta_constraints_dom;
- provider_class->meta_funcs._el_types = _gda_capi_meta__el_types;
- provider_class->meta_funcs.el_types = _gda_capi_meta_el_types;
- provider_class->meta_funcs._collations = _gda_capi_meta__collations;
- provider_class->meta_funcs.collations = _gda_capi_meta_collations;
- provider_class->meta_funcs._character_sets = _gda_capi_meta__character_sets;
- provider_class->meta_funcs.character_sets = _gda_capi_meta_character_sets;
- provider_class->meta_funcs._schemata = _gda_capi_meta__schemata;
- provider_class->meta_funcs.schemata = _gda_capi_meta_schemata;
- provider_class->meta_funcs._tables_views = _gda_capi_meta__tables_views;
- provider_class->meta_funcs.tables_views = _gda_capi_meta_tables_views;
- provider_class->meta_funcs._columns = _gda_capi_meta__columns;
- provider_class->meta_funcs.columns = _gda_capi_meta_columns;
- provider_class->meta_funcs._view_cols = _gda_capi_meta__view_cols;
- provider_class->meta_funcs.view_cols = _gda_capi_meta_view_cols;
- provider_class->meta_funcs._constraints_tab = _gda_capi_meta__constraints_tab;
- provider_class->meta_funcs.constraints_tab = _gda_capi_meta_constraints_tab;
- provider_class->meta_funcs._constraints_ref = _gda_capi_meta__constraints_ref;
- provider_class->meta_funcs.constraints_ref = _gda_capi_meta_constraints_ref;
- provider_class->meta_funcs._key_columns = _gda_capi_meta__key_columns;
- provider_class->meta_funcs.key_columns = _gda_capi_meta_key_columns;
- provider_class->meta_funcs._check_columns = _gda_capi_meta__check_columns;
- provider_class->meta_funcs.check_columns = _gda_capi_meta_check_columns;
- provider_class->meta_funcs._triggers = _gda_capi_meta__triggers;
- provider_class->meta_funcs.triggers = _gda_capi_meta_triggers;
- provider_class->meta_funcs._routines = _gda_capi_meta__routines;
- provider_class->meta_funcs.routines = _gda_capi_meta_routines;
- provider_class->meta_funcs._routine_col = _gda_capi_meta__routine_col;
- provider_class->meta_funcs.routine_col = _gda_capi_meta_routine_col;
- provider_class->meta_funcs._routine_par = _gda_capi_meta__routine_par;
- provider_class->meta_funcs.routine_par = _gda_capi_meta_routine_par;
- provider_class->meta_funcs._indexes_tab = _gda_capi_meta__indexes_tab;
- provider_class->meta_funcs.indexes_tab = _gda_capi_meta_indexes_tab;
- provider_class->meta_funcs._index_cols = _gda_capi_meta__index_cols;
- provider_class->meta_funcs.index_cols = _gda_capi_meta_index_cols;
-
- /* distributed transactions: if not supported, then provider_class->xa_funcs should be set to NULL */
- provider_class->xa_funcs = g_new0 (GdaServerProviderXa, 1);
- provider_class->xa_funcs->xa_start = gda_capi_provider_xa_start;
- provider_class->xa_funcs->xa_end = gda_capi_provider_xa_end;
- provider_class->xa_funcs->xa_prepare = gda_capi_provider_xa_prepare;
- provider_class->xa_funcs->xa_commit = gda_capi_provider_xa_commit;
- provider_class->xa_funcs->xa_rollback = gda_capi_provider_xa_rollback;
- provider_class->xa_funcs->xa_recover = gda_capi_provider_xa_recover;
+ parent_class = g_type_class_peek_parent (klass);
}
static void
@@ -342,23 +359,15 @@ gda_capi_provider_get_version (G_GNUC_UNUSED GdaServerProvider *provider)
* - open the real connection to the database using the parameters previously checked
* - create a CapiConnectionData structure and associate it to @cnc
*
- * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR connection event must be added to
@cnc)
+ * Returns: TRUE if no error occurred (and the connection is opened), or FALSE otherwise (and an ERROR
connection event must be added to @cnc)
*/
static gboolean
gda_capi_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
- GdaQuarkList *params, G_GNUC_UNUSED GdaQuarkList *auth,
- G_GNUC_UNUSED guint *task_id, GdaServerProviderAsyncCallback async_cb,
- G_GNUC_UNUSED gpointer cb_data)
+ GdaQuarkList *params, GdaQuarkList *auth)
{
g_return_val_if_fail (GDA_IS_CAPI_PROVIDER (provider), FALSE);
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
- /* If asynchronous connection opening is not supported, then exit now */
- if (async_cb) {
- gda_connection_add_event_string (cnc, _("Provider does not support asynchronous connection
open"));
- return FALSE;
- }
-
/* Check for connection parameters */
/* TO_ADD: your own connection parameters */
const gchar *db_name;
@@ -378,9 +387,33 @@ gda_capi_provider_open_connection (GdaServerProvider *provider, GdaConnection *c
* and set its contents */
CapiConnectionData *cdata;
cdata = g_new0 (CapiConnectionData, 1);
- gda_connection_internal_set_provider_data (cnc, cdata, (GDestroyNotify) gda_capi_free_cnc_data);
+ gda_connection_internal_set_provider_data (cnc, (GdaServerProviderConnectionData*) cdata,
+ (GDestroyNotify) gda_capi_free_cnc_data);
TO_IMPLEMENT; /* cdata->... = ... */
+ return TRUE;
+}
+
+/*
+ * Prepare connection request
+ *
+ * In this function, the extra preparation steps can be done such as setting some connection parameters, etc.
+ * If the preparation step failed, then the #GdaServerProvider will call the close_connection() method.
+ *
+ * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR connection event must be added to
@cnc)
+ */
+static gboolean
+gda_capi_provider_prepare_connection (GdaServerProvider *provider, GdaConnection *cnc, GdaQuarkList *params,
GdaQuarkList *auth)
+{
+ CapiConnectionData *cdata;
+
+ g_return_val_if_fail (GDA_IS_CAPI_PROVIDER (provider), FALSE);
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+
+ cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
+ if (!cdata)
+ return FALSE;
+
/* Optionnally set some attributes for the newly opened connection (encoding to UTF-8 for example )*/
TO_IMPLEMENT;
@@ -405,19 +438,37 @@ gda_capi_provider_close_connection (GdaServerProvider *provider, GdaConnection *
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
/* Close the connection using the C API */
- cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return FALSE;
- TO_IMPLEMENT;
- /* Free the CapiConnectionData structure and its contents*/
- gda_capi_free_cnc_data (cdata);
- gda_connection_internal_set_provider_data (cnc, NULL, NULL);
+ TO_IMPLEMENT;
return TRUE;
}
/*
+ * Escape a string so it can be used in SQL statements
+ */
+static gchar *
+gda_capi_provider_escape_string (GdaServerProvider *provider, GdaConnection *cnc, const gchar *str)
+{
+ TO_IMPLEMENT;
+ return NULL;
+}
+
+/*
+ * Does the reverse of gda_capi_provider_escape_string
+ */
+static gchar *
+gda_capi_provider_unescape_string (GdaServerProvider *provider, GdaConnection *cnc, const gchar *str)
+{
+ TO_IMPLEMENT;
+ return NULL;
+}
+
+
+/*
* Server version request
*
* Returns the server version as a string, which should be stored in @cnc's associated CapiConnectionData
structure
@@ -430,7 +481,7 @@ gda_capi_provider_get_server_version (GdaServerProvider *provider, GdaConnection
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
- cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
TO_IMPLEMENT;
@@ -450,7 +501,7 @@ gda_capi_provider_get_database (GdaServerProvider *provider, GdaConnection *cnc)
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
- cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
TO_IMPLEMENT;
@@ -610,19 +661,10 @@ gda_capi_provider_render_operation (GdaServerProvider *provider, GdaConnection *
*/
static gboolean
gda_capi_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
- GdaServerOperation *op, G_GNUC_UNUSED guint *task_id,
- GdaServerProviderAsyncCallback async_cb, G_GNUC_UNUSED gpointer cb_data,
- GError **error)
+ GdaServerOperation *op, GError **error)
{
GdaServerOperationType optype;
- /* If asynchronous connection opening is not supported, then exit now */
- if (async_cb) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
- "%s", _("Provider does not support asynchronous server operation"));
- return FALSE;
- }
-
if (cnc) {
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
@@ -785,6 +827,28 @@ gda_capi_provider_supports_feature (GdaServerProvider *provider, GdaConnection *
}
/*
+ * Create a #GdaWorker: all the calls to the C API will be made from within the GdaWorker's worker thread.
This ensures that
+ * each connection is manipulated from only one thread. If the C API does not support several threads each
manipulating its
+ * own connection, then this function should return a single GdaWorker for any request (using
gda_worker_ref()).
+ */
+static GdaWorker *
+gda_capi_provider_create_worker (GdaServerProvider *provider)
+{
+ TO_IMPLEMENT;
+ return gda_worker_new ();
+}
+
+/*
+ * For providers which require a specific GdaConnection object, seldom used.
+ */
+static GdaConnection *
+gda_capi_provider_create_connection (GdaServerProvider *provider)
+{
+ TO_IMPLEMENT;
+ return NULL;
+}
+
+/*
* Get data handler request
*
* This method allows one to obtain a pointer to a #GdaDataHandler object specific to @type or @dbms_type
(@dbms_type
@@ -913,8 +977,7 @@ gda_capi_provider_create_parser (G_GNUC_UNUSED GdaServerProvider *provider, G_GN
* can be specialized to the database's SQL dialect, see the implementation of
gda_statement_to_sql_extended()
* and SQLite's specialized rendering for more details
*
- * NOTE: This implementation MUST NOT call gda_statement_to_sql_extended() if it is
- * the GdaServerProvider::statement_to_sql() virtual method's implementation
+ * NOTE: The implementation MUST NOT call gda_statement_to_sql_extended() because this will end up in a loop.
*/
static gchar *
gda_capi_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection *cnc,
@@ -927,9 +990,23 @@ gda_capi_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection *
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
}
- return gda_statement_to_sql_extended (stmt, cnc, params, flags, params_used, error);
+ TO_IMPLEMENT;
+ return NULL;
+}
+
+/*
+ * Function to quote identifiers to be used safely in SQL statements
+ */
+static gchar *
+gda_capi_provider_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
+ const gchar *id,
+ gboolean for_meta_store, gboolean force_quotes)
+{
+ TO_IMPLEMENT;
+ return NULL;
}
+
/*
* Statement prepare request
*
@@ -1024,9 +1101,7 @@ static GObject *
gda_capi_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
GdaStatement *stmt, GdaSet *params,
GdaStatementModelUsage model_usage,
- GType *col_types, GdaSet **last_inserted_row,
- guint *task_id,
- GdaServerProviderExecCallback async_cb, gpointer cb_data, GError **error)
+ GType *col_types, GdaSet **last_inserted_row, GError **error)
{
GdaCapiPStmt *ps;
CapiConnectionData *cdata;
@@ -1038,13 +1113,6 @@ gda_capi_provider_statement_execute (GdaServerProvider *provider, GdaConnection
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
- /* If asynchronous connection opening is not supported, then exit now */
- if (async_cb) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
- "%s", _("Provider does not support asynchronous statement execution"));
- return NULL;
- }
-
allow_noparam = (model_usage & GDA_STATEMENT_MODEL_ALLOW_NOPARAM) &&
(gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT);
@@ -1174,8 +1242,7 @@ gda_capi_provider_statement_execute (GdaServerProvider *provider, GdaConnection
rstmt, params,
model_usage,
col_types, last_inserted_row,
- task_id,
- async_cb, cb_data, error);
+ error);
g_object_unref (rstmt);
return res;
}
@@ -1223,8 +1290,7 @@ gda_capi_provider_statement_execute (GdaServerProvider *provider, GdaConnection
model_usage,
col_types,
last_inserted_row,
- task_id, async_cb,
- cb_data, error);
+ error);
/* clear original @param_ids and restore copied one */
g_slist_foreach (prep_param_ids, (GFunc) g_free, NULL);
g_slist_free (prep_param_ids);
diff --git a/providers/skel-implementation/capi/gda-capi-recordset.c
b/providers/skel-implementation/capi/gda-capi-recordset.c
index 7159ff4..bdc724a 100644
--- a/providers/skel-implementation/capi/gda-capi-recordset.c
+++ b/providers/skel-implementation/capi/gda-capi-recordset.c
@@ -152,7 +152,7 @@ gda_capi_recordset_new (GdaConnection *cnc, GdaCapiPStmt *ps, GdaSet *exec_param
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (ps != NULL, NULL);
- cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
diff --git a/providers/skel-implementation/capi/gda-capi.h b/providers/skel-implementation/capi/gda-capi.h
index 6392593..1228bb7 100644
--- a/providers/skel-implementation/capi/gda-capi.h
+++ b/providers/skel-implementation/capi/gda-capi.h
@@ -29,12 +29,15 @@
*/
#define CAPI_PROVIDER_NAME "Capi"
+#include <libgda/libgda.h>
+#include <libgda/gda-connection-private.h>
/* TO_ADD: include headers necessary for the C or C++ API */
/*
* Provider's specific connection data
*/
typedef struct {
+ GdaServerProviderConnectionData parent;
/* TO_ADD: this structure holds any information necessary to specialize the GdaConnection, usually a
connection
* handle from the C or C++ API
*/
diff --git a/providers/skel-implementation/models/gda-models-provider.c
b/providers/skel-implementation/models/gda-models-provider.c
index d0a4c9c..36d77be 100644
--- a/providers/skel-implementation/models/gda-models-provider.c
+++ b/providers/skel-implementation/models/gda-models-provider.c
@@ -25,6 +25,7 @@
#include <glib/gi18n-lib.h>
#include <virtual/gda-vconnection-data-model.h>
#include <libgda/gda-connection-private.h>
+#include <libgda/gda-server-provider-impl.h>
#include "gda-models.h"
#include "gda-models-provider.h"
#include <libgda/gda-debug-macros.h>
@@ -36,12 +37,12 @@ static void gda_models_provider_finalize (GObject *object);
static const gchar *gda_models_provider_get_name (GdaServerProvider *provider);
static const gchar *gda_models_provider_get_version (GdaServerProvider *provider);
-static gboolean gda_models_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- guint *task_id, GdaServerProviderAsyncCallback async_cb,
gpointer cb_data);
+static gboolean gda_models_provider_prepare_connection (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaQuarkList *params, GdaQuarkList *auth);
+static gboolean gda_models_provider_close_connection (GdaServerProvider *provider,
+ GdaConnection *cnc);
static const gchar *gda_models_provider_get_server_version (GdaServerProvider *provider,
GdaConnection *cnc);
-static const gchar *gda_models_provider_get_database (GdaServerProvider *provider, GdaConnection *cnc);
static GObjectClass *parent_class = NULL;
@@ -53,21 +54,54 @@ static void gda_models_free_cnc_data (ModelsConnectionData *cdata);
/*
* GdaModelsProvider class implementation
*/
+GdaServerProviderBase data_model_base_functions = {
+ gda_models_provider_get_name,
+ gda_models_provider_get_version,
+ gda_models_provider_get_server_version,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ gda_models_provider_prepare_connection,
+ gda_models_provider_close_connection,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ NULL, NULL, NULL, NULL, /* padding */
+};
+
static void
gda_models_provider_class_init (GdaModelsProviderClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GdaServerProviderClass *provider_class = GDA_SERVER_PROVIDER_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
- object_class->finalize = gda_models_provider_finalize;
+ /* set virtual functions */
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_BASE,
+ (gpointer) &data_model_base_functions);
- provider_class->get_name = gda_models_provider_get_name;
- provider_class->get_version = gda_models_provider_get_version;
- provider_class->open_connection = gda_models_provider_open_connection;
- provider_class->get_server_version = gda_models_provider_get_server_version;
- provider_class->get_database = gda_models_provider_get_database;
+ object_class->finalize = gda_models_provider_finalize;
}
static void
@@ -135,33 +169,25 @@ gda_models_provider_get_version (G_GNUC_UNUSED GdaServerProvider *provider)
}
/*
- * Open connection request
+ * Prepare connection request
*
* In this function, the following _must_ be done:
* - check for the presence and validify of the parameters required to actually open a connection,
* using @params
* - open the real connection to the database using the parameters previously checked, create one or
* more GdaDataModel objects and declare them to the virtual connection with table names
- * - open virtual (SQLite) connection
- * - create a ModelsConnectionData structure and associate it to @cnc
+ * - create a ModelsConnectionData structure and associate it to @cnc using
gda_virtual_connection_internal_set_provider_data()
+ * to get it from other methods
*
* Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR connection event must be added to
@cnc)
*/
static gboolean
-gda_models_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
- GdaQuarkList *params, G_GNUC_UNUSED GdaQuarkList *auth,
- G_GNUC_UNUSED guint *task_id, GdaServerProviderAsyncCallback async_cb,
- G_GNUC_UNUSED gpointer cb_data)
+gda_models_provider_prepare_connection (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaQuarkList *params, GdaQuarkList *auth)
{
g_return_val_if_fail (GDA_IS_MODELS_PROVIDER (provider), FALSE);
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
- /* Don't allow asynchronous connection opening for virtual providers */
- if (async_cb) {
- gda_connection_add_event_string (cnc, _("Provider does not support asynchronous connection
open"));
- return FALSE;
- }
-
/* Check for connection parameters */
/* TO_ADD: your own connection parameters */
const gchar *db_name;
@@ -179,13 +205,6 @@ gda_models_provider_open_connection (GdaServerProvider *provider, GdaConnection
GdaDataModel *model;
model = NULL; TO_IMPLEMENT;
- /* open virtual connection */
- if (! GDA_SERVER_PROVIDER_CLASS (parent_class)->open_connection (GDA_SERVER_PROVIDER (provider), cnc,
params,
- NULL, NULL, NULL, NULL)) {
- gda_connection_add_event_string (cnc, _("Can't open virtual connection"));
- return FALSE;
- }
-
/* add the data model(s) as table(s) */
GError *error = NULL;
if (!gda_vconnection_data_model_add_model (GDA_VCONNECTION_DATA_MODEL (cnc), model, "a_table",
&error)) {
@@ -193,7 +212,6 @@ gda_models_provider_open_connection (GdaServerProvider *provider, GdaConnection
_("Could not add data model to connection: %s"),
error && error->message ? error->message : _("no detail"));
g_error_free (error);
- gda_connection_close_no_warning (cnc);
g_object_unref (model);
return FALSE;
@@ -211,28 +229,34 @@ gda_models_provider_open_connection (GdaServerProvider *provider, GdaConnection
}
/*
- * Server version request
+ * Close connection request
*/
-static const gchar *
-gda_models_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc)
+static gboolean
+gda_models_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc)
{
ModelsConnectionData *cdata;
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
- cdata = (ModelsConnectionData*) gda_virtual_connection_internal_get_provider_data
(GDA_VIRTUAL_CONNECTION (cnc));
+ cdata = (ModelsConnectionData*) gda_virtual_connection_internal_get_provider_data
(GDA_VIRTUAL_CONNECTION (cnc));
if (!cdata)
return FALSE;
- TO_IMPLEMENT;
- return NULL;
+
+ /* liberate the ressources used by the virtual connection */
+ TO_IMPLEMENT;
+
+ /* link to parent implementation */
+ GdaServerProviderBase *parent_functions;
+ parent_functions = gda_server_provider_get_impl_functions_for_class (parent_class,
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+ return parent_functions->close_connection (provider, cnc);
}
/*
- * Get database request
+ * Server version request
*/
static const gchar *
-gda_models_provider_get_database (GdaServerProvider *provider, GdaConnection *cnc)
+gda_models_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc)
{
ModelsConnectionData *cdata;
@@ -241,7 +265,7 @@ gda_models_provider_get_database (GdaServerProvider *provider, GdaConnection *cn
cdata = (ModelsConnectionData*) gda_virtual_connection_internal_get_provider_data
(GDA_VIRTUAL_CONNECTION (cnc));
if (!cdata)
- return NULL;
+ return FALSE;
TO_IMPLEMENT;
return NULL;
}
diff --git a/providers/web/gda-web-blob-op.c b/providers/web/gda-web-blob-op.c
index 8398fa7..d98ccab 100644
--- a/providers/web/gda-web-blob-op.c
+++ b/providers/web/gda-web-blob-op.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 - 2011 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2008 - 2014 Vivien Malerba <malerba gnome-db org>
* Copyright (C) 2010 David King <davidk openismus com>
* Copyright (C) 2011 Murray Cumming <murrayc murrayc com>
*
@@ -24,6 +24,7 @@
#include <libgda/libgda.h>
#include "gda-web.h"
#include "gda-web-blob-op.h"
+#include <libgda/gda-blob-op-impl.h>
#include <libgda/gda-debug-macros.h>
struct _GdaWebBlobOpPrivate {
@@ -93,9 +94,9 @@ gda_web_blob_op_class_init (GdaWebBlobOpClass *klass)
parent_class = g_type_class_peek_parent (klass);
object_class->finalize = gda_web_blob_op_finalize;
- blob_class->get_length = gda_web_blob_op_get_length;
- blob_class->read = gda_web_blob_op_read;
- blob_class->write = gda_web_blob_op_write;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->get_length = gda_web_blob_op_get_length;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->read = gda_web_blob_op_read;
+ GDA_BLOB_OP_FUNCTIONS (blob_class->functions)->write = gda_web_blob_op_write;
}
static void
@@ -121,7 +122,7 @@ gda_web_blob_op_new (GdaConnection *cnc)
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- bop = g_object_new (GDA_TYPE_WEB_BLOB_OP, NULL);
+ bop = g_object_new (GDA_TYPE_WEB_BLOB_OP, "connection", cnc, NULL);
bop->priv->cnc = cnc;
return GDA_BLOB_OP (bop);
diff --git a/providers/web/gda-web-provider.c b/providers/web/gda-web-provider.c
index 4acbca6..05f59e5 100644
--- a/providers/web/gda-web-provider.c
+++ b/providers/web/gda-web-provider.c
@@ -28,6 +28,7 @@
#include <libgda/libgda.h>
#include <libgda/gda-data-model-private.h>
#include <libgda/gda-server-provider-extra.h>
+#include <libgda/gda-server-provider-impl.h>
#include <libgda/binreloc/gda-binreloc.h>
#include <libgda/gda-statement-extra.h>
#include <sql-parser/gda-sql-parser.h>
@@ -58,8 +59,7 @@ static GObjectClass *parent_class = NULL;
*/
/* connection management */
static gboolean gda_web_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- guint *task_id, GdaServerProviderAsyncCallback
async_cb, gpointer cb_data);
+ GdaQuarkList *params, GdaQuarkList *auth);
static gboolean gda_web_provider_close_connection (GdaServerProvider *provider, GdaConnection
*cnc);
static const gchar *gda_web_provider_get_server_version (GdaServerProvider *provider, GdaConnection
*cnc);
@@ -73,9 +73,7 @@ static gchar *gda_web_provider_render_operation (GdaServerProvider
GdaServerOperation *op, GError **error);
static gboolean gda_web_provider_perform_operation (GdaServerProvider *provider, GdaConnection
*cnc,
- GdaServerOperation *op, guint *task_id,
- GdaServerProviderAsyncCallback async_cb,
gpointer cb_data,
- GError **error);
+ GdaServerOperation *op, GError **error);
/* transactions */
static gboolean gda_web_provider_begin_transaction (GdaServerProvider *provider, GdaConnection
*cnc,
const gchar *name, GdaTransactionIsolation
level, GError **error);
@@ -95,6 +93,8 @@ static const gchar *gda_web_provider_get_version (GdaServerProvider *prov
static gboolean gda_web_provider_supports_feature (GdaServerProvider *provider, GdaConnection
*cnc,
GdaConnectionFeature feature);
+static GdaWorker *gda_web_provider_create_worker (GdaServerProvider *provider);
+
static const gchar *gda_web_provider_get_name (GdaServerProvider *provider);
static GdaDataHandler *gda_web_provider_get_data_handler (GdaServerProvider *provider, GdaConnection
*cnc,
@@ -113,21 +113,105 @@ static gboolean gda_web_provider_statement_prepare (GdaServerProvide
static GObject *gda_web_provider_statement_execute (GdaServerProvider *provider, GdaConnection
*cnc,
GdaStatement *stmt, GdaSet *params,
GdaStatementModelUsage model_usage,
- GType *col_types, GdaSet **last_inserted_row,
- guint *task_id, GdaServerProviderExecCallback
async_cb,
- gpointer cb_data, GError **error);
-static GdaSqlStatement *gda_web_statement_rewrite (GdaServerProvider *provider, GdaConnection
*cnc,
+ GType *col_types, GdaSet **last_inserted_row,
GError **error);
+static GdaSqlStatement *gda_web_provider_statement_rewrite (GdaServerProvider *provider, GdaConnection
*cnc,
GdaStatement *stmt, GdaSet *params, GError
**error);
/* Quoting */
-static gchar *gda_web_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
- const gchar *id,
- gboolean meta_store_convention, gboolean
force_quotes);
+static gchar *gda_web_provider_identifier_quote (GdaServerProvider *provider, GdaConnection
*cnc,
+ const gchar *id,
+ gboolean meta_store_convention, gboolean
force_quotes);
/*
* GdaWebProvider class implementation
*/
+GdaServerProviderBase web_base_functions = {
+ gda_web_provider_get_name,
+ gda_web_provider_get_version,
+ gda_web_provider_get_server_version,
+ gda_web_provider_supports_feature,
+ gda_web_provider_create_worker,
+ NULL,
+ gda_web_provider_create_parser,
+ gda_web_provider_get_data_handler,
+ gda_web_provider_get_default_dbms_type,
+ gda_web_provider_supports_operation,
+ gda_web_provider_create_operation,
+ gda_web_provider_render_operation,
+ gda_web_provider_statement_to_sql,
+ gda_web_provider_identifier_quote,
+ gda_web_provider_statement_rewrite,
+ gda_web_provider_open_connection,
+ NULL,
+ gda_web_provider_close_connection,
+ NULL,
+ NULL,
+ NULL,
+ gda_web_provider_perform_operation,
+ gda_web_provider_begin_transaction,
+ gda_web_provider_commit_transaction,
+ gda_web_provider_rollback_transaction,
+ gda_web_provider_add_savepoint,
+ gda_web_provider_rollback_savepoint,
+ gda_web_provider_delete_savepoint,
+ gda_web_provider_statement_prepare,
+ gda_web_provider_statement_execute,
+
+ NULL, NULL, NULL, NULL, /* padding */
+};
+
+GdaServerProviderMeta web_meta_functions = {
+ _gda_web_meta__info,
+ _gda_web_meta__btypes,
+ _gda_web_meta__udt,
+ _gda_web_meta_udt,
+ _gda_web_meta__udt_cols,
+ _gda_web_meta_udt_cols,
+ _gda_web_meta__enums,
+ _gda_web_meta_enums,
+ _gda_web_meta__domains,
+ _gda_web_meta_domains,
+ _gda_web_meta__constraints_dom,
+ _gda_web_meta_constraints_dom,
+ _gda_web_meta__el_types,
+ _gda_web_meta_el_types,
+ _gda_web_meta__collations,
+ _gda_web_meta_collations,
+ _gda_web_meta__character_sets,
+ _gda_web_meta_character_sets,
+ _gda_web_meta__schemata,
+ _gda_web_meta_schemata,
+ _gda_web_meta__tables_views,
+ _gda_web_meta_tables_views,
+ _gda_web_meta__columns,
+ _gda_web_meta_columns,
+ _gda_web_meta__view_cols,
+ _gda_web_meta_view_cols,
+ _gda_web_meta__constraints_tab,
+ _gda_web_meta_constraints_tab,
+ _gda_web_meta__constraints_ref,
+ _gda_web_meta_constraints_ref,
+ _gda_web_meta__key_columns,
+ _gda_web_meta_key_columns,
+ _gda_web_meta__check_columns,
+ _gda_web_meta_check_columns,
+ _gda_web_meta__triggers,
+ _gda_web_meta_triggers,
+ _gda_web_meta__routines,
+ _gda_web_meta_routines,
+ _gda_web_meta__routine_col,
+ _gda_web_meta_routine_col,
+ _gda_web_meta__routine_par,
+ _gda_web_meta_routine_par,
+ _gda_web_meta__indexes_tab,
+ _gda_web_meta_indexes_tab,
+ _gda_web_meta__index_cols,
+ _gda_web_meta_index_cols,
+
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* padding */
+};
+
static void
gda_web_provider_class_init (GdaWebProviderClass *klass)
{
@@ -135,96 +219,18 @@ gda_web_provider_class_init (GdaWebProviderClass *klass)
parent_class = g_type_class_peek_parent (klass);
- provider_class->get_version = gda_web_provider_get_version;
- provider_class->get_server_version = gda_web_provider_get_server_version;
- provider_class->get_name = gda_web_provider_get_name;
- provider_class->supports_feature = gda_web_provider_supports_feature;
-
- provider_class->get_data_handler = gda_web_provider_get_data_handler;
- provider_class->get_def_dbms_type = gda_web_provider_get_default_dbms_type;
-
- provider_class->open_connection = gda_web_provider_open_connection;
- provider_class->close_connection = gda_web_provider_close_connection;
- provider_class->get_database = NULL;
-
- provider_class->supports_operation = gda_web_provider_supports_operation;
- provider_class->create_operation = gda_web_provider_create_operation;
- provider_class->render_operation = gda_web_provider_render_operation;
- provider_class->perform_operation = gda_web_provider_perform_operation;
-
- provider_class->begin_transaction = gda_web_provider_begin_transaction;
- provider_class->commit_transaction = gda_web_provider_commit_transaction;
- provider_class->rollback_transaction = gda_web_provider_rollback_transaction;
- provider_class->add_savepoint = gda_web_provider_add_savepoint;
- provider_class->rollback_savepoint = gda_web_provider_rollback_savepoint;
- provider_class->delete_savepoint = gda_web_provider_delete_savepoint;
-
- provider_class->create_parser = gda_web_provider_create_parser;
- provider_class->statement_to_sql = NULL; /* don't use gda_web_provider_statement_to_sql()
- * because it only calls gda_statement_to_sql_extended() */
- provider_class->statement_prepare = gda_web_provider_statement_prepare;
- provider_class->statement_execute = gda_web_provider_statement_execute;
- provider_class->statement_rewrite = gda_web_statement_rewrite;
-
- provider_class->is_busy = NULL;
- provider_class->cancel = NULL;
- provider_class->create_connection = NULL;
-
- provider_class->identifier_quote = gda_web_identifier_quote;
-
- memset (&(provider_class->meta_funcs), 0, sizeof (GdaServerProviderMeta));
- provider_class->meta_funcs._info = _gda_web_meta__info;
- provider_class->meta_funcs._btypes = _gda_web_meta__btypes;
- provider_class->meta_funcs._udt = _gda_web_meta__udt;
- provider_class->meta_funcs.udt = _gda_web_meta_udt;
- provider_class->meta_funcs._udt_cols = _gda_web_meta__udt_cols;
- provider_class->meta_funcs.udt_cols = _gda_web_meta_udt_cols;
- provider_class->meta_funcs._enums = _gda_web_meta__enums;
- provider_class->meta_funcs.enums = _gda_web_meta_enums;
- provider_class->meta_funcs._domains = _gda_web_meta__domains;
- provider_class->meta_funcs.domains = _gda_web_meta_domains;
- provider_class->meta_funcs._constraints_dom = _gda_web_meta__constraints_dom;
- provider_class->meta_funcs.constraints_dom = _gda_web_meta_constraints_dom;
- provider_class->meta_funcs._el_types = _gda_web_meta__el_types;
- provider_class->meta_funcs.el_types = _gda_web_meta_el_types;
- provider_class->meta_funcs._collations = _gda_web_meta__collations;
- provider_class->meta_funcs.collations = _gda_web_meta_collations;
- provider_class->meta_funcs._character_sets = _gda_web_meta__character_sets;
- provider_class->meta_funcs.character_sets = _gda_web_meta_character_sets;
- provider_class->meta_funcs._schemata = _gda_web_meta__schemata;
- provider_class->meta_funcs.schemata = _gda_web_meta_schemata;
- provider_class->meta_funcs._tables_views = _gda_web_meta__tables_views;
- provider_class->meta_funcs.tables_views = _gda_web_meta_tables_views;
- provider_class->meta_funcs._columns = _gda_web_meta__columns;
- provider_class->meta_funcs.columns = _gda_web_meta_columns;
- provider_class->meta_funcs._view_cols = _gda_web_meta__view_cols;
- provider_class->meta_funcs.view_cols = _gda_web_meta_view_cols;
- provider_class->meta_funcs._constraints_tab = _gda_web_meta__constraints_tab;
- provider_class->meta_funcs.constraints_tab = _gda_web_meta_constraints_tab;
- provider_class->meta_funcs._constraints_ref = _gda_web_meta__constraints_ref;
- provider_class->meta_funcs.constraints_ref = _gda_web_meta_constraints_ref;
- provider_class->meta_funcs._key_columns = _gda_web_meta__key_columns;
- provider_class->meta_funcs.key_columns = _gda_web_meta_key_columns;
- provider_class->meta_funcs._check_columns = _gda_web_meta__check_columns;
- provider_class->meta_funcs.check_columns = _gda_web_meta_check_columns;
- provider_class->meta_funcs._triggers = _gda_web_meta__triggers;
- provider_class->meta_funcs.triggers = _gda_web_meta_triggers;
- provider_class->meta_funcs._routines = _gda_web_meta__routines;
- provider_class->meta_funcs.routines = _gda_web_meta_routines;
- provider_class->meta_funcs._routine_col = _gda_web_meta__routine_col;
- provider_class->meta_funcs.routine_col = _gda_web_meta_routine_col;
- provider_class->meta_funcs._routine_par = _gda_web_meta__routine_par;
- provider_class->meta_funcs.routine_par = _gda_web_meta_routine_par;
- provider_class->meta_funcs._indexes_tab = _gda_web_meta__indexes_tab;
- provider_class->meta_funcs.indexes_tab = _gda_web_meta_indexes_tab;
- provider_class->meta_funcs._index_cols = _gda_web_meta__index_cols;
- provider_class->meta_funcs.index_cols = _gda_web_meta_index_cols;
-
- /* distributed transactions: if not supported, then provider_class->xa_funcs should be set to NULL */
- provider_class->xa_funcs = NULL;
-
- /* provider is thread safe */
- provider_class->limiting_thread = NULL;
+ /* set virtual functions */
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_BASE,
+ (gpointer) &web_base_functions);
+
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_META,
+ (gpointer) &web_meta_functions);
+
+ gda_server_provider_set_impl_functions (GDA_SERVER_PROVIDER_CLASS (klass),
+ GDA_SERVER_PROVIDER_FUNCTIONS_XA,
+ (gpointer) NULL);
}
static void
@@ -259,6 +265,18 @@ gda_web_provider_get_type (void)
return type;
}
+static GdaWorker *
+gda_web_provider_create_worker (GdaServerProvider *provider)
+{
+ /* Let's assume for now that this provider is not thread safe... */
+ static GdaWorker *unique_worker = NULL;
+ if (unique_worker)
+ return gda_worker_ref (unique_worker);
+ else {
+ unique_worker = gda_worker_new ();
+ return gda_worker_ref (unique_worker);
+ }
+}
/*
* Get provider name request
@@ -331,19 +349,11 @@ do_server_setup (GdaConnection *cnc, WebConnectionData *cdata)
*/
static gboolean
gda_web_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
- GdaQuarkList *params, GdaQuarkList *auth,
- G_GNUC_UNUSED guint *task_id, GdaServerProviderAsyncCallback async_cb,
- G_GNUC_UNUSED gpointer cb_data)
+ GdaQuarkList *params, GdaQuarkList *auth)
{
g_return_val_if_fail (GDA_IS_WEB_PROVIDER (provider), FALSE);
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
- /* If asynchronous connection opening is not supported, then exit now */
- if (async_cb) {
- gda_connection_add_event_string (cnc, _("Provider does not support asynchronous connection
open"));
- return FALSE;
- }
-
/* Check for connection parameters */
const gchar *db_name, *host, *path, *port, *serversecret, *pass = NULL, *use_ssl;
@@ -403,7 +413,7 @@ gda_web_provider_open_connection (GdaServerProvider *provider, GdaConnection *cn
cdata->server_base_url = g_string_free (server_url, FALSE);
if (serversecret)
cdata->key = g_strdup (serversecret);
- gda_connection_internal_set_provider_data (cnc, cdata, (GDestroyNotify) _gda_web_free_cnc_data);
+ gda_connection_internal_set_provider_data (cnc, (GdaServerProviderConnectionData*) cdata,
(GDestroyNotify) _gda_web_free_cnc_data);
/*
* perform setup
@@ -505,7 +515,7 @@ gda_web_provider_close_connection (GdaServerProvider *provider, GdaConnection *c
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
- cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (WebConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return FALSE;
@@ -561,7 +571,7 @@ gda_web_provider_get_server_version (GdaServerProvider *provider, GdaConnection
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
- cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (WebConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
return cdata->server_version;
@@ -674,19 +684,10 @@ gda_web_provider_render_operation (GdaServerProvider *provider, GdaConnection *c
*/
static gboolean
gda_web_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
- GdaServerOperation *op, G_GNUC_UNUSED guint *task_id,
- GdaServerProviderAsyncCallback async_cb, G_GNUC_UNUSED gpointer cb_data,
- GError **error)
+ GdaServerOperation *op, GError **error)
{
GdaServerOperationType optype;
- /* If asynchronous connection opening is not supported, then exit now */
- if (async_cb) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
- "%s", _("Provider does not support asynchronous server operation"));
- return FALSE;
- }
-
if (cnc) {
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
@@ -1074,7 +1075,7 @@ gda_web_provider_get_data_handler (GdaServerProvider *provider, GdaConnection *c
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
- cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (WebConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
}
if (!cdata)
return NULL;
@@ -1097,7 +1098,7 @@ gda_web_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConnecti
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
- cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (WebConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
}
if (!cdata)
return NULL;
@@ -1118,7 +1119,7 @@ gda_web_provider_create_parser (G_GNUC_UNUSED GdaServerProvider *provider, GdaCo
WebConnectionData *cdata = NULL;
if (cnc)
- cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (WebConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
if (!cdata)
return NULL;
if (cdata->reuseable && cdata->reuseable->operations->re_create_parser)
@@ -1384,9 +1385,7 @@ static GObject *
gda_web_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
GdaStatement *stmt, GdaSet *params,
GdaStatementModelUsage model_usage,
- GType *col_types, GdaSet **last_inserted_row,
- guint *task_id,
- GdaServerProviderExecCallback async_cb, gpointer cb_data, GError **error)
+ GType *col_types, GdaSet **last_inserted_row, GError **error)
{
GdaWebPStmt *ps;
WebConnectionData *cdata;
@@ -1398,13 +1397,6 @@ gda_web_provider_statement_execute (GdaServerProvider *provider, GdaConnection *
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
- /* If asynchronous connection opening is not supported, then exit now */
- if (async_cb) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
- "%s", _("Provider does not support asynchronous statement execution"));
- return NULL;
- }
-
allow_noparam = (model_usage & GDA_STATEMENT_MODEL_ALLOW_NOPARAM) &&
(gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT);
@@ -1560,9 +1552,7 @@ gda_web_provider_statement_execute (GdaServerProvider *provider, GdaConnection *
res = gda_web_provider_statement_execute (provider, cnc,
rstmt, params,
model_usage,
- col_types, last_inserted_row,
- task_id,
- async_cb, cb_data, error);
+ col_types, last_inserted_row, error);
g_object_unref (rstmt);
return res;
}
@@ -1615,9 +1605,7 @@ gda_web_provider_statement_execute (GdaServerProvider *provider, GdaConnection *
rstmt, params,
model_usage,
col_types,
- last_inserted_row,
- task_id, async_cb,
- cb_data, error);
+ last_inserted_row, error);
/* clear original @param_ids and restore copied one */
g_slist_foreach (prep_param_ids, (GFunc) g_free, NULL);
g_slist_free (prep_param_ids);
@@ -1757,8 +1745,8 @@ gda_web_provider_statement_execute (GdaServerProvider *provider, GdaConnection *
* Removes any default value inserted or updated
*/
static GdaSqlStatement *
-gda_web_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
- GdaStatement *stmt, GdaSet *params, GError **error)
+gda_web_provider_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error)
{
if (cnc) {
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
@@ -1768,9 +1756,9 @@ gda_web_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
}
static gchar *
-gda_web_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
- const gchar *id,
- gboolean for_meta_store, gboolean force_quotes)
+gda_web_provider_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
+ const gchar *id,
+ gboolean for_meta_store, gboolean force_quotes)
{
WebConnectionData *cdata = NULL;
@@ -1778,7 +1766,7 @@ gda_web_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
- cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ cdata = (WebConnectionData*) gda_connection_internal_get_provider_data_error (cnc, NULL);
}
if (!cdata)
return gda_sql_identifier_quote (id, NULL, NULL, for_meta_store, force_quotes);
diff --git a/providers/web/gda-web-pstmt.c b/providers/web/gda-web-pstmt.c
index dd75629..cf0def6 100644
--- a/providers/web/gda-web-pstmt.c
+++ b/providers/web/gda-web-pstmt.c
@@ -90,7 +90,7 @@ gda_web_pstmt_finalize (GObject *object)
if (pstmt->pstmt_hash) {
WebConnectionData *cdata;
- cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (pstmt->cnc);
+ cdata = (WebConnectionData*) gda_connection_internal_get_provider_data_error (pstmt->cnc,
NULL);
if (!cdata)
goto next;
diff --git a/providers/web/gda-web-util.c b/providers/web/gda-web-util.c
index c1169e1..0222f77 100644
--- a/providers/web/gda-web-util.c
+++ b/providers/web/gda-web-util.c
@@ -625,7 +625,7 @@ void
_gda_web_change_connection_to_closed (GdaConnection *cnc, WebConnectionData *cdata)
{
cdata->forced_closing = TRUE;
- gda_connection_close_no_warning (cnc);
+ gda_connection_close (cnc, NULL);
}
/*
diff --git a/providers/web/gda-web.h b/providers/web/gda-web.h
index f58801f..814e7a5 100644
--- a/providers/web/gda-web.h
+++ b/providers/web/gda-web.h
@@ -32,12 +32,14 @@
#include <libsoup/soup.h>
#include <libgda/gda-mutex.h>
#include <libgda/gda-connection.h>
+#include <libgda/gda-connection-private.h>
#include "../reuseable/gda-provider-reuseable.h"
/*
* Provider's specific connection data
*/
typedef struct {
+ GdaServerProviderConnectionData parent;
GdaProviderReuseable *reuseable; /* pointer to GdaProviderReuseable, not inherited! */
GdaMutex *mutex; /* protected access */
diff --git a/samples/DirDataModel/find-duplicates.c b/samples/DirDataModel/find-duplicates.c
index e5bfe27..dd80829 100644
--- a/samples/DirDataModel/find-duplicates.c
+++ b/samples/DirDataModel/find-duplicates.c
@@ -115,7 +115,7 @@ main (int argc, char *argv [])
/* set up virtual environment */
provider = gda_vprovider_data_model_new ();
- cnc = gda_virtual_connection_open (provider, NULL);
+ cnc = gda_virtual_connection_open (provider, GDA_CONNECTION_OPTIONS_NONE, NULL);
model = gda_data_model_dir_new (dirname);
g_print ("Finding duplicates among %d files\n", gda_data_model_get_n_rows (model));
diff --git a/samples/F-Spot/repair-path.c b/samples/F-Spot/repair-path.c
index e9dcfd3..b995cf7 100644
--- a/samples/F-Spot/repair-path.c
+++ b/samples/F-Spot/repair-path.c
@@ -112,7 +112,7 @@ main (int argc, char *argv [])
/* Set up Connection hub */
provider = gda_vprovider_hub_new ();
- hub = gda_virtual_connection_open (provider, NULL);
+ hub = gda_virtual_connection_open (provider, GDA_CONNECTION_OPTIONS_NONE, NULL);
g_assert (hub);
if (!gda_vconnection_hub_add (GDA_VCONNECTION_HUB (hub), cnc, "spot", &error)) {
diff --git a/samples/TableCopy/table-copy-easier.c b/samples/TableCopy/table-copy-easier.c
index 27b51b1..2546c5e 100644
--- a/samples/TableCopy/table-copy-easier.c
+++ b/samples/TableCopy/table-copy-easier.c
@@ -37,7 +37,7 @@ main (int argc, char *argv[])
GdaVirtualProvider *provider;
GError *error = NULL;
provider = gda_vprovider_hub_new ();
- virtual = gda_virtual_connection_open (provider, NULL);
+ virtual = gda_virtual_connection_open (provider, GDA_CONNECTION_OPTIONS_NONE, NULL);
/* adding connections to the virtual connection */
if (!gda_vconnection_hub_add (GDA_VCONNECTION_HUB (virtual), s_cnc, "source", &error)) {
diff --git a/samples/Virtual/virtual-test.c b/samples/Virtual/virtual-test.c
index 7248450..7b27234 100644
--- a/samples/Virtual/virtual-test.c
+++ b/samples/Virtual/virtual-test.c
@@ -35,7 +35,7 @@ main ()
gda_init ();
provider = gda_vprovider_data_model_new ();
- cnc = gda_virtual_connection_open (provider, NULL);
+ cnc = gda_virtual_connection_open (provider, GDA_CONNECTION_OPTIONS_NONE, NULL);
g_assert (cnc);
/* create RW data model to store results */
diff --git a/testing/Makefile.am b/testing/Makefile.am
index c5b808f..91be38d 100644
--- a/testing/Makefile.am
+++ b/testing/Makefile.am
@@ -11,7 +11,7 @@ bin_PROGRAMS = gda-test-connection-5.0
if HAVE_UI
UI_PROGS=gdaui-test-data-entries gdaui-test-widget-entry gdaui-test-errors gdaui-test-rt-editor
endif
-noinst_PROGRAMS = gda-test-blob gda-provider-status virtual-test virtual-test-2 $(UI_PROGS)
+noinst_PROGRAMS = gda-test-blob virtual-test virtual-test-2 $(UI_PROGS)
gda_test_connection_5_0_SOURCES = \
gda-test-connection.c
diff --git a/testing/gda-test-blob.c b/testing/gda-test-blob.c
index fdcb61b..6a612df 100644
--- a/testing/gda-test-blob.c
+++ b/testing/gda-test-blob.c
@@ -184,7 +184,8 @@ main (int argc, char **argv)
*/
gda_connection_commit_transaction (cnc, NULL, NULL);
- gda_connection_close (cnc);
+ if (! gda_connection_close (cnc, &error))
+ g_error ("Can't close connection: %s", error && error->message ? error->message : "No
detail");
return 0;
}
diff --git a/testing/gda-test-connection.c b/testing/gda-test-connection.c
index 508400f..aa2bb77 100644
--- a/testing/gda-test-connection.c
+++ b/testing/gda-test-connection.c
@@ -105,7 +105,11 @@ main (int argc, char **argv)
g_free (auth_string);
g_print (_("Connection successfully opened!\n"));
- gda_connection_close (cnc);
+ if (! gda_connection_close (cnc, &error)) {
+ g_warning (_("Can't close connection: %s\n"),
+ error && error->message ? error->message : "???");
+ exit (1);
+ }
return 0;
}
diff --git a/testing/virtual-test-2.c b/testing/virtual-test-2.c
index 8d24d86..cc8df50 100644
--- a/testing/virtual-test-2.c
+++ b/testing/virtual-test-2.c
@@ -52,7 +52,7 @@ main ()
/* Set up Connection hub */
provider = gda_vprovider_hub_new ();
- hub = gda_virtual_connection_open (provider, NULL);
+ hub = gda_virtual_connection_open (provider, GDA_CONNECTION_OPTIONS_NONE, NULL);
g_assert (hub);
if (!gda_vconnection_hub_add (GDA_VCONNECTION_HUB (hub), cnc, "sales", &error)) {
diff --git a/testing/virtual-test.c b/testing/virtual-test.c
index a62b93c..40ecd23 100644
--- a/testing/virtual-test.c
+++ b/testing/virtual-test.c
@@ -40,7 +40,7 @@ main ()
parser = gda_sql_parser_new ();
provider = gda_vprovider_data_model_new ();
- cnc = gda_virtual_connection_open (provider, NULL);
+ cnc = gda_virtual_connection_open (provider, GDA_CONNECTION_OPTIONS_NONE, NULL);
g_assert (GDA_IS_VCONNECTION_DATA_MODEL (cnc));
g_print ("Connection status for %s: %s\n", G_OBJECT_TYPE_NAME (cnc),
diff --git a/tests/data-models/check_data_proxy.c b/tests/data-models/check_data_proxy.c
index 09f80d5..a48180e 100644
--- a/tests/data-models/check_data_proxy.c
+++ b/tests/data-models/check_data_proxy.c
@@ -1431,7 +1431,7 @@ wait_for_signals (void)
if (!defer_sync)
return;
- ms = ((expected_signals->len / 5)+1) * 75; /* nice heuristic, heu? */
+ ms = ((expected_signals->len / 5)+1) * 100; /* nice heuristic, heu? */
loop = g_main_loop_new (NULL, FALSE);
#ifdef CHECK_EXTRA_INFO
g_print ("Waiting %d ms...\n", ms);
diff --git a/tests/data-models/check_model_errors.c b/tests/data-models/check_model_errors.c
index 24faf6b..b4b37c4 100644
--- a/tests/data-models/check_model_errors.c
+++ b/tests/data-models/check_model_errors.c
@@ -336,7 +336,7 @@ test2 (GdaConnection *cnc)
GdaDataModelIter *iter = NULL;
GdaStatement *stmt;
virtual_provider = gda_vprovider_data_model_new ();
- vcnc = gda_virtual_connection_open (virtual_provider, &lerror);
+ vcnc = gda_virtual_connection_open (virtual_provider, GDA_CONNECTION_OPTIONS_NONE, &lerror);
if (!vcnc) {
#ifdef CHECK_EXTRA_INFO
g_print ("Virtual ERROR: %s\n", lerror && lerror->message ? lerror->message : "No detail");
diff --git a/tests/data-models/check_vcnc.c b/tests/data-models/check_vcnc.c
index 9b8908b..6ba3a48 100644
--- a/tests/data-models/check_vcnc.c
+++ b/tests/data-models/check_vcnc.c
@@ -55,7 +55,7 @@ main (int argc, char *argv[])
gda_init ();
provider = gda_vprovider_hub_new ();
- virtual = gda_virtual_connection_open (provider, NULL);
+ virtual = gda_virtual_connection_open (provider, GDA_CONNECTION_OPTIONS_NONE, NULL);
g_assert (virtual);
/* load CSV data models */
@@ -96,8 +96,16 @@ main (int argc, char *argv[])
check_threads_select_random (virtual);
check_date (virtual);
- gda_connection_close (virtual);
- gda_connection_close (out_cnc);
+ if (! gda_connection_close (virtual, &error)) {
+ g_print ("gda_connection_close(virtual) error: %s\n",
+ error && error->message ? error->message : "No detail");
+ exit (1);
+ }
+ if (! gda_connection_close (out_cnc, &error)) {
+ g_print ("gda_connection_close(out_cnc) error: %s\n",
+ error && error->message ? error->message : "No detail");
+ exit (1);
+ }
g_print ("All Ok\n");
return 0;
@@ -109,15 +117,20 @@ open_destination_connection (void)
/* create connection */
GdaConnection *cnc;
GError *error = NULL;
- cnc = gda_connection_open_from_string ("SQLite", "DB_DIR=.;DB_NAME=vcnc",
- NULL,
- GDA_CONNECTION_OPTIONS_NONE,
- &error);
+ cnc = gda_connection_new_from_string ("SQLite", "DB_DIR=.;DB_NAME=vcnc",
+ NULL,
+ GDA_CONNECTION_OPTIONS_NONE,
+ &error);
if (!cnc) {
- g_print ("Could not open connection to local SQLite database: %s\n",
+ g_print ("Could not create connection to local SQLite database: %s\n",
error && error->message ? error->message : "No detail");
exit (1);
}
+ if (! gda_connection_open (cnc, &error)) {
+ g_print ("gda_connection_open() error: %s\n",
+ error && error->message ? error->message : "No detail");
+ exit (1);
+ }
/* table "cities" */
assert_run_sql_non_select (cnc, "DROP table IF EXISTS cities", NULL);
@@ -506,7 +519,7 @@ test_multiple_threads (GThreadFunc func, GdaConnection *virtual)
#ifdef DEBUG_PRINT
g_print ("Running thread %d\n", d->th_id);
#endif
- d->thread = g_thread_create (func, d, TRUE, NULL);
+ d->thread = g_thread_new ("For_test_multiple_threads", func, d);
}
for (i = 0; i < NTHREADS; i++) {
diff --git a/tests/data-models/check_virtual.c b/tests/data-models/check_virtual.c
index a51e2a4..6b491d0 100644
--- a/tests/data-models/check_virtual.c
+++ b/tests/data-models/check_virtual.c
@@ -59,7 +59,7 @@ test1 (void)
g_print ("===== %s() =====\n", __FUNCTION__);
provider = gda_vprovider_data_model_new ();
- cnc = gda_virtual_connection_open (provider, NULL);
+ cnc = gda_virtual_connection_open (provider, GDA_CONNECTION_OPTIONS_NONE, NULL);
g_assert (cnc);
/* create RW data model to store results */
@@ -137,7 +137,7 @@ test2 (void)
g_print ("===== %s () =====\n", __FUNCTION__);
provider = gda_vprovider_data_model_new ();
- cnc = gda_virtual_connection_open (provider, NULL);
+ cnc = gda_virtual_connection_open (provider, GDA_CONNECTION_OPTIONS_NONE, NULL);
g_assert (cnc);
/* load CSV data models */
diff --git a/tests/meta-store/common.c b/tests/meta-store/common.c
index cdf0ff0..a772f07 100644
--- a/tests/meta-store/common.c
+++ b/tests/meta-store/common.c
@@ -117,8 +117,7 @@ static void
meta_changed_cb (GdaMetaStore *store, GSList *changes, gpointer data)
{
GSList *gl;
- gint i;
- for (i = 0, gl = changes; gl; gl = gl->next) {
+ for (gl = changes; gl; gl = gl->next) {
gchar *gstr = stringify_a_change ((GdaMetaStoreChange *) gl->data);
if (!find_expected_change (gstr)) {
g_print ("Unexpected GdaMetaStoreChange: %s", gstr);
diff --git a/tests/multi-threading/Makefile.am b/tests/multi-threading/Makefile.am
index d18e155..04662e0 100644
--- a/tests/multi-threading/Makefile.am
+++ b/tests/multi-threading/Makefile.am
@@ -7,8 +7,8 @@ AM_CPPFLAGS = \
-DROOT_DIR=\""$(top_srcdir)"\"
TESTS_ENVIRONMENT = GDA_TOP_SRC_DIR="$(abs_top_srcdir)" GDA_TOP_BUILD_DIR="$(abs_top_builddir)"
-TESTS = check_mutex check_parser check_cnc_lock check_threaded_cnc check_wrapper
-check_PROGRAMS = check_mutex check_parser check_cnc_lock check_threaded_cnc check_wrapper
+TESTS = check_mutex check_parser check_cnc_lock
+check_PROGRAMS = check_mutex check_parser check_cnc_lock
common_sources = \
../test-errors.h \
@@ -31,16 +31,6 @@ check_cnc_lock_LDADD = \
$(top_builddir)/libgda/libgda-5.0.la \
$(COREDEPS_LIBS)
-check_threaded_cnc_SOURCES = check_threaded_cnc.c $(common_sources)
-check_threaded_cnc_LDADD = \
- $(top_builddir)/libgda/libgda-5.0.la \
- $(COREDEPS_LIBS)
-
-check_wrapper_SOURCES = check_wrapper.c dummy-object.c dummy-object.h
-check_wrapper_LDADD = \
- $(top_builddir)/libgda/libgda-5.0.la \
- $(COREDEPS_LIBS)
-
EXTRA_DIST = testdb.sql
DISTCLEANFILES = testdb.db storedb.db
diff --git a/tests/multi-threading/check_cnc_lock.c b/tests/multi-threading/check_cnc_lock.c
index d3567b0..5209a72 100644
--- a/tests/multi-threading/check_cnc_lock.c
+++ b/tests/multi-threading/check_cnc_lock.c
@@ -119,7 +119,6 @@ test_multiple_threads (GThreadFunc func, GError **error)
if (!cnc)
return FALSE;
- g_object_set (G_OBJECT (cnc), "thread-owner", g_thread_self (), NULL);
/* prepare threads data */
for (i = 0; i < NTHREADS; i++) {
@@ -153,7 +152,6 @@ test_multiple_threads (GThreadFunc func, GError **error)
gboolean retval = TRUE;
for (i = 0; i < NTHREADS; i++) {
ThData *d = &(data[i]);
- g_object_set (G_OBJECT (cnc), "thread-owner", d->thread, NULL);
g_thread_join (d->thread);
if (d->error)
retval = FALSE;
diff --git a/tests/multi-threading/common.c b/tests/multi-threading/common.c
index d0b339f..8e84305 100644
--- a/tests/multi-threading/common.c
+++ b/tests/multi-threading/common.c
@@ -86,7 +86,7 @@ create_sqlite_db (const gchar *dir, const gchar *dbname, const gchar *sqlfile, G
g_slist_foreach (list, (GFunc) g_object_unref, NULL);
g_slist_free (list);
- gda_connection_close (cnc);
+ g_assert (gda_connection_close (cnc, NULL));
g_object_unref (cnc);
g_object_unref (batch);
return retval;
diff --git a/tests/test-cnc-utils.c b/tests/test-cnc-utils.c
index 9b76d5f..21c2ed4 100644
--- a/tests/test-cnc-utils.c
+++ b/tests/test-cnc-utils.c
@@ -330,7 +330,7 @@ test_cnc_clean_connection (GdaConnection *cnc, GError **error)
g_assert (dbname);
dbname = g_strdup (dbname);
- gda_connection_close (cnc);
+ g_assert (gda_connection_close (cnc, NULL));
g_object_unref (cnc);
#ifdef CHECK_EXTRA_INFO
@@ -354,7 +354,7 @@ test_cnc_clean_connection (GdaConnection *cnc, GError **error)
}
else {
TO_IMPLEMENT;
- gda_connection_close (cnc);
+ g_assert (gda_connection_close (cnc, NULL));
g_object_unref (cnc);
}
g_free (upname);
diff --git a/tests/test-sql-renderer.c b/tests/test-sql-renderer.c
index d323919..f92f55b 100644
--- a/tests/test-sql-renderer.c
+++ b/tests/test-sql-renderer.c
@@ -20,8 +20,6 @@
#include <sql-parser/gda-sql-parser.h>
#include <string.h>
-#define PROV_CLASS(provider) (GDA_SERVER_PROVIDER_CLASS (G_OBJECT_GET_CLASS (provider)))
-
static gboolean
string_equal_to_template (const gchar *str, const gchar *tmpl)
{
@@ -59,6 +57,9 @@ GdaTime gt = {
};
+/*
+ * @prov may be NULL
+ */
static guint
do_a_test (GdaServerProvider *prov, GdaSqlParser *parser)
{
@@ -105,10 +106,24 @@ do_a_test (GdaServerProvider *prov, GdaSqlParser *parser)
goto endtest;
}
+ GdaConnection *cnc = NULL;
+ if (prov) {
+ cnc = gda_connection_new_from_string (gda_server_provider_get_name (prov),
"DB_NAME=dummy;HOST=dummy", NULL,
+ GDA_CONNECTION_OPTIONS_NONE, &error);
+ if (!cnc) {
+ g_print ("Failed to create GdaConnection object: %s\n",
+ error && error->message ? error->message : "No detail");
+ g_clear_error (&error);
+ g_object_unref (stmt);
+ g_object_unref (params);
+ nfailed ++;
+ goto endtest;
+ }
+ }
gchar *expected;
expected = "('@@@@@@@@@@ 17:10:23+2', '16:09:22-3')";
- if (prov && PROV_CLASS (prov)->statement_to_sql)
- sql = PROV_CLASS (prov)->statement_to_sql (prov, NULL, stmt, params, 0, NULL, &error);
+ if (cnc)
+ sql = gda_connection_statement_to_sql (cnc, stmt, params, 0, NULL, &error);
else
sql = gda_statement_to_sql_extended (stmt, NULL, params, 0, NULL, &error);
if (!sql) {
@@ -130,8 +145,8 @@ do_a_test (GdaServerProvider *prov, GdaSqlParser *parser)
g_free (sql);
expected = "('@@@@@@@@@@ 15:10:23', '19:09:22')";
- if (prov && PROV_CLASS (prov)->statement_to_sql)
- sql = PROV_CLASS (prov)->statement_to_sql (prov, NULL, stmt, params,
GDA_STATEMENT_SQL_TIMEZONE_TO_GMT, NULL, &error);
+ if (cnc)
+ sql = gda_connection_statement_to_sql (cnc, stmt, params, GDA_STATEMENT_SQL_TIMEZONE_TO_GMT,
NULL, &error);
else
sql = gda_statement_to_sql_extended (stmt, NULL, params, GDA_STATEMENT_SQL_TIMEZONE_TO_GMT,
NULL, &error);
if (!sql) {
@@ -190,8 +205,8 @@ do_a_test (GdaServerProvider *prov, GdaSqlParser *parser)
}
expected = "('@@@@@@@@@@ 17:10:23+2', '16:09:22-3')";
- if (prov && PROV_CLASS (prov)->statement_to_sql)
- sql = PROV_CLASS (prov)->statement_to_sql (prov, NULL, stmt, params, 0, NULL, &error);
+ if (cnc)
+ sql = gda_connection_statement_to_sql (cnc, stmt, params, 0, NULL, &error);
else
sql = gda_statement_to_sql_extended (stmt, NULL, params, 0, NULL, &error);
if (!sql) {
@@ -213,8 +228,8 @@ do_a_test (GdaServerProvider *prov, GdaSqlParser *parser)
g_free (sql);
expected = "('@@@@@@@@@@ 15:10:23', '19:09:22')";
- if (prov && PROV_CLASS (prov)->statement_to_sql)
- sql = PROV_CLASS (prov)->statement_to_sql (prov, NULL, stmt, params,
GDA_STATEMENT_SQL_TIMEZONE_TO_GMT, NULL, &error);
+ if (cnc)
+ sql = gda_connection_statement_to_sql (cnc, stmt, params, GDA_STATEMENT_SQL_TIMEZONE_TO_GMT,
NULL, &error);
else
sql = gda_statement_to_sql_extended (stmt, NULL, params, GDA_STATEMENT_SQL_TIMEZONE_TO_GMT,
NULL, &error);
if (!sql) {
diff --git a/tools/browser/auth-dialog.c b/tools/browser/auth-dialog.c
index d15d866..9ee21d7 100644
--- a/tools/browser/auth-dialog.c
+++ b/tools/browser/auth-dialog.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 - 2012 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2009 - 2014 Vivien Malerba <malerba gnome-db org>
* Copyright (C) 2010 David King <davidk openismus com>
* Copyright (C) 2011 Murray Cumming <murrayc murrayc com>
*
@@ -24,7 +24,6 @@
#include "auth-dialog.h"
#include "browser-spinner.h"
#include "support.h"
-#include <libgda/thread-wrapper/gda-thread-wrapper.h>
/*
* Main static functions
@@ -42,7 +41,6 @@ typedef struct {
GtkWidget *auth_widget;
GString *auth_string;
- GdaThreadWrapper *wrapper;
guint jobid;
} AuthData;
@@ -58,7 +56,6 @@ auth_data_free (AuthData *ad)
if (ad->auth_string)
g_string_free (ad->auth_string, TRUE);
- g_object_unref (ad->wrapper);
if (ad->ext.cnc_open_error)
g_error_free (ad->ext.cnc_open_error);
if (ad->ext.cnc)
@@ -289,70 +286,59 @@ auth_dialog_new (GtkWindow *parent)
"border-width", 10, NULL);
}
-/*
- * executed in a sub thread
- */
-static GdaConnection *
-sub_thread_open_cnc (AuthData *ad, GError **error)
+static void
+cnc_opened_cb (GdaConnection *cnc, guint job_id, gboolean result, GError *error, AuthDialog *dialog)
{
-#ifndef DUMMY
- GdaConnection *cnc;
- GdaDsnInfo *info = &(ad->cncinfo);
- if (info->name)
- cnc = gda_connection_open_from_dsn (info->name, ad->auth_string ? ad->auth_string->str : NULL,
- GDA_CONNECTION_OPTIONS_THREAD_SAFE |
- GDA_CONNECTION_OPTIONS_AUTO_META_DATA,
- error);
- else
- cnc = gda_connection_open_from_string (info->provider, info->cnc_string,
- ad->auth_string ? ad->auth_string->str : NULL,
- GDA_CONNECTION_OPTIONS_THREAD_SAFE |
- GDA_CONNECTION_OPTIONS_AUTO_META_DATA,
- error);
+ if (result) {
#ifdef HAVE_LDAP
- if (cnc && GDA_IS_LDAP_CONNECTION (cnc)) {
- /* force classes init */
- gda_ldap_get_class_info (GDA_LDAP_CONNECTION (cnc), "top");
- }
-#endif
- return cnc;
-#else /* DUMMY defined */
- sleep (5);
- g_set_error (error, GDA_TOOLS_ERROR, TOOLS_INTERNAL_COMMAND_ERROR, "%s", "Dummy error!");
- return NULL;
+ if (cnc && GDA_IS_LDAP_CONNECTION (cnc)) {
+ /* force classes init */
+ gda_ldap_get_class_info (GDA_LDAP_CONNECTION (cnc), "top");
+ }
#endif
-}
+ }
-static gboolean
-check_for_cnc (AuthDialog *dialog)
-{
GSList *list;
gboolean finished = TRUE;
for (list = dialog->priv->auth_list; list; list = list->next) {
AuthData *ad = (AuthData*) list->data;
- if (ad->jobid) {
- GError *lerror = NULL;
- ad->ext.cnc = gda_thread_wrapper_fetch_result (ad->wrapper, FALSE, ad->jobid,
&lerror);
- if (ad->ext.cnc || (!ad->ext.cnc && lerror)) {
- /* waiting is finished! */
- if (ad->ext.cnc)
- g_object_set (ad->ext.cnc, "monitor-wrapped-in-mainloop", TRUE, NULL);
- if (lerror)
- ad->ext.cnc_open_error = lerror;
- ad->jobid = 0;
+ g_print ("%s (job => %u, result => %d)\n", __FUNCTION__, job_id, result);
+ if (ad->jobid == job_id) {
+ if (!result) {
+ g_object_unref (ad->ext.cnc);
+ ad->ext.cnc = NULL;
+ if (error)
+ ad->ext.cnc_open_error = g_error_copy (error);
}
- else
- finished = FALSE;
+ ad->jobid = 0;
}
+ else if (ad->jobid)
+ finished = FALSE;
}
+}
- if (finished) {
- dialog->priv->source_id = 0;
- if (dialog->priv->loop)
- g_main_loop_quit (dialog->priv->loop);
- }
- return !finished;
+static void
+real_connection_open (AuthDialog *dialog, AuthData *ad)
+{
+#ifndef DUMMY
+ GdaConnection *cnc;
+ GdaDsnInfo *info = &(ad->cncinfo);
+ if (info->name)
+ ad->ext.cnc = gda_connection_new_from_dsn (info->name, ad->auth_string ? ad->auth_string->str
: NULL,
+ GDA_CONNECTION_OPTIONS_AUTO_META_DATA,
+ &(ad->ext.cnc_open_error));
+ else
+ ad->ext.cnc = gda_connection_new_from_string (info->provider, info->cnc_string,
+ ad->auth_string ? ad->auth_string->str : NULL,
+ GDA_CONNECTION_OPTIONS_AUTO_META_DATA,
+ &(ad->ext.cnc_open_error));
+ ad->jobid = gda_connection_open_async (ad->ext.cnc, (GdaConnectionOpenFunc*) cnc_opened_cb, dialog,
+ &(ad->ext.cnc_open_error));
+#else /* DUMMY defined */
+ sleep (5);
+ g_set_error (&(ad->ext.cnc_open_error), GDA_TOOLS_ERROR, TOOLS_INTERNAL_COMMAND_ERROR, "%s", "Dummy
error!");
+#endif
}
static void
@@ -452,8 +438,6 @@ auth_dialog_add_cnc_string (AuthDialog *dialog, const gchar *cnc_string, GError
AuthData *ad;
ad = g_new0 (AuthData, 1);
- ad->wrapper = gda_thread_wrapper_new ();
- /*g_print ("Auth dialog: new thread wrapper %p\n", ad->wrapper);*/
ad->ext.cnc_string = g_strdup (cnc_string);
ad->auth_string = NULL;
info = gda_config_get_dsn_info (real_cnc);
@@ -570,14 +554,7 @@ auth_dialog_add_cnc_string (AuthDialog *dialog, const gchar *cnc_string, GError
}
else {
/* open connection right away */
- ad->jobid = gda_thread_wrapper_execute (ad->wrapper,
- (GdaThreadWrapperFunc) sub_thread_open_cnc,
- (gpointer) ad,
- (GDestroyNotify) NULL,
- &(ad->ext.cnc_open_error));
- if (dialog->priv->source_id == 0) {
- dialog->priv->source_id = g_timeout_add (200, (GSourceFunc) check_for_cnc, dialog);
- }
+ real_connection_open (dialog, ad);
}
g_free (real_cnc_string);
@@ -678,15 +655,7 @@ auth_dialog_run (AuthDialog *dialog)
}
}
gtk_widget_set_sensitive (ad->auth_widget, FALSE);
- ad->jobid = gda_thread_wrapper_execute (ad->wrapper,
- (GdaThreadWrapperFunc)
sub_thread_open_cnc,
- (gpointer) ad,
- (GDestroyNotify) NULL,
- &(ad->ext.cnc_open_error));
- if (dialog->priv->source_id == 0) {
- dialog->priv->source_id =
- g_timeout_add (200, (GSourceFunc) check_for_cnc,
dialog);
- }
+ real_connection_open (dialog, ad);
}
}
diff --git a/tools/browser/browser-connection-priv.h b/tools/browser/browser-connection-priv.h
index 2786b20..286f252 100644
--- a/tools/browser/browser-connection-priv.h
+++ b/tools/browser/browser-connection-priv.h
@@ -19,18 +19,7 @@
#ifndef __BROWSER_CONNECTION_PRIVATE_H__
#define __BROWSER_CONNECTION_PRIVATE_H__
-#include <libgda/thread-wrapper/gda-thread-wrapper.h>
-
struct _BrowserConnectionPrivate {
- GdaThreadWrapper *wrapper;
- GIOChannel *ioc;
- guint ioc_watch_id;
- GSList *wrapper_jobs;
- guint wrapper_results_timer;
- gboolean long_timer;
- gint nb_no_job_waits; /* number of times check_for_wrapper_result() has been
- called without any job */
-
GHashTable *executed_statements; /* key = guint exec ID, value = a StatementResult pointer */
gulong meta_store_signal;
@@ -42,10 +31,7 @@ struct _BrowserConnectionPrivate {
GdaSqlParser *parser;
GdaDsnInfo dsn_info;
- GMutex mstruct_mutex;
- GSList *p_mstruct_list; /* private GdaMetaStruct list: while they are being created */
- GdaMetaStruct *c_mstruct; /* last GdaMetaStruct up to date, ready to be passed as @mstruct */
- GdaMetaStruct *mstruct; /* public GdaMetaStruct: once it has been created and is no more modified */
+ GdaMetaStruct *mstruct;
ToolsFavorites *bfav;
@@ -55,9 +41,6 @@ struct _BrowserConnectionPrivate {
GdaConnection *store_cnc;
GdaSet *variables;
-
- GSList *results_list; /* list of #ExecCallbackData pointers */
- gulong results_timer_id;
};
void browser_connection_set_busy_state (BrowserConnection *bcnc, gboolean busy, const gchar *busy_reason);
diff --git a/tools/browser/browser-connection.c b/tools/browser/browser-connection.c
index 711de62..346bc0f 100644
--- a/tools/browser/browser-connection.c
+++ b/tools/browser/browser-connection.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 - 2013 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2009 - 2014 Vivien Malerba <malerba gnome-db org>
* Copyright (C) 2010 David King <davidk openismus com>
* Copyright (C) 2010 Murray Cumming <murrayc murrayc com>
*
@@ -22,7 +22,6 @@
#include <glib/gi18n-lib.h>
#include "../tool-utils.h"
#include "browser-connection.h"
-#include <libgda/thread-wrapper/gda-thread-wrapper.h>
#include "support.h"
#include "marshal.h"
#include <sql-parser/gda-sql-parser.h>
@@ -37,23 +36,6 @@
#define CHECK_RESULTS_SHORT_TIMER 200
#define CHECK_RESULTS_LONG_TIMER 2
-typedef struct {
- GObject *result;
- GError *error;
- GdaSet *last_inserted_row;
-} StatementResult;
-
-static void
-statement_result_free (StatementResult *res)
-{
- if (res->result)
- g_object_unref (res->result);
- if (res->last_inserted_row)
- g_object_unref (res->last_inserted_row);
- g_clear_error (&(res->error));
- g_free (res);
-}
-
/* signals */
enum {
BUSY,
@@ -66,130 +48,6 @@ enum {
gint browser_connection_signals [LAST_SIGNAL] = { 0, 0, 0, 0, 0 };
-/* wrapper jobs handling */
-static gboolean check_for_wrapper_result (BrowserConnection *bcnc);
-
-typedef enum {
- JOB_TYPE_META_STORE_UPDATE,
- JOB_TYPE_META_STRUCT_SYNC,
- JOB_TYPE_STATEMENT_EXECUTE,
- JOB_TYPE_CALLBACK
-} JobType;
-
-typedef struct {
- guint job_id;
- JobType job_type;
- gchar *reason;
-
- /* the following may be %NULL for stmt execution and meta store updates */
- BrowserConnectionJobCallback callback;
- gpointer cb_data;
-} WrapperJob;
-
-static void
-wrapper_job_free (WrapperJob *wj)
-{
- g_free (wj->reason);
- g_free (wj);
-}
-
-#ifdef GDA_DEBUG_MUTEX
-static void
-my_lock (GMutex *mutex, gint where)
-{
- GTimer *timer;
- g_print ("wait to lock %p (th %p)@line %d\n", mutex, g_thread_self(), where);
- timer = g_timer_new ();
- g_mutex_lock (mutex);
- g_timer_stop (timer);
-
- if (g_timer_elapsed (timer, NULL) > 2.0)
- g_print ("WARN: locking %p (th %p)@line %d: %02f\n", mutex, g_thread_self(), where,
- g_timer_elapsed (timer, NULL));
- g_print ("tmp LOC %p (th %p)@line %d took %02f\n", mutex, g_thread_self(), where,
- g_timer_elapsed (timer, NULL));
- g_timer_destroy (timer);
-}
-static void
-my_unlock (GMutex *mutex, gint where)
-{
- g_mutex_unlock (mutex);
- g_print ("tmp UNL %p (th %p)@line %d\n", mutex, g_thread_self(), where);
-}
-
- #define MUTEX_LOCK(bcnc) g_mutex_lock (&((bcnc)->priv->mstruct_mutex))
- #define MUTEX_UNLOCK(bcnc) g_mutex_unlock (&((bcnc)->priv->mstruct_mutex))
-#else /* GDA_DEBUG_MUTEX */
- #define MUTEX_LOCK(bcnc) g_mutex_lock (&((bcnc)->priv->mstruct_mutex))
- #define MUTEX_UNLOCK(bcnc) g_mutex_unlock (&((bcnc)->priv->mstruct_mutex))
-#endif /* GDA_DEBUG_MUTEX */
-
-/*
- * Returns: %TRUE if current timer should be removed
- */
-static gboolean
-setup_results_timer (BrowserConnection *bcnc)
-{
- gboolean short_timer = TRUE;
-
- if (bcnc->priv->ioc_watch_id != 0)
- return FALSE; /* nothing to do, we use notifications */
-
- bcnc->priv->nb_no_job_waits ++;
- if (bcnc->priv->nb_no_job_waits > 100)
- short_timer = FALSE;
-
- if ((bcnc->priv->wrapper_results_timer > 0) &&
- (bcnc->priv->long_timer != short_timer))
- return FALSE; /* nothing to do, timer already correctlyset up */
-
- /* switch to a short/long timer to check for results */
- if (bcnc->priv->long_timer == short_timer)
- g_source_remove (bcnc->priv->wrapper_results_timer);
-
- bcnc->priv->long_timer = !short_timer;
- bcnc->priv->wrapper_results_timer = g_timeout_add (short_timer ? CHECK_RESULTS_SHORT_TIMER :
CHECK_RESULTS_LONG_TIMER,
- (GSourceFunc) check_for_wrapper_result,
- bcnc);
- bcnc->priv->nb_no_job_waits = 0;
- return TRUE;
-}
-
-/*
- * Pushes a job which has been asked to be exected in a sub thread using gda_thread_wrapper_execute()
- */
-static void
-push_wrapper_job (BrowserConnection *bcnc, guint job_id, JobType job_type, const gchar *reason,
- BrowserConnectionJobCallback callback, gpointer cb_data)
-{
- /* handle timers if necessary */
- setup_results_timer (bcnc);
-
- /* add WrapperJob structure */
- WrapperJob *wj;
- wj = g_new0 (WrapperJob, 1);
- wj->job_id = job_id;
- wj->job_type = job_type;
- if (reason)
- wj->reason = g_strdup (reason);
- wj->callback = callback;
- wj->cb_data = cb_data;
-
- bcnc->priv->wrapper_jobs = g_slist_append (bcnc->priv->wrapper_jobs, wj);
-
- if (! bcnc->priv->wrapper_jobs->next)
- g_signal_emit (bcnc, browser_connection_signals [BUSY], 0, TRUE, wj->reason);
-}
-
-static void
-pop_wrapper_job (BrowserConnection *bcnc, WrapperJob *wj)
-{
- bcnc->priv->wrapper_jobs = g_slist_remove (bcnc->priv->wrapper_jobs, wj);
- wrapper_job_free (wj);
- g_signal_emit (bcnc, browser_connection_signals [BUSY], 0, FALSE, NULL);
-}
-
-
/*
* Main static functions
*/
@@ -307,77 +165,11 @@ browser_connection_class_init (BrowserConnectionClass *klass)
object_class->dispose = browser_connection_dispose;
}
-static gboolean
-wrapper_ioc_cb (GIOChannel *source, GIOCondition condition, BrowserConnection *bcnc)
-{
- GIOStatus status;
- gsize nread;
- GdaThreadNotification notif;
-
- g_assert (source == bcnc->priv->ioc);
-//#define DEBUG_POLLING_SWITCH
-#ifdef DEBUG_POLLING_SWITCH
- static guint c = 0;
- c++;
- if (c == 4)
- goto onerror;
-#endif
- if (condition & G_IO_IN) {
- status = g_io_channel_read_chars (bcnc->priv->ioc, (gchar*) ¬if, sizeof (notif),
- &nread, NULL);
- if ((status != G_IO_STATUS_NORMAL) || (nread != sizeof (notif)))
- goto onerror;
-
- switch (notif.type) {
- case GDA_THREAD_NOTIFICATION_JOB:
- check_for_wrapper_result (bcnc);
- break;
- case GDA_THREAD_NOTIFICATION_SIGNAL:
- gda_thread_wrapper_iterate (bcnc->priv->wrapper, FALSE);
- break;
- default:
- /* an error occurred somewhere */
- goto onerror;
- }
- }
- if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
- goto onerror;
-
- return TRUE; /* keep callback */
-
- onerror:
-#ifdef GDA_DEBUG
- g_print ("Switching to polling instead of notifications...\n");
-#endif
- g_source_remove (bcnc->priv->ioc_watch_id);
- bcnc->priv->ioc_watch_id = 0;
- g_io_channel_shutdown (bcnc->priv->ioc, FALSE, NULL);
- g_io_channel_unref (bcnc->priv->ioc);
- bcnc->priv->ioc = NULL;
-
- setup_results_timer (bcnc);
- return FALSE; /* remove callback */
-}
-
static void
browser_connection_init (BrowserConnection *bcnc)
{
static guint index = 1;
bcnc->priv = g_new0 (BrowserConnectionPrivate, 1);
- bcnc->priv->wrapper = gda_thread_wrapper_new ();
- bcnc->priv->ioc = gda_thread_wrapper_get_io_channel (bcnc->priv->wrapper);
- if (bcnc->priv->ioc) {
- g_io_channel_ref (bcnc->priv->ioc);
- bcnc->priv->ioc_watch_id = g_io_add_watch (bcnc->priv->ioc,
- G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- (GIOFunc) wrapper_ioc_cb, bcnc);
- }
- else
- bcnc->priv->ioc_watch_id = 0;
- bcnc->priv->wrapper_jobs = NULL;
- bcnc->priv->wrapper_results_timer = 0;
- bcnc->priv->long_timer = FALSE;
- bcnc->priv->nb_no_job_waits = 0;
bcnc->priv->executed_statements = NULL;
bcnc->priv->name = g_strdup_printf (_("c%u"), index++);
@@ -385,12 +177,10 @@ browser_connection_init (BrowserConnection *bcnc)
bcnc->priv->parser = NULL;
bcnc->priv->variables = NULL;
memset (&(bcnc->priv->dsn_info), 0, sizeof (GdaDsnInfo));
- g_mutex_init (&bcnc->priv->mstruct_mutex);
- bcnc->priv->p_mstruct_list = NULL;
- bcnc->priv->c_mstruct = NULL;
bcnc->priv->mstruct = NULL;
bcnc->priv->meta_store_signal = 0;
+ bcnc->priv->transaction_status_signal = 0;
bcnc->priv->bfav = NULL;
@@ -401,101 +191,53 @@ browser_connection_init (BrowserConnection *bcnc)
}
static void
-transaction_status_changed_cb (G_GNUC_UNUSED GdaThreadWrapper *wrapper, G_GNUC_UNUSED gpointer instance,
- G_GNUC_UNUSED const gchar *signame, G_GNUC_UNUSED gint n_param_values,
- G_GNUC_UNUSED const GValue *param_values, G_GNUC_UNUSED gpointer gda_reserved,
- BrowserConnection *bcnc)
+transaction_status_changed_cb (GdaConnection *cnc, BrowserConnection *bcnc)
{
g_signal_emit (bcnc, browser_connection_signals [TRANSACTION_STATUS_CHANGED], 0);
}
-/* executed in sub @bcnc->priv->wrapper's thread */
-static gpointer
-wrapper_meta_store_update (BrowserConnection *bcnc, GError **error)
-{
- gboolean retval;
- GdaMetaContext context = {"_tables", 0, NULL, NULL};
- retval = gda_connection_update_meta_store (bcnc->priv->cnc, &context, error);
-
- return GINT_TO_POINTER (retval ? 2 : 1);
-}
-
-/* executed in sub @bcnc->priv->wrapper's thread */
-static gpointer
-wrapper_meta_struct_sync (BrowserConnection *bcnc, GError **error)
-{
- gboolean retval = TRUE;
- GdaMetaStruct *mstruct;
-
- MUTEX_LOCK (bcnc);
- g_assert (bcnc->priv->p_mstruct_list);
- mstruct = (GdaMetaStruct *) bcnc->priv->p_mstruct_list->data;
- /*g_print ("%s() for GdaMetaStruct %p\n", __FUNCTION__, mstruct);*/
- bcnc->priv->p_mstruct_list = g_slist_delete_link (bcnc->priv->p_mstruct_list,
- bcnc->priv->p_mstruct_list);
- if (bcnc->priv->p_mstruct_list) {
- /* don't care about this one */
- g_object_unref (G_OBJECT (mstruct));
- MUTEX_UNLOCK (bcnc);
- return GINT_TO_POINTER (3);
- }
- else {
- if (bcnc->priv->c_mstruct)
- g_object_unref (bcnc->priv->c_mstruct);
- bcnc->priv->c_mstruct = mstruct;
-
- /*g_print ("Meta struct sync for %p\n", mstruct);*/
- retval = gda_meta_struct_complement_all (mstruct, error);
- MUTEX_UNLOCK (bcnc);
- }
-
-#ifdef GDA_DEBUG_NO
- GSList *all, *list;
- g_print ("%s() %p:\n", __FUNCTION__, bcnc->priv->mstruct);
- all = gda_meta_struct_get_all_db_objects (bcnc->priv->mstruct);
- for (list = all; list; list = list->next) {
- GdaMetaDbObject *dbo = (GdaMetaDbObject *) list->data;
- g_print ("DBO, Type %d: short=>[%s] schema=>[%s] full=>[%s]\n", dbo->obj_type,
- dbo->obj_short_name, dbo->obj_schema, dbo->obj_full_name);
- }
- g_slist_free (all);
-#endif
-
- return GINT_TO_POINTER (retval ? 2 : 1);
-}
-
/*
* executed in main thread
*/
static void
-meta_changed_cb (G_GNUC_UNUSED GdaThreadWrapper *wrapper,
- G_GNUC_UNUSED GdaMetaStore *store,
- G_GNUC_UNUSED const gchar *signame,
- G_GNUC_UNUSED gint n_param_values,
- G_GNUC_UNUSED const GValue *param_values,
- G_GNUC_UNUSED gpointer gda_reserved,
- BrowserConnection *bcnc)
+meta_changed_cb (G_GNUC_UNUSED GdaMetaStore *store, G_GNUC_UNUSED const GSList *changes, BrowserConnection
*bcnc)
{
guint job_id;
- GError *lerror = NULL;
+ GError *error = NULL;
GdaMetaStruct *mstruct;
- MUTEX_LOCK (bcnc);
mstruct = gda_meta_struct_new (gda_connection_get_meta_store (bcnc->priv->cnc),
GDA_META_STRUCT_FEATURE_ALL);
- bcnc->priv->p_mstruct_list = g_slist_append (bcnc->priv->p_mstruct_list, mstruct);
- /*g_print ("%s() Added %p to p_mstruct_list\n", __FUNCTION__, mstruct);*/
- MUTEX_UNLOCK (bcnc);
- job_id = gda_thread_wrapper_execute (bcnc->priv->wrapper,
- (GdaThreadWrapperFunc) wrapper_meta_struct_sync,
- g_object_ref (bcnc), g_object_unref, &lerror);
- if (job_id > 0)
- push_wrapper_job (bcnc, job_id, JOB_TYPE_META_STRUCT_SYNC,
- _("Analysing database schema"), NULL, NULL);
- else if (lerror) {
+
+ browser_connection_set_busy_state (bcnc, TRUE, _("Analysing database schema"));
+
+ gboolean compl;
+ compl = gda_meta_struct_complement_all (mstruct, &error);
+
+ browser_connection_set_busy_state (bcnc, FALSE, NULL);
+
+ if (compl) {
+ if (bcnc->priv->mstruct)
+ g_object_unref (bcnc->priv->mstruct);
+ bcnc->priv->mstruct = mstruct;
+
+#ifdef GDA_DEBUG_NO
+ GSList *all, *list;
+ g_print ("%s() %p:\n", __FUNCTION__, bcnc->priv->mstruct);
+ all = gda_meta_struct_get_all_db_objects (bcnc->priv->mstruct);
+ for (list = all; list; list = list->next) {
+ GdaMetaDbObject *dbo = (GdaMetaDbObject *) list->data;
+ g_print ("DBO, Type %d: short=>[%s] schema=>[%s] full=>[%s]\n", dbo->obj_type,
+ dbo->obj_short_name, dbo->obj_schema, dbo->obj_full_name);
+ }
+ g_slist_free (all);
+#endif
+ }
+ else {
+ g_object_unref (mstruct);
browser_show_error (NULL, _("Error while fetching meta data from the connection: %s"),
- lerror->message ? lerror->message : _("No detail"));
- g_error_free (lerror);
+ error->message ? error->message : _("No detail"));
+ g_clear_error (&error);
}
}
@@ -510,14 +252,14 @@ void
browser_connection_meta_data_changed (BrowserConnection *bcnc)
{
g_return_if_fail (BROWSER_IS_CONNECTION (bcnc));
- meta_changed_cb (NULL, NULL, NULL, 0, NULL, NULL, bcnc);
+ meta_changed_cb (NULL, NULL, bcnc);
}
/*
* executed in bcnc->priv->wrapper's thread
*/
-static gpointer
-wrapper_have_meta_store_ready (BrowserConnection *bcnc, GError **error)
+static gboolean
+have_meta_store_ready (BrowserConnection *bcnc, GError **error)
{
gchar *dict_file_name = NULL;
gboolean update_store = FALSE;
@@ -553,21 +295,15 @@ wrapper_have_meta_store_ready (BrowserConnection *bcnc, GError **error)
retval = gda_connection_update_meta_store (bcnc->priv->cnc, &context, error);
if (!retval) {
g_object_unref (store);
- return NULL;
+ return FALSE;
}
}
gboolean retval = TRUE;
GdaMetaStruct *mstruct;
mstruct = gda_meta_struct_new (store, GDA_META_STRUCT_FEATURE_ALL);
- MUTEX_LOCK (bcnc);
- if (bcnc->priv->c_mstruct) {
- g_object_unref (bcnc->priv->c_mstruct);
- bcnc->priv->c_mstruct = NULL;
- }
bcnc->priv->mstruct = mstruct;
retval = gda_meta_struct_complement_all (mstruct, error);
- MUTEX_UNLOCK (bcnc);
#ifdef GDA_DEBUG_NO
GSList *all, *list;
@@ -581,38 +317,9 @@ wrapper_have_meta_store_ready (BrowserConnection *bcnc, GError **error)
g_slist_free (all);
#endif
g_object_unref (store);
- return retval ? (void*) 0x01 : NULL;
-}
-
-typedef struct {
- guint jid;
- GMainLoop *loop;
- GError **error;
- GdaThreadWrapper *wrapper;
-
- /* out */
- gboolean retval;
-} MainloopData;
-
-static gboolean
-check_for_meta_store_ready (MainloopData *data)
-{
- gpointer retval;
- GError *lerror = NULL;
-
- retval = gda_thread_wrapper_fetch_result (data->wrapper, FALSE, data->jid, &lerror);
- if (retval || (!retval && lerror)) {
- /* waiting is finished! */
- data->retval = retval ? TRUE : FALSE;
- if (lerror)
- g_propagate_error (data->error, lerror);
- g_main_loop_quit (data->loop);
- return FALSE;
- }
- return TRUE;
+ return retval;
}
-
static void
browser_connection_set_property (GObject *object,
guint param_id,
@@ -633,6 +340,8 @@ browser_connection_set_property (GObject *object,
bcnc, bcnc->priv->name, bcnc->priv->wrapper, bcnc->priv->cnc);*/
g_object_ref (bcnc->priv->cnc);
g_object_set (G_OBJECT (bcnc->priv->cnc), "execution-timer", TRUE, NULL);
+ TO_IMPLEMENT;
+ /*
bcnc->priv->transaction_status_signal =
gda_thread_wrapper_connect_raw (bcnc->priv->wrapper,
bcnc->priv->cnc,
@@ -640,49 +349,26 @@ browser_connection_set_property (GObject *object,
FALSE, FALSE,
(GdaThreadWrapperCallback)
transaction_status_changed_cb,
bcnc);
+ */
/* meta store, open it in a sub thread to avoid locking the GTK thread */
GError *lerror = NULL;
- guint jid;
- jid = gda_thread_wrapper_execute (bcnc->priv->wrapper,
- (GdaThreadWrapperFunc)
wrapper_have_meta_store_ready,
- (gpointer) bcnc,
- NULL, &lerror);
- if (jid == 0) {
+ if (! have_meta_store_ready (bcnc, &lerror)) {
browser_show_error (NULL, _("Error while fetching meta data from the
connection: %s"),
lerror->message ? lerror->message : _("No detail"));
g_clear_error (&lerror);
}
- else {
- GMainLoop *loop;
- MainloopData data;
-
- loop = g_main_loop_new (NULL, FALSE);
- data.jid = jid;
- data.loop = loop;
- data.error = &lerror;
- data.wrapper = bcnc->priv->wrapper;
- g_timeout_add (200, (GSourceFunc) check_for_meta_store_ready, &data);
- g_main_loop_run (loop);
- g_main_loop_unref (loop);
- if (!data.retval) {
- browser_show_error (NULL, _("Error while fetching meta data from the
connection: %s"),
- lerror->message ? lerror->message : _("No
detail"));
- g_clear_error (&lerror);
- }
- else {
- GdaMetaStore *store;
- g_object_get (G_OBJECT (bcnc->priv->cnc), "meta-store", &store, NULL);
- bcnc->priv->meta_store_signal =
- gda_thread_wrapper_connect_raw (bcnc->priv->wrapper, store,
"meta-changed",
- FALSE, FALSE,
- (GdaThreadWrapperCallback)
meta_changed_cb,
- bcnc);
- g_object_unref (store);
- }
-
- }
+ TO_IMPLEMENT;
+ /*
+ g_object_get (G_OBJECT (bcnc->priv->cnc), "meta-store", &store, NULL);
+ bcnc->priv->meta_store_signal =
+ gda_thread_wrapper_connect_raw (bcnc->priv->wrapper, store, "meta-changed",
+ FALSE, FALSE,
+ (GdaThreadWrapperCallback) meta_changed_cb,
+ bcnc);
+ g_object_unref (store);
+ */
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
@@ -749,16 +435,6 @@ browser_connection_dispose (GObject *object)
bcnc = BROWSER_CONNECTION (object);
if (bcnc->priv) {
- if (bcnc->priv->results_timer_id) {
- g_source_remove (bcnc->priv->results_timer_id);
- bcnc->priv->results_timer_id = 0;
- }
- if (bcnc->priv->results_list) {
- g_slist_foreach (bcnc->priv->results_list, (GFunc) g_free, NULL);
- g_slist_free (bcnc->priv->results_list);
- bcnc->priv->results_list = NULL;
- }
-
if (bcnc->priv->variables)
g_object_unref (bcnc->priv->variables);
@@ -772,32 +448,19 @@ browser_connection_dispose (GObject *object)
g_free (bcnc->priv->dict_file_name);
- if (bcnc->priv->wrapper_jobs) {
- g_slist_foreach (bcnc->priv->wrapper_jobs, (GFunc) wrapper_job_free, NULL);
- g_slist_free (bcnc->priv->wrapper_jobs);
- }
-
- if (bcnc->priv->wrapper_results_timer > 0)
- g_source_remove (bcnc->priv->wrapper_results_timer);
-
+ TO_IMPLEMENT;
+ /*
if (bcnc->priv->meta_store_signal)
gda_thread_wrapper_disconnect (bcnc->priv->wrapper,
bcnc->priv->meta_store_signal);
if (bcnc->priv->transaction_status_signal)
gda_thread_wrapper_disconnect (bcnc->priv->wrapper,
bcnc->priv->transaction_status_signal);
+ */
- g_object_unref (bcnc->priv->wrapper);
g_free (bcnc->priv->name);
- if (bcnc->priv->c_mstruct)
- g_object_unref (bcnc->priv->c_mstruct);
if (bcnc->priv->mstruct)
g_object_unref (bcnc->priv->mstruct);
- if (bcnc->priv->p_mstruct_list) {
- g_slist_foreach (bcnc->priv->p_mstruct_list, (GFunc) g_object_unref, NULL);
- g_slist_free (bcnc->priv->p_mstruct_list);
- }
- g_mutex_clear (&bcnc->priv->mstruct_mutex);
if (bcnc->priv->cnc)
g_object_unref (bcnc->priv->cnc);
@@ -811,16 +474,6 @@ browser_connection_dispose (GObject *object)
}
browser_connection_set_busy_state (bcnc, FALSE, NULL);
- if (bcnc->priv->ioc_watch_id > 0) {
- g_source_remove (bcnc->priv->ioc_watch_id);
- bcnc->priv->ioc_watch_id = 0;
- }
-
- if (bcnc->priv->ioc) {
- g_io_channel_unref (bcnc->priv->ioc);
- bcnc->priv->ioc = NULL;
- }
-
g_free (bcnc->priv);
bcnc->priv = NULL;
/*g_print ("Disposed BrowserConnection %p\n", bcnc);*/
@@ -830,127 +483,6 @@ browser_connection_dispose (GObject *object)
parent_class->dispose (object);
}
-static gboolean
-check_for_wrapper_result (BrowserConnection *bcnc)
-{
- GError *lerror = NULL;
- gpointer exec_res = NULL;
- WrapperJob *wj;
- gboolean retval = TRUE; /* return FALSE to interrupt current timer */
-
- retval = !setup_results_timer (bcnc);
- if (!bcnc->priv->wrapper_jobs) {
- gda_thread_wrapper_iterate (bcnc->priv->wrapper, FALSE);
- return retval;
- }
-
- wj = (WrapperJob*) bcnc->priv->wrapper_jobs->data;
- exec_res = gda_thread_wrapper_fetch_result (bcnc->priv->wrapper,
- FALSE,
- wj->job_id, &lerror);
- if (exec_res) {
- switch (wj->job_type) {
- case JOB_TYPE_META_STORE_UPDATE: {
- if (GPOINTER_TO_INT (exec_res) == 1) {
- browser_show_error (NULL, _("Error while analysing database schema: %s"),
- lerror && lerror->message ? lerror->message : _("No
detail"));
- g_clear_error (&lerror);
- }
- else if (! bcnc->priv->meta_store_signal) {
- GdaMetaStore *store;
- store = gda_connection_get_meta_store (bcnc->priv->cnc);
- meta_changed_cb (bcnc->priv->wrapper, store,
- NULL, 0, NULL, NULL, bcnc);
- bcnc->priv->meta_store_signal =
- gda_thread_wrapper_connect_raw (bcnc->priv->wrapper, store,
"meta-changed",
- FALSE, FALSE,
- (GdaThreadWrapperCallback)
meta_changed_cb,
- bcnc);
-
- }
- break;
- }
- case JOB_TYPE_META_STRUCT_SYNC: {
- if (GPOINTER_TO_INT (exec_res) == 1) {
- browser_show_error (NULL, _("Error while analysing database schema: %s"),
- lerror && lerror->message ? lerror->message : _("No
detail"));
- g_clear_error (&lerror);
- }
- else if (GPOINTER_TO_INT (exec_res) == 3) {
- /* nothing to do */
- }
- else {
- MUTEX_LOCK (bcnc);
-
- if (bcnc->priv->c_mstruct) {
- GdaMetaStruct *old_mstruct;
- old_mstruct = bcnc->priv->mstruct;
- bcnc->priv->mstruct = bcnc->priv->c_mstruct;
- bcnc->priv->c_mstruct = NULL;
- if (old_mstruct)
- g_object_unref (old_mstruct);
-#ifdef GDA_DEBUG_NO
- GSList *all, *list;
- g_print ("Signalling change for GdaMetaStruct %p:\n",
bcnc->priv->mstruct);
- all = gda_meta_struct_get_all_db_objects (bcnc->priv->mstruct);
- for (list = all; list; list = list->next) {
- GdaMetaDbObject *dbo = (GdaMetaDbObject *) list->data;
- g_print ("DBO, Type %d: short=>[%s] schema=>[%s]
full=>[%s]\n", dbo->obj_type,
- dbo->obj_short_name, dbo->obj_schema,
dbo->obj_full_name);
- }
- g_slist_free (all);
-#endif
- g_signal_emit (bcnc, browser_connection_signals [META_CHANGED], 0,
bcnc->priv->mstruct);
- }
- MUTEX_UNLOCK (bcnc);
- }
- break;
- }
- case JOB_TYPE_STATEMENT_EXECUTE: {
- guint *id;
- StatementResult *res;
-
- if (! bcnc->priv->executed_statements)
- bcnc->priv->executed_statements = g_hash_table_new_full (g_int_hash,
g_int_equal,
- g_free,
- (GDestroyNotify)
statement_result_free);
- id = g_new (guint, 1);
- *id = wj->job_id;
- res = g_new0 (StatementResult, 1);
- if (exec_res == (gpointer) 0x01)
- res->error = lerror;
- else {
- res->result = G_OBJECT (exec_res);
- res->last_inserted_row = g_object_get_data (exec_res,
"__bcnc_last_inserted_row");
- if (res->last_inserted_row)
- g_object_set_data (exec_res, "__bcnc_last_inserted_row", NULL);
- }
- g_hash_table_insert (bcnc->priv->executed_statements, id, res);
- break;
- }
- case JOB_TYPE_CALLBACK:
- if (wj->callback) {
- wj->callback (bcnc, exec_res == (gpointer) 0x01 ? NULL : exec_res,
- wj->cb_data, lerror);
- g_clear_error (&lerror);
- }
- break;
- default:
- g_assert_not_reached ();
- break;
- }
-
- pop_wrapper_job (bcnc, wj);
- }
-
- if (bcnc->priv->wrapper_jobs) {
- wj = (WrapperJob*) bcnc->priv->wrapper_jobs->data;
- if (exec_res)
- g_signal_emit (bcnc, browser_connection_signals [BUSY], 0, TRUE, wj->reason);
- }
- return retval;
-}
-
/**
* browser_connection_new
* @cnc: a #GdaConnection
@@ -1028,16 +560,13 @@ browser_connection_get_long_name (BrowserConnection *bcnc)
const GdaDsnInfo *
browser_connection_get_information (BrowserConnection *bcnc)
{
- gboolean is_wrapper;
g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
clear_dsn_info (bcnc);
if (!bcnc->priv->cnc)
return NULL;
- g_object_get (G_OBJECT (bcnc->priv->cnc), "is-wrapper", &is_wrapper, NULL);
-
- if (!is_wrapper && gda_connection_get_provider_name (bcnc->priv->cnc))
+ if (gda_connection_get_provider_name (bcnc->priv->cnc))
bcnc->priv->dsn_info.provider = g_strdup (gda_connection_get_provider_name (bcnc->priv->cnc));
if (gda_connection_get_dsn (bcnc->priv->cnc)) {
bcnc->priv->dsn_info.name = g_strdup (gda_connection_get_dsn (bcnc->priv->cnc));
@@ -1050,15 +579,6 @@ browser_connection_get_information (BrowserConnection *bcnc)
}
if (gda_connection_get_cnc_string (bcnc->priv->cnc))
bcnc->priv->dsn_info.cnc_string = g_strdup (gda_connection_get_cnc_string (bcnc->priv->cnc));
- if (is_wrapper && bcnc->priv->dsn_info.cnc_string) {
- GdaQuarkList *ql;
- const gchar *prov;
- ql = gda_quark_list_new_from_string (bcnc->priv->dsn_info.cnc_string);
- prov = gda_quark_list_find (ql, "PROVIDER_NAME");
- if (prov)
- bcnc->priv->dsn_info.provider = g_strdup (prov);
- gda_quark_list_free (ql);
- }
if (gda_connection_get_authentication (bcnc->priv->cnc))
bcnc->priv->dsn_info.auth_string = g_strdup (gda_connection_get_authentication
(bcnc->priv->cnc));
@@ -1117,33 +637,19 @@ browser_connection_update_meta_data (BrowserConnection *bcnc)
{
g_return_if_fail (BROWSER_IS_CONNECTION (bcnc));
- if (bcnc->priv->wrapper_jobs) {
- WrapperJob *wj;
- wj = (WrapperJob*) g_slist_last (bcnc->priv->wrapper_jobs)->data;
- if (wj->job_type == JOB_TYPE_META_STORE_UPDATE) {
- /* nothing to do */
- return;
- }
- }
+ browser_connection_set_busy_state (bcnc, TRUE, _("Getting database schema information"));
- if (bcnc->priv->meta_store_signal) {
- gda_thread_wrapper_disconnect (bcnc->priv->wrapper,
- bcnc->priv->meta_store_signal);
- bcnc->priv->meta_store_signal = 0;
- }
+ GdaMetaContext context = {"_tables", 0, NULL, NULL};
+ gboolean result;
+ GError *error = NULL;
+ result = gda_connection_update_meta_store (bcnc->priv->cnc, &context, &error);
- guint job_id;
- GError *lerror = NULL;
- job_id = gda_thread_wrapper_execute (bcnc->priv->wrapper,
- (GdaThreadWrapperFunc) wrapper_meta_store_update,
- g_object_ref (bcnc), g_object_unref, &lerror);
- if (job_id > 0)
- push_wrapper_job (bcnc, job_id, JOB_TYPE_META_STORE_UPDATE,
- _("Getting database schema information"), NULL, NULL);
- else if (lerror) {
+ browser_connection_set_busy_state (bcnc, FALSE, NULL);
+
+ if (!result) {
browser_show_error (NULL, _("Error while fetching meta data from the connection: %s"),
- lerror->message ? lerror->message : _("No detail"));
- g_error_free (lerror);
+ error->message ? error->message : _("No detail"));
+ g_clear_error (&error);
}
}
@@ -1325,105 +831,42 @@ browser_connection_render_pretty_sql (BrowserConnection *bcnc, GdaStatement *stm
NULL, NULL);
}
-typedef struct {
- GdaConnection *cnc;
- GdaStatement *stmt;
- GdaSet *params;
- GdaStatementModelUsage model_usage;
- gboolean need_last_insert_row;
-} StmtExecData;
-
-/* executed in sub @bcnc->priv->wrapper's thread */
-static gpointer
-wrapper_statement_execute (StmtExecData *data, GError **error)
-{
- GObject *obj;
- GdaSet *last_insert_row = NULL;
- GError *lerror = NULL;
- obj = gda_connection_statement_execute (data->cnc, data->stmt,
- data->params, data->model_usage,
- data->need_last_insert_row ? &last_insert_row : NULL,
- &lerror);
- if (obj) {
- if (GDA_IS_DATA_MODEL (obj))
- /* force loading of rows if necessary */
- gda_data_model_get_n_rows ((GdaDataModel*) obj);
- else if (last_insert_row)
- g_object_set_data (obj, "__bcnc_last_inserted_row", last_insert_row);
- }
- else {
- if (lerror)
- g_propagate_error (error, lerror);
- else {
- g_warning (_("Execution reported an undefined error, please report error to "
- "http://bugzilla.gnome.org/ for the \"libgda\" product"));
- g_set_error (error, GDA_TOOLS_ERROR, GDA_TOOLS_INTERNAL_COMMAND_ERROR,
- "%s", _("No detail"));
- }
- }
- return obj ? obj : (gpointer) 0x01;
-}
-
/**
* browser_connection_execute_statement
* @bcnc: a #BrowserConnection
* @stmt: a #GdaStatement
* @params: a #GdaSet as parameters, or %NULL
* @model_usage: how the returned data model (if any) will be used
- * @need_last_insert_row: %TRUE if the values of the last interted row must be computed
+ * @last_insert_row: (allow-none): a place to store a new GdaSet object which contains the values of the
last inserted row, or %NULL.
* @error: a place to store errors, or %NULL
*
- * Executes @stmt by @bcnc. Unless specific requirements, it's easier to use
- * browser_connection_execute_statement_cb().
+ * Executes @stmt by @bcnc.
*
- * Returns: a job ID, to be used with browser_connection_execution_get_result(), or %0 if an
- * error occurred
+ * Returns: (transfer full): a #GObject, or %NULL if an error occurred
*/
-guint
+GObject *
browser_connection_execute_statement (BrowserConnection *bcnc,
GdaStatement *stmt,
GdaSet *params,
GdaStatementModelUsage model_usage,
- gboolean need_last_insert_row,
+ GdaSet **last_insert_row,
GError **error)
{
- g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), 0);
- g_return_val_if_fail (GDA_IS_STATEMENT (stmt), 0);
- g_return_val_if_fail (!params || GDA_IS_SET (params), 0);
-
- StmtExecData *data;
- guint job_id;
-
- data = g_new0 (StmtExecData, 1);
- data->cnc = bcnc->priv->cnc;
- data->stmt = stmt;
- data->params = params;
- data->model_usage = model_usage;
- data->need_last_insert_row = need_last_insert_row;
-
- job_id = gda_thread_wrapper_execute (bcnc->priv->wrapper,
- (GdaThreadWrapperFunc) wrapper_statement_execute,
- data, (GDestroyNotify) g_free, error);
- if (job_id > 0)
- push_wrapper_job (bcnc, job_id, JOB_TYPE_STATEMENT_EXECUTE,
- _("Executing a query"), NULL, NULL);
-
- return job_id;
-}
-
-typedef struct {
- GdaConnection *cnc;
- GdaDataModel *model;
-} RerunSelectData;
-
-/* executed in @bcnc->priv->wrapper's sub thread */
-static gpointer
-wrapper_rerun_select (RerunSelectData *data, GError **error)
-{
- gboolean retval;
+ g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
+ g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
+ g_return_val_if_fail (!params || GDA_IS_SET (params), NULL);
- retval = gda_data_select_rerun (GDA_DATA_SELECT (data->model), error);
- return retval ? data->model : (gpointer) 0x01;
+ GObject *obj;
+ obj = gda_connection_statement_execute (bcnc->priv->cnc, stmt, params, model_usage,
+ last_insert_row, error);
+ if (obj) {
+ if (GDA_IS_DATA_MODEL (obj))
+ /* force loading of rows if necessary */
+ gda_data_model_get_n_rows ((GdaDataModel*) obj);
+ else if (last_insert_row)
+ g_object_set_data (obj, "__bcnc_last_inserted_row", last_insert_row);
+ }
+ return obj;
}
/**
@@ -1434,248 +877,19 @@ wrapper_rerun_select (RerunSelectData *data, GError **error)
*
* Re-execute @model
*
- * Returns: a job ID, or %0 if an error occurred
+ * Returns: %TRUE if no error occurred
*/
-guint
+gboolean
browser_connection_rerun_select (BrowserConnection *bcnc,
GdaDataModel *model,
GError **error)
{
- g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), 0);
- g_return_val_if_fail (GDA_IS_DATA_SELECT (model), 0);
-
- RerunSelectData *data;
- guint job_id;
-
- data = g_new0 (RerunSelectData, 1);
- data->cnc = bcnc->priv->cnc;
- data->model = model;
-
- job_id = gda_thread_wrapper_execute (bcnc->priv->wrapper,
- (GdaThreadWrapperFunc) wrapper_rerun_select,
- data, (GDestroyNotify) g_free, error);
- if (job_id > 0)
- push_wrapper_job (bcnc, job_id, JOB_TYPE_STATEMENT_EXECUTE,
- _("Executing a query"), NULL, NULL);
-
- return job_id;
-}
-
-
-/**
- * browser_connection_execution_get_result
- * @bcnc: a #BrowserConnection
- * @exec_id: the ID of the excution
- * @last_insert_row: a place to store the last inserted row, if any, or %NULL
- * @error: a place to store errors, or %NULL
- *
- * Pick up the result of the @exec_id's execution.
- *
- * Returns: the execution result, or %NULL if either an error occurred or the result is not yet ready
- */
-GObject *
-browser_connection_execution_get_result (BrowserConnection *bcnc, guint exec_id,
- GdaSet **last_insert_row, GError **error)
-{
- StatementResult *res;
- guint id;
- GObject *retval;
-
- g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
- g_return_val_if_fail (exec_id > 0, NULL);
-
- if (! bcnc->priv->executed_statements)
- return NULL;
-
- id = exec_id;
- res = g_hash_table_lookup (bcnc->priv->executed_statements, &id);
- if (!res)
- return NULL;
-
- retval = res->result;
- res->result = NULL;
-
- if (last_insert_row) {
- *last_insert_row = res->last_inserted_row;
- res->last_inserted_row = NULL;
- }
-
- if (res->error) {
- g_propagate_error (error, res->error);
- res->error = NULL;
- }
-
- g_hash_table_remove (bcnc->priv->executed_statements, &id);
- /*if (GDA_IS_DATA_MODEL (retval))
- gda_data_model_dump (GDA_DATA_MODEL (retval), NULL);*/
- return retval;
-}
-
-/**
- * browser_connection_job_cancel:
- * @bcnc: a #BrowserConnection
- * @job_id: the job_id to cancel
- *
- * Cancel a job, from the job ID returned by browser_connection_ldap_describe_entry()
- * or browser_connection_ldap_get_entry_children().
- */
-void
-browser_connection_job_cancel (BrowserConnection *bcnc, guint job_id)
-{
- g_return_if_fail (BROWSER_IS_CONNECTION (bcnc));
- g_return_if_fail (job_id > 0);
-
- TO_IMPLEMENT;
-}
-
-static gboolean query_exec_fetch_cb (BrowserConnection *bcnc);
-
-typedef struct {
- guint exec_id;
- gboolean need_last_insert_row;
- BrowserConnectionExecuteCallback callback;
- gpointer cb_data;
-} ExecCallbackData;
-
-/**
- * browser_connection_execute_statement_cb
- * @bcnc: a #BrowserConnection
- * @stmt: a #GdaStatement
- * @params: a #GdaSet as parameters, or %NULL
- * @model_usage: how the returned data model (if any) will be used
- * @need_last_insert_row: %TRUE if the values of the last interted row must be computed
- * @callback: the function to call when statement has been executed
- * @data: data to pass to @callback, or %NULL
- * @error: a place to store errors, or %NULL
- *
- * Executes @stmt by @bcnc and calls @callback when done. This occurs in the UI thread and avoids
- * having to set up a waiting mechanism to call browser_connection_execution_get_result()
- * repeatedly.
- *
- * Returns: a job ID, or %0 if an error occurred
- */
-guint
-browser_connection_execute_statement_cb (BrowserConnection *bcnc,
- GdaStatement *stmt,
- GdaSet *params,
- GdaStatementModelUsage model_usage,
- gboolean need_last_insert_row,
- BrowserConnectionExecuteCallback callback,
- gpointer data,
- GError **error)
-{
- guint exec_id;
- g_return_val_if_fail (callback, 0);
-
- exec_id = browser_connection_execute_statement (bcnc, stmt, params, model_usage,
- need_last_insert_row, error);
- if (!exec_id)
- return 0;
- ExecCallbackData *cbdata;
- cbdata = g_new0 (ExecCallbackData, 1);
- cbdata->exec_id = exec_id;
- cbdata->need_last_insert_row = need_last_insert_row;
- cbdata->callback = callback;
- cbdata->cb_data = data;
-
- bcnc->priv->results_list = g_slist_append (bcnc->priv->results_list, cbdata);
- if (! bcnc->priv->results_timer_id)
- bcnc->priv->results_timer_id = g_timeout_add (200,
- (GSourceFunc) query_exec_fetch_cb,
- bcnc);
- return exec_id;
-}
-
-/**
- * browser_connection_rerun_select_cb
- * @bcnc: a #BrowserConnection object
- * @model: a #GdaDataModel, which has to ba a #GdaDataSelect
- * @callback: the function to call when statement has been executed
- * @data: data to pass to @callback, or %NULL
- * @error: a place to store errors, or %NULL
- *
- * Re-execute @model.
- *
- * Warning: gda_data_model_freeze() and gda_data_model_thaw() should be used
- * before and after this call since the model will signal its changes in a thread
- * which is not the GUI thread.
- *
- * Returns: a job ID, or %0 if an error occurred
- */
-guint
-browser_connection_rerun_select_cb (BrowserConnection *bcnc,
- GdaDataModel *model,
- BrowserConnectionExecuteCallback callback,
- gpointer data,
- GError **error)
-{
- guint exec_id;
- g_return_val_if_fail (callback, 0);
-
- exec_id = browser_connection_rerun_select (bcnc, model, error);
- if (!exec_id)
- return 0;
- ExecCallbackData *cbdata;
- cbdata = g_new0 (ExecCallbackData, 1);
- cbdata->exec_id = exec_id;
- cbdata->need_last_insert_row = FALSE;
- cbdata->callback = callback;
- cbdata->cb_data = data;
-
- bcnc->priv->results_list = g_slist_append (bcnc->priv->results_list, cbdata);
- if (! bcnc->priv->results_timer_id)
- bcnc->priv->results_timer_id = g_timeout_add (200,
- (GSourceFunc) query_exec_fetch_cb,
- bcnc);
- return exec_id;
-}
-
-
-static gboolean
-query_exec_fetch_cb (BrowserConnection *bcnc)
-{
- GObject *res;
- GError *lerror = NULL;
- ExecCallbackData *cbdata;
- GdaSet *last_inserted_row = NULL;
-
- if (!bcnc->priv->results_list)
- goto out;
-
- cbdata = (ExecCallbackData *) bcnc->priv->results_list->data;
-
- if (cbdata->need_last_insert_row)
- res = browser_connection_execution_get_result (bcnc,
- cbdata->exec_id,
- &last_inserted_row,
- &lerror);
- else
- res = browser_connection_execution_get_result (bcnc,
- cbdata->exec_id, NULL,
- &lerror);
-
- if (res || lerror) {
- cbdata->callback (bcnc, cbdata->exec_id, res, last_inserted_row, lerror, cbdata->cb_data);
- if (res)
- g_object_unref (res);
- if (last_inserted_row)
- g_object_unref (last_inserted_row);
- g_clear_error (&lerror);
-
- bcnc->priv->results_list = g_slist_remove (bcnc->priv->results_list, cbdata);
- g_free (cbdata);
- }
+ g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), FALSE);
+ g_return_val_if_fail (GDA_IS_DATA_SELECT (model), FALSE);
- out:
- if (! bcnc->priv->results_list) {
- bcnc->priv->results_timer_id = 0;
- return FALSE;
- }
- else
- return TRUE; /* keep timer */
+ return gda_data_select_rerun (GDA_DATA_SELECT (model), error);
}
-
/**
* browser_connection_normalize_sql_statement
* @bcnc: a #BrowserConnection
@@ -1715,11 +929,14 @@ browser_connection_check_sql_statement_validify (BrowserConnection *bcnc,
/*
- * DOES NOT emit any signal
+ * DOES emit the "busy" signal
*/
void
browser_connection_set_busy_state (BrowserConnection *bcnc, gboolean busy, const gchar *busy_reason)
{
+ if (busy && !busy_reason)
+ g_warning ("Connection busy, but no reason provided");
+
if (bcnc->priv->busy_reason) {
g_free (bcnc->priv->busy_reason);
bcnc->priv->busy_reason = NULL;
@@ -1728,6 +945,8 @@ browser_connection_set_busy_state (BrowserConnection *bcnc, gboolean busy, const
bcnc->priv->busy = busy;
if (busy_reason)
bcnc->priv->busy_reason = g_strdup (busy_reason);
+
+ g_signal_emit (bcnc, browser_connection_signals [BUSY], 0, busy, busy_reason);
}
/*
@@ -2430,33 +1649,29 @@ browser_connection_is_ldap (BrowserConnection *bcnc)
#ifdef HAVE_LDAP
-typedef struct {
- GdaConnection *cnc;
- gchar *base_dn;
- gchar *attributes;
- gchar *filter;
- GdaLdapSearchScope scope;
-} LdapSearchData;
-static void
-ldap_search_data_free (LdapSearchData *data)
+/**
+ * browser_connection_ldap_search:
+ *
+ * Executes an LDAP search. Wrapper around gda_data_model_ldap_new()
+ *
+ * Returns: (transfer full): a new #GdaDataModel, or %NULL on error
+ */
+GdaDataModel *
+browser_connection_ldap_search (BrowserConnection *bcnc,
+ const gchar *base_dn, const gchar *filter,
+ const gchar *attributes, GdaLdapSearchScope scope,
+ GError **error)
{
- g_free (data->base_dn);
- g_free (data->filter);
- g_free (data->attributes);
- g_free (data);
-}
+ g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
+ g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (bcnc->priv->cnc), NULL);
-/* executed in sub @bcnc->priv->wrapper's thread */
-static gpointer
-wrapper_ldap_search (LdapSearchData *data, GError **error)
-{
GdaDataModel *model;
- model = gda_data_model_ldap_new (GDA_CONNECTION (data->cnc), data->base_dn,
- data->filter, data->attributes, data->scope);
+ gda_data_model_ldap_new_with_config (GDA_CONNECTION (bcnc->priv->cnc), base_dn,
+ filter, attributes, scope);
if (!model) {
g_set_error (error, GDA_TOOLS_ERROR, GDA_TOOLS_INTERNAL_COMMAND_ERROR,
"%s", _("Could not execute LDAP search"));
- return (gpointer) 0x01;
+ return NULL;
}
else {
GdaDataModel *wrapped;
@@ -2470,65 +1685,6 @@ wrapper_ldap_search (LdapSearchData *data, GError **error)
}
/**
- * browser_connection_ldap_search:
- *
- * Executes an LDAP search. Wrapper around gda_data_model_ldap_new()
- *
- * Returns: a job ID, or %0 if an error occurred
- */
-guint
-browser_connection_ldap_search (BrowserConnection *bcnc,
- const gchar *base_dn, const gchar *filter,
- const gchar *attributes, GdaLdapSearchScope scope,
- BrowserConnectionJobCallback callback,
- gpointer cb_data, GError **error)
-{
- g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), 0);
- g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (bcnc->priv->cnc), 0);
-
- LdapSearchData *data;
- guint job_id;
- data = g_new0 (LdapSearchData, 1);
- data->cnc = bcnc->priv->cnc;
- data->base_dn = g_strdup (base_dn);
- data->filter = g_strdup (filter);
- data->attributes = g_strdup (attributes);
- data->scope = scope;
-
- job_id = gda_thread_wrapper_execute (bcnc->priv->wrapper,
- (GdaThreadWrapperFunc) wrapper_ldap_search,
- data, (GDestroyNotify) ldap_search_data_free, error);
- if (job_id > 0)
- push_wrapper_job (bcnc, job_id, JOB_TYPE_CALLBACK,
- _("Executing LDAP search"), callback, cb_data);
- return job_id;
-}
-
-
-typedef struct {
- GdaConnection *cnc;
- gchar *dn;
- gchar **attributes;
-} LdapData;
-static void
-ldap_data_free (LdapData *data)
-{
- g_free (data->dn);
- if (data->attributes)
- g_strfreev (data->attributes);
- g_free (data);
-}
-
-/* executed in sub @bcnc->priv->wrapper's thread */
-static gpointer
-wrapper_ldap_describe_entry (LdapData *data, GError **error)
-{
- GdaLdapEntry *lentry;
- lentry = gda_ldap_describe_entry (GDA_LDAP_CONNECTION (data->cnc), data->dn, error);
- return lentry ? lentry : (gpointer) 0x01;
-}
-
-/**
* browser_connection_ldap_describe_entry:
* @bcnc: a #BrowserConnection
* @dn: the DN of the entry to describe
@@ -2538,40 +1694,15 @@ wrapper_ldap_describe_entry (LdapData *data, GError **error)
*
* Wrapper around gda_ldap_describe_entry().
*
- * Returns: a job ID, or %0 if an error occurred
+ * Returns: (transfer full): a new #GdaLdapEntry, or %NULL
*/
-guint
-browser_connection_ldap_describe_entry (BrowserConnection *bcnc, const gchar *dn,
- BrowserConnectionJobCallback callback,
- gpointer cb_data, GError **error)
+GdaLdapEntry *
+browser_connection_ldap_describe_entry (BrowserConnection *bcnc, const gchar *dn, GError **error)
{
g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), 0);
g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (bcnc->priv->cnc), 0);
- LdapData *data;
- guint job_id;
-
- data = g_new0 (LdapData, 1);
- data->cnc = bcnc->priv->cnc;
- data->dn = g_strdup (dn);
-
- job_id = gda_thread_wrapper_execute (bcnc->priv->wrapper,
- (GdaThreadWrapperFunc) wrapper_ldap_describe_entry,
- data, (GDestroyNotify) ldap_data_free, error);
- if (job_id > 0)
- push_wrapper_job (bcnc, job_id, JOB_TYPE_CALLBACK,
- _("Fetching LDAP entry's attributes"), callback, cb_data);
-
- return job_id;
-}
-
-/* executed in sub @bcnc->priv->wrapper's thread */
-static gpointer
-wrapper_ldap_get_entry_children (LdapData *data, GError **error)
-{
- GdaLdapEntry **array;
- array = gda_ldap_get_entry_children (GDA_LDAP_CONNECTION (data->cnc), data->dn, data->attributes,
error);
- return array ? array : (gpointer) 0x01;
+ return gda_ldap_describe_entry (GDA_LDAP_CONNECTION (bcnc->priv->cnc), dn, error);
}
/**
@@ -2584,52 +1715,23 @@ wrapper_ldap_get_entry_children (LdapData *data, GError **error)
*
* Wrapper around gda_ldap_get_entry_children().
*
- * Returns: a job ID, or %0 if an error occurred
+ * Returns: (transfer full): a %NULL terminated array of #GdaLdapEntry pointers, or %NULL if an error
occurred
*/
-guint
+GdaLdapEntry **
browser_connection_ldap_get_entry_children (BrowserConnection *bcnc, const gchar *dn,
- gchar **attributes,
- BrowserConnectionJobCallback callback,
- gpointer cb_data, GError **error)
+ gchar **attributes, GError **error)
{
g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), 0);
g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (bcnc->priv->cnc), 0);
- LdapData *data;
- guint job_id;
-
- data = g_new0 (LdapData, 1);
- data->cnc = bcnc->priv->cnc;
- data->dn = g_strdup (dn);
- if (attributes) {
- gint i;
- GArray *array = NULL;
- for (i = 0; attributes [i]; i++) {
- gchar *tmp;
- if (! array)
- array = g_array_new (TRUE, FALSE, sizeof (gchar*));
- tmp = g_strdup (attributes [i]);
- g_array_append_val (array, tmp);
- }
- if (array)
- data->attributes = (gchar**) g_array_free (array, FALSE);
- }
-
- job_id = gda_thread_wrapper_execute (bcnc->priv->wrapper,
- (GdaThreadWrapperFunc) wrapper_ldap_get_entry_children,
- data, (GDestroyNotify) ldap_data_free, error);
- if (job_id > 0)
- push_wrapper_job (bcnc, job_id, JOB_TYPE_CALLBACK,
- _("Fetching LDAP entry's children"), callback, cb_data);
-
- return job_id;
+ return gda_ldap_get_entry_children (GDA_LDAP_CONNECTION (bcnc->priv->cnc), dn, attributes, error);
}
/**
* browser_connection_ldap_icon_for_class:
* @objectclass: objectClass attribute
*
- * Returns: the correct icon, or %NULL if it could not be determined
+ * Returns: (transfer none): the correct icon, or %NULL if it could not be determined
*/
GdkPixbuf *
browser_connection_ldap_icon_for_class (GdaLdapAttribute *objectclass)
@@ -2678,59 +1780,36 @@ browser_connection_ldap_icon_for_class (GdaLdapAttribute *objectclass)
return NULL;
}
-typedef struct {
- BrowserConnectionJobCallback callback;
- gpointer cb_data;
-} IconTypeData;
-
-static void
-fetch_classes_cb (G_GNUC_UNUSED BrowserConnection *bcnc,
- gpointer out_result, IconTypeData *data, G_GNUC_UNUSED GError *error)
-{
- GdkPixbuf *pixbuf = NULL;
- if (out_result) {
- GdaLdapEntry *lentry = (GdaLdapEntry*) out_result;
- GdaLdapAttribute *attr;
- attr = g_hash_table_lookup (lentry->attributes_hash, "objectClass");
- pixbuf = browser_connection_ldap_icon_for_class (attr);
- gda_ldap_entry_free (lentry);
- }
- if (data->callback)
- data->callback (bcnc, pixbuf, data->cb_data, error);
-
- g_free (data);
-}
-
/**
* browser_connection_ldap_icon_for_dn:
* @bcnc: a #BrowserConnection
* @dn: the DN of the entry
- * @callback: the callback to execute with the results
- * @cb_data: a pointer to pass to @callback
* @error: a place to store errors, or %NULL
*
* Determines the correct icon type for @dn based on which class it belongs to
*
- * Returns: a job ID, or %0 if an error occurred
+ * Returns: (transfer none): a #GdkPixbuf, or %NULL
*/
-guint
-browser_connection_ldap_icon_for_dn (BrowserConnection *bcnc, const gchar *dn,
- BrowserConnectionJobCallback callback,
- gpointer cb_data, GError **error)
+GdkPixbuf *
+browser_connection_ldap_icon_for_dn (BrowserConnection *bcnc, const gchar *dn, GError **error)
{
- IconTypeData *data;
- guint job_id;
- g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), 0);
- g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (bcnc->priv->cnc), 0);
- g_return_val_if_fail (dn && *dn, 0);
-
- data = g_new (IconTypeData, 1);
- data->callback = callback;
- data->cb_data = cb_data;
- job_id = browser_connection_ldap_describe_entry (bcnc, dn,
- BROWSER_CONNECTION_JOB_CALLBACK (fetch_classes_cb),
- data, error);
- return job_id;
+ g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
+ g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (bcnc->priv->cnc), NULL);
+ g_return_val_if_fail (dn && *dn, NULL);
+
+ GdaLdapEntry *lentry;
+ lentry = browser_connection_ldap_describe_entry (bcnc, dn, error);
+ if (lentry) {
+ GdaLdapAttribute *attr;
+ attr = g_hash_table_lookup (lentry->attributes_hash, "objectClass");
+
+ GdkPixbuf *pixbuf;
+ pixbuf = browser_connection_ldap_icon_for_class (attr);
+ gda_ldap_entry_free (lentry);
+ return pixbuf;
+ }
+ else
+ return NULL;
}
/**
diff --git a/tools/browser/browser-connection.h b/tools/browser/browser-connection.h
index 5d8661e..6cc60c6 100644
--- a/tools/browser/browser-connection.h
+++ b/tools/browser/browser-connection.h
@@ -116,50 +116,20 @@ void browser_connection_job_cancel (BrowserConnection
GdaSqlParser *browser_connection_create_parser (BrowserConnection *bcnc);
gchar *browser_connection_render_pretty_sql (BrowserConnection *bcnc,
GdaStatement *stmt);
-guint browser_connection_execute_statement (BrowserConnection *bcnc,
+GObject *browser_connection_execute_statement (BrowserConnection *bcnc,
GdaStatement *stmt,
GdaSet *params,
GdaStatementModelUsage model_usage,
- gboolean need_last_insert_row,
+ GdaSet **last_insert_row,
GError **error);
-guint browser_connection_rerun_select (BrowserConnection *bcnc,
+gboolean browser_connection_rerun_select (BrowserConnection *bcnc,
GdaDataModel *model,
GError **error);
-GObject *browser_connection_execution_get_result (BrowserConnection *bcnc,
- guint exec_id,
- GdaSet **last_insert_row, GError **error);
+
gboolean browser_connection_normalize_sql_statement(BrowserConnection *bcnc,
GdaSqlStatement *sqlst, GError **error);
gboolean browser_connection_check_sql_statement_validify (BrowserConnection *bcnc,
GdaSqlStatement *sqlst, GError **error);
-/**
- * BrowserConnectionExecuteCallback
- *
- * Callback function called by browser_connection_execute_statement_cb(). If you need to keep
- * some of the arguments for a later usage, you need to ref/copy them.
- *
- * None of the passed arguments must not be modified
- */
-typedef void (*BrowserConnectionExecuteCallback) (BrowserConnection *bcnc,
- guint exec_id,
- GObject *out_result,
- GdaSet *out_last_inserted_row, GError *error,
- gpointer data);
-
-guint browser_connection_execute_statement_cb (BrowserConnection *bcnc,
- GdaStatement *stmt,
- GdaSet *params,
- GdaStatementModelUsage model_usage,
- gboolean need_last_insert_row,
- BrowserConnectionExecuteCallback callback,
- gpointer data,
- GError **error);
-guint browser_connection_rerun_select_cb (BrowserConnection *bcnc,
- GdaDataModel *model,
- BrowserConnectionExecuteCallback callback,
- gpointer data,
- GError **error);
-
/*
* transactions
@@ -202,21 +172,14 @@ void browser_connection_load_variables (BrowserConnection *bcnc,
gboolean browser_connection_is_ldap (BrowserConnection *bcnc);
#ifdef HAVE_LDAP
const gchar *browser_connection_ldap_get_base_dn (BrowserConnection *bcnc);
-guint browser_connection_ldap_search (BrowserConnection *bcnc,
+GdaDataModel *browser_connection_ldap_search (BrowserConnection *bcnc,
const gchar *base_dn, const gchar *filter,
const gchar *attributes, GdaLdapSearchScope scope,
- BrowserConnectionJobCallback callback,
- gpointer cb_data, GError **error);
-guint browser_connection_ldap_describe_entry (BrowserConnection *bcnc, const gchar *dn,
- BrowserConnectionJobCallback callback,
- gpointer cb_data, GError **error);
-guint browser_connection_ldap_get_entry_children (BrowserConnection *bcnc, const gchar *dn,
- gchar **attributes,
- BrowserConnectionJobCallback callback,
- gpointer cb_data, GError **error);
-guint browser_connection_ldap_icon_for_dn (BrowserConnection *bcnc, const gchar *dn,
- BrowserConnectionJobCallback callback,
- gpointer cb_data, GError **error);
+ GError **error);
+GdaLdapEntry *browser_connection_ldap_describe_entry (BrowserConnection *bcnc, const gchar *dn,
GError **error);
+GdaLdapEntry **browser_connection_ldap_get_entry_children (BrowserConnection *bcnc, const gchar *dn,
+ gchar **attributes, GError **error);
+GdkPixbuf *browser_connection_ldap_icon_for_dn (BrowserConnection *bcnc, const gchar *dn, GError
**error);
GdkPixbuf *browser_connection_ldap_icon_for_class (GdaLdapAttribute *objectclass);
gboolean browser_connection_describe_table (BrowserConnection *bcnc, const gchar *table_name,
const gchar **out_base_dn, const gchar **out_filter,
diff --git a/tools/browser/browser-virtual-connection.c b/tools/browser/browser-virtual-connection.c
index e2fbe39..380f1e2 100644
--- a/tools/browser/browser-virtual-connection.c
+++ b/tools/browser/browser-virtual-connection.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 - 2012 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2009 - 2014 Vivien Malerba <malerba gnome-db org>
* Copyright (C) 2010 David King <davidk openismus com>
*
* This program is free software; you can redistribute it and/or
@@ -236,50 +236,32 @@ browser_virtual_connection_get_property (GObject *object,
}
}
-
-
-typedef struct {
- guint cncid;
- GMainLoop *loop;
- GError **error;
- GdaThreadWrapper *wrapper;
-
- /* out */
- GdaConnection *cnc;
-} MainloopData;
-
-static gboolean
-check_for_cnc (MainloopData *data)
-{
- GdaConnection *cnc;
- GError *lerror = NULL;
- cnc = gda_thread_wrapper_fetch_result (data->wrapper, FALSE, data->cncid, &lerror);
- if (cnc || (!cnc && lerror)) {
- /* waiting is finished! */
- data->cnc = cnc;
- if (lerror)
- g_propagate_error (data->error, lerror);
- g_main_loop_quit (data->loop);
- return FALSE;
- }
- return TRUE;
-}
-
-/*
- * executed in a sub thread
+/**
+ * browser_virtual_connection_new
+ * @specs: the specifications of the virtual connection's contents
+ * @error: a place to store errors, or %NULL
+ *
+ * Creates a new #BrowserVirtualConnection connection.
+ *
+ * Returns: the new connection
*/
-static GdaConnection *
-sub_thread_open_cnc (BrowserVirtualConnectionSpecs *specs, GError **error)
+BrowserConnection *
+browser_virtual_connection_new (const BrowserVirtualConnectionSpecs *specs, GError **error)
{
-#ifndef DUMMY
+#ifdef DUMMY
+ sleep (5);
+ g_set_error (error, GDA_TOOLS_ERROR, TOOLS_INTERNAL_COMMAND_ERROR,
+ "%s", "Timeout!!!");
+ return NULL;
+#endif
+
/* create GDA virtual connection */
static GdaVirtualProvider *provider = NULL;
GdaConnection *virtual;
if (!provider)
provider = gda_vprovider_hub_new ();
- virtual = gda_virtual_connection_open_extended (provider, GDA_CONNECTION_OPTIONS_THREAD_SAFE |
- GDA_CONNECTION_OPTIONS_AUTO_META_DATA, NULL);
+ virtual = gda_virtual_connection_open (provider, GDA_CONNECTION_OPTIONS_AUTO_META_DATA, NULL);
/* add parts to connection as specified by @specs */
GSList *list;
@@ -312,67 +294,13 @@ sub_thread_open_cnc (BrowserVirtualConnectionSpecs *specs, GError **error)
g_assert_not_reached ();
}
}
-
- return virtual;
-#else /* DUMMY defined */
- sleep (5);
- g_set_error (error, GDA_TOOLS_ERROR, TOOLS_INTERNAL_COMMAND_ERROR,
- "%s", "Timeout!!!");
- return NULL;
-#endif
-}
-
-/**
- * browser_virtual_connection_new
- * @specs: the specifications of the virtual connection's contents
- * @error: a place to store errors, or %NULL
- *
- * Creates a new #BrowserVirtualConnection connection.
- *
- * Returns: the new connection
- */
-BrowserConnection *
-browser_virtual_connection_new (const BrowserVirtualConnectionSpecs *specs, GError **error)
-{
- /* open virtual GdaConnection in sub thread */
- GdaThreadWrapper *wrapper;
- guint cncid;
-
- g_return_val_if_fail (specs, NULL);
-
- wrapper = gda_thread_wrapper_new ();
- cncid = gda_thread_wrapper_execute (wrapper,
- (GdaThreadWrapperFunc) sub_thread_open_cnc,
- (gpointer) specs,
- (GDestroyNotify) NULL,
- error);
- if (cncid == 0)
- return NULL;
-
- GMainLoop *loop;
- MainloopData data;
-
- loop = g_main_loop_new (NULL, FALSE);
- data.wrapper = wrapper;
- data.cncid = cncid;
- data.error = error;
- data.loop = loop;
- data.cnc = NULL;
-
- g_timeout_add (200, (GSourceFunc) check_for_cnc, &data);
- g_main_loop_run (loop);
- g_main_loop_unref (loop);
- g_object_unref (wrapper);
/* create the BrowserConnection object */
- if (data.cnc) {
+ if (virtual) {
BrowserConnection *nbcnc;
- g_object_set (data.cnc, "monitor-wrapped-in-mainloop", TRUE, NULL);
nbcnc = g_object_new (BROWSER_TYPE_VIRTUAL_CONNECTION, "specs", specs,
- "gda-connection", data.cnc, NULL);
- g_object_unref (data.cnc);
- /*g_print ("BrowserVirtualConnection %p had TMP wrapper %p\n", nbcnc, wrapper);*/
-
+ "gda-connection", virtual, NULL);
+ g_object_unref (virtual);
return nbcnc;
}
else
diff --git a/tools/browser/common/ui-formgrid.c b/tools/browser/common/ui-formgrid.c
index 5f256f1..689c67c 100644
--- a/tools/browser/common/ui-formgrid.c
+++ b/tools/browser/common/ui-formgrid.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010 David King <davidk openismus com>
- * Copyright (C) 2010 - 2012 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2010 - 2014 Vivien Malerba <malerba gnome-db org>
* Copyright (C) 2011 Murray Cumming <murrayc murrayc com>
*
* This program is free software; you can redistribute it and/or
@@ -335,7 +335,7 @@ ui_formgrid_init (UiFormGrid *formgrid)
/* button to toggle between auto update and not */
button = gtk_toggle_button_new ();
- GtkWidget *img = gtk_image_new_from_stock (GTK_STOCK_EXECUTE, GTK_ICON_SIZE_MENU);
+ GtkWidget *img = gtk_image_new_from_icon_name (_("_Execute"), GTK_ICON_SIZE_MENU);
gtk_button_set_image (GTK_BUTTON (button), img);
formgrid->priv->autoupdate_toggle = button;
@@ -633,47 +633,6 @@ action_executed_data_free (ActionExecutedData *data)
g_free (data);
}
-static gboolean
-exec_end_timeout_cb (ActionExecutedData *aed)
-{
- GError *error = NULL;
- GObject *obj;
- obj = browser_connection_execution_get_result (aed->bcnc, aed->exec_id,
- NULL, &error);
- if (obj) {
- if (GDA_IS_DATA_MODEL (obj)) {
- g_assert (aed->model == (GdaDataModel*) obj);
- gda_data_model_thaw (aed->model);
- gda_data_model_reset (aed->model);
-
- aed->exec_id = 0;
- aed->timer_id = 0;
- return FALSE;
- }
- else {
- g_object_unref (obj);
- g_set_error (&error, GDA_TOOLS_ERROR, GDA_TOOLS_COMMAND_ARGUMENTS_ERROR,
- "%s", _("Statement to execute is not a selection statement"));
- }
- }
-
- if (error) {
- GtkWidget *toplevel;
- toplevel = gtk_widget_get_toplevel (GTK_WIDGET (aed->formgrid));
- browser_show_error (GTK_WINDOW (toplevel),
- _("Error executing query:\n%s"),
- error->message ?
- error->message : _("No detail"));
- g_clear_error (&error);
- gda_data_model_thaw (aed->model);
- aed->exec_id = 0;
- aed->timer_id = 0;
- return FALSE;
- }
- else
- return TRUE; /* keep timer */
-}
-
static void
action_executed_holder_changed_cb (G_GNUC_UNUSED GdaSet *params, G_GNUC_UNUSED GdaHolder *holder,
ActionExecutedData *aed)
@@ -682,111 +641,19 @@ action_executed_holder_changed_cb (G_GNUC_UNUSED GdaSet *params, G_GNUC_UNUSED G
return;
GError *error = NULL;
- guint jid;
gda_data_model_freeze (aed->model);
- jid = browser_connection_rerun_select (aed->bcnc, aed->model, &error);
- if (!jid) {
+ if (!browser_connection_rerun_select (aed->bcnc, aed->model, &error)) {
GtkWidget *toplevel;
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (aed->formgrid));
browser_show_error (GTK_WINDOW (toplevel),
- _("Error executing query:\n%s"),
- error->message ?
- error->message : _("No detail"));
+ _("Error executing query:\n%s"), error->message ? error->message : _("No
detail"));
+ g_clear_error (&error);
gda_data_model_thaw (aed->model);
}
else {
- /* watch the end of execution */
- aed->exec_id = jid;
- if (! aed->timer_id)
- aed->timer_id = g_timeout_add (50, (GSourceFunc) exec_end_timeout_cb, aed);
- }
-}
-
-/*
- * Called after an action's statement has been executed
- */
-static void
-statement_executed_cb (G_GNUC_UNUSED BrowserConnection *bcnc,
- G_GNUC_UNUSED guint exec_id,
- GObject *out_result,
- G_GNUC_UNUSED GdaSet *out_last_inserted_row, GError *error,
- ActionExecutedData *aed)
-{
- GtkWidget *toplevel;
-
- toplevel = gtk_widget_get_toplevel (GTK_WIDGET (aed->formgrid));
- g_object_unref (aed->formgrid);
- aed->formgrid = NULL;
-
- if (error)
- browser_show_error (GTK_WINDOW (toplevel),
- _("Error executing query:\n%s"),
- error->message ?
- error->message : _("No detail"));
- else if (out_result && GDA_IS_DATA_MODEL (out_result)) {
- GtkWidget *dialog, *label, *fg;
- GtkWidget *dcontents;
-
- gchar *tmp;
- dialog = gtk_dialog_new_with_buttons (aed->name,
- NULL,
- 0,
- GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
- dcontents = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
- gtk_box_set_spacing (GTK_BOX (dcontents), 5);
- gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE, TRUE);
-
- tmp = g_markup_printf_escaped ("<b>%s:</b>", aed->name);
- label = gtk_label_new ("");
- gtk_label_set_markup (GTK_LABEL (label), tmp);
- g_free (tmp);
- gtk_misc_set_alignment (GTK_MISC (label), 0., 0.);
- gtk_box_pack_start (GTK_BOX (dcontents), label, FALSE, FALSE, 5);
-
- fg = ui_formgrid_new (GDA_DATA_MODEL (out_result), TRUE,
- GDAUI_DATA_PROXY_INFO_CURRENT_ROW);
- ui_formgrid_set_connection (UI_FORMGRID (fg), aed->bcnc);
-
- if (GDA_IS_DATA_SELECT (out_result)) {
- GdaStatement *stmt;
- g_object_get (G_OBJECT (out_result), "select-stmt", &stmt, NULL);
- if (stmt) {
- ui_formgrid_handle_user_prefs (UI_FORMGRID (fg), NULL, stmt);
- g_object_unref (stmt);
- }
- aed->model = g_object_ref (out_result);
- g_signal_connect (aed->params, "holder-changed",
- G_CALLBACK (action_executed_holder_changed_cb), aed);
-
- aed->formgrid = g_object_ref (fg);
- aed->formgrid->priv->autoupdate_possible = TRUE;
- gtk_widget_show (aed->formgrid->priv->autoupdate_toggle);
- }
- gtk_box_pack_start (GTK_BOX (dcontents), fg, TRUE, TRUE, 0);
-
- gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 600);
- gtk_widget_show_all (dialog);
-
- g_signal_connect (dialog, "response",
- G_CALLBACK (gtk_widget_destroy), NULL);
- g_signal_connect (dialog, "close",
- G_CALLBACK (gtk_widget_destroy), NULL);
- g_object_set_data_full (G_OBJECT (dialog), "aed", aed,
- (GDestroyNotify) action_executed_data_free);
- aed = NULL; /* don't free it yet */
- }
- else if (BROWSER_IS_WINDOW (toplevel)) {
- browser_window_show_notice_printf (BROWSER_WINDOW (toplevel),
- GTK_MESSAGE_INFO,
- "ActionExecution",
- "%s", _("Action successfully executed"));
+ gda_data_model_thaw (aed->model);
+ gda_data_model_reset (aed->model);
}
- else
- browser_show_message (GTK_WINDOW (toplevel),
- "%s", _("Action successfully executed"));
-
- if (aed)
- action_executed_data_free (aed);
}
static void
@@ -811,30 +678,88 @@ execute_action_mitem_cb (GtkMenuItem *menuitem, UiFormGrid *formgrid)
if (response == GTK_RESPONSE_ACCEPT) {
GError *lerror = NULL;
BrowserConnection *bcnc;
- ActionExecutedData *aed;
bcnc = get_browser_connection (formgrid);
g_assert (bcnc);
-
- aed = g_new0 (ActionExecutedData, 1);
- aed->formgrid = g_object_ref (formgrid);
- aed->bcnc = g_object_ref (bcnc);
- if (act->name)
- aed->name = g_strdup (act->name);
- aed->stmt = g_object_ref (act->stmt);
- aed->params = g_object_ref (act->params);
-
- if (! browser_connection_execute_statement_cb (bcnc,
- act->stmt, act->params,
- GDA_STATEMENT_MODEL_RANDOM_ACCESS,
- FALSE,
- (BrowserConnectionExecuteCallback)
statement_executed_cb,
- aed, &lerror)) {
+
+ GObject *result;
+ result = browser_connection_execute_statement (bcnc, act->stmt, act->params,
+ GDA_STATEMENT_MODEL_RANDOM_ACCESS, NULL,
+ &lerror);
+ if (result && GDA_IS_DATA_MODEL (result)) {
+ GtkWidget *dialog, *label, *fg;
+ GtkWidget *dcontents;
+ gchar *tmp;
+ dialog = gtk_dialog_new_with_buttons (act->name, NULL, 0,
+ _("_Close"), GTK_RESPONSE_CLOSE, NULL);
+ dcontents = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+ gtk_box_set_spacing (GTK_BOX (dcontents), 5);
+ gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE, TRUE);
+
+ tmp = g_markup_printf_escaped ("<b>%s:</b>", act->name);
+ label = gtk_label_new ("");
+ gtk_label_set_markup (GTK_LABEL (label), tmp);
+ g_free (tmp);
+ gtk_misc_set_alignment (GTK_MISC (label), 0., 0.);
+ gtk_box_pack_start (GTK_BOX (dcontents), label, FALSE, FALSE, 5);
+
+ fg = ui_formgrid_new (GDA_DATA_MODEL (result), TRUE,
+ GDAUI_DATA_PROXY_INFO_CURRENT_ROW);
+ ui_formgrid_set_connection (UI_FORMGRID (fg), bcnc);
+
+ ActionExecutedData *aed;
+ aed = g_new0 (ActionExecutedData, 1);
+ aed->formgrid = g_object_ref (formgrid);
+ aed->bcnc = g_object_ref (bcnc);
+ if (act->name)
+ aed->name = g_strdup (act->name);
+ aed->stmt = g_object_ref (act->stmt);
+ aed->params = g_object_ref (act->params);
+
+ if (GDA_IS_DATA_SELECT (result)) {
+ GdaStatement *stmt;
+ g_object_get (G_OBJECT (result), "select-stmt", &stmt, NULL);
+ if (stmt) {
+ ui_formgrid_handle_user_prefs (UI_FORMGRID (fg), NULL, stmt);
+ g_object_unref (stmt);
+ }
+ aed->model = g_object_ref (result);
+ g_signal_connect (aed->params, "holder-changed",
+ G_CALLBACK (action_executed_holder_changed_cb), aed);
+
+ aed->formgrid = g_object_ref (fg);
+ aed->formgrid->priv->autoupdate_possible = TRUE;
+ gtk_widget_show (aed->formgrid->priv->autoupdate_toggle);
+ }
+ gtk_box_pack_start (GTK_BOX (dcontents), fg, TRUE, TRUE, 0);
+
+ gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 600);
+ gtk_widget_show_all (dialog);
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+ g_signal_connect (dialog, "close",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+ g_object_set_data_full (G_OBJECT (dialog), "aed", aed,
+ (GDestroyNotify) action_executed_data_free);
+ }
+ else if (result) {
+ if (BROWSER_IS_WINDOW (toplevel)) {
+ browser_window_show_notice_printf (BROWSER_WINDOW (toplevel),
+ GTK_MESSAGE_INFO,
+ "ActionExecution",
+ "%s", _("Action successfully executed"));
+ }
+ else
+ browser_show_message (GTK_WINDOW (toplevel),
+ "%s", _("Action successfully executed"));
+ g_object_unref (result);
+ }
+ else {
browser_show_error (GTK_WINDOW (toplevel),
_("Error executing query: %s"),
lerror && lerror->message ? lerror->message : _("No detail"));
g_clear_error (&lerror);
- action_executed_data_free (aed);
}
}
}
diff --git a/tools/browser/data-manager/data-source-manager.c
b/tools/browser/data-manager/data-source-manager.c
index 1cb508a..875b4e8 100644
--- a/tools/browser/data-manager/data-source-manager.c
+++ b/tools/browser/data-manager/data-source-manager.c
@@ -21,7 +21,6 @@
#include <string.h>
#include <glib/gi18n-lib.h>
#include "browser-connection.h"
-#include <libgda/thread-wrapper/gda-thread-wrapper.h>
#include "support.h"
#include "marshal.h"
#include <sql-parser/gda-sql-parser.h>
diff --git a/tools/browser/data-manager/data-source.c b/tools/browser/data-manager/data-source.c
index c5bc6b9..ff0d9f5 100644
--- a/tools/browser/data-manager/data-source.c
+++ b/tools/browser/data-manager/data-source.c
@@ -22,7 +22,6 @@
#include <string.h>
#include <glib/gi18n-lib.h>
#include "browser-connection.h"
-#include <libgda/thread-wrapper/gda-thread-wrapper.h>
#include "support.h"
#include "marshal.h"
#include <sql-parser/gda-sql-parser.h>
@@ -780,59 +779,6 @@ data_source_to_xml_node (DataSource *source)
return node;
}
-static gboolean
-exec_end_timeout_cb (DataSource *source)
-{
- GObject *obj;
-
- g_return_val_if_fail (source->priv->exec_id > 0, FALSE);
-
- g_clear_error (&source->priv->exec_error);
- obj = browser_connection_execution_get_result (source->priv->bcnc,
- source->priv->exec_id,
- NULL,
- &source->priv->exec_error);
- if (obj) {
- if (GDA_IS_DATA_MODEL (obj)) {
- if (source->priv->model != GDA_DATA_MODEL (obj)) {
- if (source->priv->model)
- g_object_unref (source->priv->model);
- source->priv->model = GDA_DATA_MODEL (obj);
- g_object_set (source->priv->model, "auto-reset", FALSE, NULL);
- }
- else {
- gda_data_model_thaw (source->priv->model);
- gda_data_model_reset (source->priv->model);
- }
- /*gda_data_model_dump (source->priv->model, NULL);*/
- }
- else {
- g_object_unref (obj);
- g_set_error (&source->priv->exec_error, GDA_TOOLS_ERROR,
GDA_TOOLS_COMMAND_ARGUMENTS_ERROR,
- "%s", _("Statement to execute is not a selection statement"));
- }
-
- source->priv->exec_id = 0;
- g_signal_emit (source, data_source_signals [EXEC_FINISHED], 0, source->priv->exec_error);
- if (source->priv->exec_again) {
- source->priv->exec_again = FALSE;
- data_source_execute (source, NULL);
- }
- return FALSE;
- }
- else if (source->priv->exec_error) {
- source->priv->exec_id = 0;
- g_signal_emit (source, data_source_signals [EXEC_FINISHED], 0, source->priv->exec_error);
- if (source->priv->exec_again) {
- source->priv->exec_again = FALSE;
- data_source_execute (source, NULL);
- }
- return FALSE;
- }
- else
- return TRUE; /* keep timer */
-}
-
/**
*data_source_get_statement
*/
@@ -932,13 +878,9 @@ void
data_source_execute (DataSource *source, GError **error)
{
GError *lerror = NULL;
- gboolean has_exec = TRUE;
- guint exec_id = 0;
g_return_if_fail (IS_DATA_SOURCE (source));
- if (source->priv->exec_again)
- return;
- if (source->priv->executing || (source->priv->exec_id > 0)) {
+ if (source->priv->exec_again || source->priv->executing) {
source->priv->exec_again = TRUE;
return;
}
@@ -954,38 +896,48 @@ data_source_execute (DataSource *source, GError **error)
if (source->priv->model) {
if (source->priv->need_rerun) {
- /* freeze source->priv->model to avoid that it emits signals while being in the
- * wrong thread */
source->priv->need_rerun = FALSE;
- gda_data_model_freeze (source->priv->model);
- exec_id = browser_connection_rerun_select (source->priv->bcnc,
- source->priv->model, &lerror);
+ g_signal_emit (source, data_source_signals [EXEC_STARTED], 0);
+ browser_connection_rerun_select (source->priv->bcnc, source->priv->model, &lerror);
+ gda_data_model_dump (source->priv->model, NULL);
+ g_signal_emit (source, data_source_signals [EXEC_FINISHED], lerror);
}
- else
- has_exec = FALSE;
}
- else
- exec_id = browser_connection_execute_statement (source->priv->bcnc,
- source->priv->stmt,
- source->priv->params,
- GDA_STATEMENT_MODEL_RANDOM_ACCESS |
- GDA_STATEMENT_MODEL_ALLOW_NOPARAM,
- FALSE, &lerror);
-
- if (has_exec) {
+ else {
+ GObject *result;
g_signal_emit (source, data_source_signals [EXEC_STARTED], 0);
- if (! exec_id) {
- gda_data_model_thaw (source->priv->model);
- gda_data_model_reset (source->priv->model);
- g_signal_emit (source, data_source_signals [EXEC_FINISHED], 0, lerror);
- g_propagate_error (error, lerror);
- }
- else {
- /* monitor the end of execution */
- source->priv->exec_id = exec_id;
- g_timeout_add (50, (GSourceFunc) exec_end_timeout_cb, source);
+ result = browser_connection_execute_statement (source->priv->bcnc,
+ source->priv->stmt,
+ source->priv->params,
+ GDA_STATEMENT_MODEL_RANDOM_ACCESS |
+ GDA_STATEMENT_MODEL_ALLOW_NOPARAM,
+ NULL, &lerror);
+ if (result) {
+ if (GDA_IS_DATA_MODEL (result)) {
+ if (source->priv->model != GDA_DATA_MODEL (result)) {
+ if (source->priv->model)
+ g_object_unref (source->priv->model);
+ source->priv->model = GDA_DATA_MODEL (result);
+ g_object_set (source->priv->model, "auto-reset", FALSE, NULL);
+ }
+ gda_data_model_dump (source->priv->model, NULL);
+ }
+ else {
+ g_object_unref (result);
+ g_set_error (&lerror, GDA_TOOLS_ERROR, GDA_TOOLS_COMMAND_ARGUMENTS_ERROR,
+ "%s", _("Statement to execute is not a selection statement"));
+ }
+ g_signal_emit (source, data_source_signals [EXEC_FINISHED], lerror);
}
+
+ g_signal_emit (source, data_source_signals [EXEC_FINISHED], 0, lerror);
+ }
+
+ if (source->priv->exec_again) {
+ source->priv->exec_again = FALSE;
+ data_source_execute (source, NULL);
}
+
source->priv->executing = FALSE;
}
diff --git a/tools/browser/doc/gda-browser-sections.txt b/tools/browser/doc/gda-browser-sections.txt
index f7a5129..f687030 100644
--- a/tools/browser/doc/gda-browser-sections.txt
+++ b/tools/browser/doc/gda-browser-sections.txt
@@ -92,13 +92,9 @@ browser_connection_get_completions
browser_connection_create_parser
browser_connection_render_pretty_sql
browser_connection_execute_statement
-browser_connection_execution_get_result
-BrowserConnectionExecuteCallback
-browser_connection_execute_statement_cb
browser_connection_normalize_sql_statement
browser_connection_check_sql_statement_validify
browser_connection_rerun_select
-browser_connection_rerun_select_cb
<SUBSECTION>
browser_connection_begin
browser_connection_commit
diff --git a/tools/browser/ldap-browser/entry-properties.c b/tools/browser/ldap-browser/entry-properties.c
index f7fe0c0..7ad1b6d 100644
--- a/tools/browser/ldap-browser/entry-properties.c
+++ b/tools/browser/ldap-browser/entry-properties.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2011 Murray Cumming <murrayc murrayc com>
- * Copyright (C) 2011 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2011 - 2014 Vivien Malerba <malerba gnome-db org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -743,96 +743,74 @@ ad_sam_account_type_to_string (const gchar *value)
}
static void
-info_fetch_cb (BrowserConnection *bcnc, gpointer out_result, EntryProperties *eprop, G_GNUC_UNUSED GError
*error)
+entry_info_fetched_done (EntryProperties *eprop, GdaLdapEntry *entry)
{
- if (out_result) {
- GtkTextBuffer *tbuffer;
- GtkTextIter start, end;
-
- tbuffer = eprop->priv->text;
- gtk_text_buffer_get_start_iter (tbuffer, &start);
- gtk_text_buffer_get_end_iter (tbuffer, &end);
- gtk_text_buffer_delete (tbuffer, &start, &end);
-
- GdaLdapEntry *entry = (GdaLdapEntry*) out_result;
- guint i;
- GtkTextIter current;
-
- gtk_text_buffer_get_start_iter (tbuffer, ¤t);
+ GtkTextBuffer *tbuffer;
+ GtkTextIter start, end;
+ BrowserConnection *bcnc = eprop->priv->bcnc;
+
+ tbuffer = eprop->priv->text;
+ gtk_text_buffer_get_start_iter (tbuffer, &start);
+ gtk_text_buffer_get_end_iter (tbuffer, &end);
+ gtk_text_buffer_delete (tbuffer, &start, &end);
- /* DN */
- gtk_text_buffer_insert_with_tags_by_name (tbuffer, ¤t, _("Distinguished Name:"), -1,
- "section", NULL);
- gtk_text_buffer_insert (tbuffer, ¤t, "\n", -1);
- gtk_text_buffer_insert_with_tags_by_name (tbuffer, ¤t, " ", -1, "starter", NULL);
- gtk_text_buffer_insert_with_tags_by_name (tbuffer, ¤t, entry->dn, -1,
- "data", NULL);
+ guint i;
+ GtkTextIter current;
+
+ gtk_text_buffer_get_start_iter (tbuffer, ¤t);
+
+ /* DN */
+ gtk_text_buffer_insert_with_tags_by_name (tbuffer, ¤t, _("Distinguished Name:"), -1,
+ "section", NULL);
+ gtk_text_buffer_insert (tbuffer, ¤t, "\n", -1);
+ gtk_text_buffer_insert_with_tags_by_name (tbuffer, ¤t, " ", -1, "starter", NULL);
+ gtk_text_buffer_insert_with_tags_by_name (tbuffer, ¤t, entry->dn, -1,
+ "data", NULL);
+ gtk_text_buffer_insert (tbuffer, ¤t, "\n", -1);
+
+ /* other attributes */
+ const gchar *basedn;
+ GdaDataHandler *ts_dh = NULL;
+ basedn = browser_connection_ldap_get_base_dn (bcnc);
+
+ for (i = 0; i < entry->nb_attributes; i++) {
+ GdaLdapAttribute *attr;
+ gchar *tmp;
+ attr = entry->attributes [i];
+ tmp = g_strdup_printf ("%s:", attr->attr_name);
+ gtk_text_buffer_insert_with_tags_by_name (tbuffer, ¤t, tmp, -1, "section", NULL);
+ g_free (tmp);
gtk_text_buffer_insert (tbuffer, ¤t, "\n", -1);
- /* other attributes */
- const gchar *basedn;
- GdaDataHandler *ts_dh = NULL;
- basedn = browser_connection_ldap_get_base_dn (bcnc);
-
- for (i = 0; i < entry->nb_attributes; i++) {
- GdaLdapAttribute *attr;
- gchar *tmp;
- attr = entry->attributes [i];
- tmp = g_strdup_printf ("%s:", attr->attr_name);
- gtk_text_buffer_insert_with_tags_by_name (tbuffer, ¤t, tmp, -1, "section",
NULL);
- g_free (tmp);
- gtk_text_buffer_insert (tbuffer, ¤t, "\n", -1);
-
- guint j;
- for (j = 0; j < attr->nb_values; j++) {
- const GValue *cvalue;
- cvalue = attr->values [j];
-
- gtk_text_buffer_insert_with_tags_by_name (tbuffer, ¤t, " ", -1,
- "starter", NULL);
-
- if (G_VALUE_TYPE (cvalue) == GDA_TYPE_BINARY) {
- GValue *copyvalue;
- GtkTextTagTable *table;
- GtkTextTag *tag;
- GtkTextMark *mark;
-
- copyvalue = gda_value_copy (cvalue);
- table = gtk_text_buffer_get_tag_table (tbuffer);
- tag = gtk_text_tag_new (NULL);
- gtk_text_tag_table_add (table, tag);
- g_object_set_data_full ((GObject*) tag, "binvalue",
- copyvalue, (GDestroyNotify) gda_value_free);
- g_object_unref ((GObject*) tag);
-
- mark = gtk_text_buffer_create_mark (tbuffer, NULL, ¤t, TRUE);
-
- GdkPixbuf *pixbuf;
- pixbuf = data_to_pixbuf (cvalue);
- if (pixbuf) {
- gtk_text_buffer_insert_pixbuf (tbuffer, ¤t, pixbuf);
- g_object_unref (pixbuf);
- }
- else {
- GdaDataHandler *dh;
- dh = gda_data_handler_get_default (G_VALUE_TYPE (cvalue));
- if (dh)
- tmp = gda_data_handler_get_str_from_value (dh,
cvalue);
- else
- tmp = gda_value_stringify (cvalue);
- gtk_text_buffer_insert_with_tags_by_name (tbuffer, ¤t,
- tmp, -1,
- "data", NULL);
- g_free (tmp);
- }
- GtkTextIter before;
- gtk_text_buffer_get_iter_at_mark (tbuffer, &before, mark);
- gtk_text_buffer_apply_tag (tbuffer, tag, &before, ¤t);
- gtk_text_buffer_delete_mark (tbuffer, mark);
-
- gtk_text_buffer_insert_with_tags_by_name (tbuffer, ¤t,
- "\n", 1,
- "data", NULL);
+ guint j;
+ for (j = 0; j < attr->nb_values; j++) {
+ const GValue *cvalue;
+ cvalue = attr->values [j];
+
+ gtk_text_buffer_insert_with_tags_by_name (tbuffer, ¤t, " ", -1,
+ "starter", NULL);
+
+ if (G_VALUE_TYPE (cvalue) == GDA_TYPE_BINARY) {
+ GValue *copyvalue;
+ GtkTextTagTable *table;
+ GtkTextTag *tag;
+ GtkTextMark *mark;
+
+ copyvalue = gda_value_copy (cvalue);
+ table = gtk_text_buffer_get_tag_table (tbuffer);
+ tag = gtk_text_tag_new (NULL);
+ gtk_text_tag_table_add (table, tag);
+ g_object_set_data_full ((GObject*) tag, "binvalue",
+ copyvalue, (GDestroyNotify) gda_value_free);
+ g_object_unref ((GObject*) tag);
+
+ mark = gtk_text_buffer_create_mark (tbuffer, NULL, ¤t, TRUE);
+
+ GdkPixbuf *pixbuf;
+ pixbuf = data_to_pixbuf (cvalue);
+ if (pixbuf) {
+ gtk_text_buffer_insert_pixbuf (tbuffer, ¤t, pixbuf);
+ g_object_unref (pixbuf);
}
else {
GdaDataHandler *dh;
@@ -841,89 +819,107 @@ info_fetch_cb (BrowserConnection *bcnc, gpointer out_result, EntryProperties *ep
tmp = gda_data_handler_get_str_from_value (dh, cvalue);
else
tmp = gda_value_stringify (cvalue);
- if (tmp) {
- if (*tmp &&
- ((basedn && g_str_has_suffix (tmp, basedn)) || !basedn) &&
- gda_ldap_is_dn (tmp)) {
- /* we have a DN */
- GtkTextTag *tag;
- tag = gtk_text_buffer_create_tag (tbuffer, NULL,
- "foreground",
"blue",
- "weight",
PANGO_WEIGHT_NORMAL,
- "underline",
PANGO_UNDERLINE_SINGLE,
- NULL);
- g_object_set_data_full (G_OBJECT (tag), "dn",
- g_strdup (tmp), g_free);
- gtk_text_buffer_insert_with_tags (tbuffer, ¤t,
- tmp, -1,
- tag, NULL);
- }
- else if (attr->attr_name &&
- !g_ascii_strcasecmp (attr->attr_name,
"objectClass")) {
- GtkTextTag *tag;
- tag = gtk_text_buffer_create_tag (tbuffer, NULL,
- "foreground",
"blue",
- "weight",
PANGO_WEIGHT_NORMAL,
- "underline",
PANGO_UNDERLINE_SINGLE,
- NULL);
- g_object_set_data_full (G_OBJECT (tag), "class",
- g_strdup (tmp), g_free);
- gtk_text_buffer_insert_with_tags (tbuffer, ¤t,
- tmp, -1,
- tag, NULL);
- }
- else
- gtk_text_buffer_insert_with_tags_by_name (tbuffer,
¤t, tmp, -1,
- "data",
NULL);
-
- gchar *extrainfo = NULL;
- if (!strncmp (attr->attr_name, "shadow", 6) &&
- (!strcmp (attr->attr_name, "shadowLastChange") ||
- !strcmp (attr->attr_name, "shadowMax") ||
- !strcmp (attr->attr_name, "shadowMin") ||
- !strcmp (attr->attr_name, "shadowInactive") ||
- !strcmp (attr->attr_name, "shadowExpire")))
- extrainfo = unix_shadow_to_string (tmp,
attr->attr_name);
- else if (!strcmp (attr->attr_name, "badPasswordTime") ||
- !strcmp (attr->attr_name, "lastLogon") ||
- !strcmp (attr->attr_name, "pwdLastSet") ||
- !strcmp (attr->attr_name, "accountExpires") ||
- !strcmp (attr->attr_name, "lockoutTime") ||
- !strcmp (attr->attr_name, "lastLogonTimestamp"))
- extrainfo = ad_1601_timestamp_to_string (tmp,
attr->attr_name);
- else if (!strcmp (attr->attr_name, "userAccountControl"))
- extrainfo = ad_1601_uac_to_string (tmp);
- else if (!strcmp (attr->attr_name, "sAMAccountType"))
- extrainfo = ad_sam_account_type_to_string (tmp);
-
- if (extrainfo) {
- gtk_text_buffer_insert_with_tags_by_name (tbuffer,
¤t,
- " ", 1,
- "data",
NULL);
- gtk_text_buffer_insert_with_tags_by_name (tbuffer,
¤t,
- extrainfo,
-1,
- "convdata",
NULL);
- g_free (extrainfo);
- }
- g_free (tmp);
- }
- else {
- gtk_text_buffer_insert_with_tags_by_name (tbuffer, ¤t,
_("Can't display attribute value"), -1,
- "error", NULL);
- }
gtk_text_buffer_insert_with_tags_by_name (tbuffer, ¤t,
- "\n", 1,
+ tmp, -1,
"data", NULL);
+ g_free (tmp);
}
+ GtkTextIter before;
+ gtk_text_buffer_get_iter_at_mark (tbuffer, &before, mark);
+ gtk_text_buffer_apply_tag (tbuffer, tag, &before, ¤t);
+ gtk_text_buffer_delete_mark (tbuffer, mark);
+
+ gtk_text_buffer_insert_with_tags_by_name (tbuffer, ¤t,
+ "\n", 1,
+ "data", NULL);
+ }
+ else {
+ GdaDataHandler *dh;
+ dh = gda_data_handler_get_default (G_VALUE_TYPE (cvalue));
+ if (dh)
+ tmp = gda_data_handler_get_str_from_value (dh, cvalue);
+ else
+ tmp = gda_value_stringify (cvalue);
+ if (tmp) {
+ if (*tmp &&
+ ((basedn && g_str_has_suffix (tmp, basedn)) || !basedn) &&
+ gda_ldap_is_dn (tmp)) {
+ /* we have a DN */
+ GtkTextTag *tag;
+ tag = gtk_text_buffer_create_tag (tbuffer, NULL,
+ "foreground", "blue",
+ "weight",
PANGO_WEIGHT_NORMAL,
+ "underline",
PANGO_UNDERLINE_SINGLE,
+ NULL);
+ g_object_set_data_full (G_OBJECT (tag), "dn",
+ g_strdup (tmp), g_free);
+ gtk_text_buffer_insert_with_tags (tbuffer, ¤t,
+ tmp, -1,
+ tag, NULL);
+ }
+ else if (attr->attr_name &&
+ !g_ascii_strcasecmp (attr->attr_name, "objectClass")) {
+ GtkTextTag *tag;
+ tag = gtk_text_buffer_create_tag (tbuffer, NULL,
+ "foreground", "blue",
+ "weight",
PANGO_WEIGHT_NORMAL,
+ "underline",
PANGO_UNDERLINE_SINGLE,
+ NULL);
+ g_object_set_data_full (G_OBJECT (tag), "class",
+ g_strdup (tmp), g_free);
+ gtk_text_buffer_insert_with_tags (tbuffer, ¤t,
+ tmp, -1,
+ tag, NULL);
+ }
+ else
+ gtk_text_buffer_insert_with_tags_by_name (tbuffer, ¤t,
tmp, -1,
+ "data", NULL);
+
+ gchar *extrainfo = NULL;
+ if (!strncmp (attr->attr_name, "shadow", 6) &&
+ (!strcmp (attr->attr_name, "shadowLastChange") ||
+ !strcmp (attr->attr_name, "shadowMax") ||
+ !strcmp (attr->attr_name, "shadowMin") ||
+ !strcmp (attr->attr_name, "shadowInactive") ||
+ !strcmp (attr->attr_name, "shadowExpire")))
+ extrainfo = unix_shadow_to_string (tmp, attr->attr_name);
+ else if (!strcmp (attr->attr_name, "badPasswordTime") ||
+ !strcmp (attr->attr_name, "lastLogon") ||
+ !strcmp (attr->attr_name, "pwdLastSet") ||
+ !strcmp (attr->attr_name, "accountExpires") ||
+ !strcmp (attr->attr_name, "lockoutTime") ||
+ !strcmp (attr->attr_name, "lastLogonTimestamp"))
+ extrainfo = ad_1601_timestamp_to_string (tmp,
attr->attr_name);
+ else if (!strcmp (attr->attr_name, "userAccountControl"))
+ extrainfo = ad_1601_uac_to_string (tmp);
+ else if (!strcmp (attr->attr_name, "sAMAccountType"))
+ extrainfo = ad_sam_account_type_to_string (tmp);
+
+ if (extrainfo) {
+ gtk_text_buffer_insert_with_tags_by_name (tbuffer, ¤t,
+ " ", 1,
+ "data", NULL);
+ gtk_text_buffer_insert_with_tags_by_name (tbuffer, ¤t,
+ extrainfo, -1,
+ "convdata", NULL);
+ g_free (extrainfo);
+ }
+ g_free (tmp);
+ }
+ else {
+ gtk_text_buffer_insert_with_tags_by_name (tbuffer, ¤t, _("Can't
display attribute value"), -1,
+ "error", NULL);
+ }
+ gtk_text_buffer_insert_with_tags_by_name (tbuffer, ¤t,
+ "\n", 1,
+ "data", NULL);
}
}
- if (ts_dh)
- g_object_unref (ts_dh);
- gda_ldap_entry_free (entry);
}
- else
- browser_show_message (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) eprop)),
- "%s", _("Could not get information about LDAP entry"));
+ if (ts_dh)
+ g_object_unref (ts_dh);
+ gda_ldap_entry_free (entry);
+
if (eprop->priv->text_search && gtk_widget_get_visible (eprop->priv->text_search))
text_search_rerun (TEXT_SEARCH (eprop->priv->text_search));
@@ -952,11 +948,11 @@ entry_properties_set_dn (EntryProperties *eprop, const gchar *dn)
gtk_text_buffer_delete (tbuffer, &start, &end);
if (dn && *dn) {
- guint id;
- id = browser_connection_ldap_describe_entry (eprop->priv->bcnc, dn,
- (BrowserConnectionJobCallback) info_fetch_cb,
- g_object_ref (eprop), NULL);
- if (id == 0)
+ GdaLdapEntry *entry;
+ entry = browser_connection_ldap_describe_entry (eprop->priv->bcnc, dn, NULL);
+ if (entry)
+ entry_info_fetched_done (eprop, entry);
+ else
browser_show_message (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) eprop)),
"%s", _("Could not get information about LDAP entry"));
}
diff --git a/tools/browser/ldap-browser/ldap-search-page.c b/tools/browser/ldap-browser/ldap-search-page.c
index 6d81b22..4055c18 100644
--- a/tools/browser/ldap-browser/ldap-search-page.c
+++ b/tools/browser/ldap-browser/ldap-search-page.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2011 Murray Cumming <murrayc murrayc com>
- * Copyright (C) 2011 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2011 - 2014 Vivien Malerba <malerba gnome-db org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -203,53 +203,39 @@ update_history_actions (LdapSearchPage *epage)
}
static void
-search_done_cb (G_GNUC_UNUSED BrowserConnection *bcnc,
- gpointer out_result, LdapSearchPage *epage, G_GNUC_UNUSED GError *error)
+filter_exec_clicked_cb (G_GNUC_UNUSED GtkWidget *button, LdapSearchPage *epage)
{
+ guint id;
+ gchar *base_dn, *filter, *attributes;
+ GdaLdapSearchScope scope;
+ GError *lerror = NULL;
+ filter_editor_get_settings (FILTER_EDITOR (epage->priv->search_entry),
+ &base_dn, &filter, &attributes, &scope);
+
+ GdaDataModel *model;
+ model = browser_connection_ldap_search (epage->priv->bcnc,
+ base_dn, filter,
+ attributes, scope, &lerror);
+ g_free (base_dn);
+ g_free (filter);
+ g_free (attributes);
+
if (epage->priv->result_view) {
gtk_widget_destroy (epage->priv->result_view);
epage->priv->result_view = NULL;
}
- if (out_result == (gpointer) 0x01) {
- TO_IMPLEMENT;
- }
- else {
- GdaDataModel *model;
+
+ if (model) {
GtkWidget *wid;
- model = GDA_DATA_MODEL (out_result);
wid = ui_formgrid_new (model, TRUE, GDAUI_DATA_PROXY_INFO_CURRENT_ROW);
g_object_unref (model);
gtk_box_pack_start (GTK_BOX (epage), wid, TRUE, TRUE, 0);
epage->priv->result_view = wid;
gtk_widget_show (wid);
}
- g_object_unref (G_OBJECT (epage));
-}
-
-static void
-filter_exec_clicked_cb (G_GNUC_UNUSED GtkWidget *button, LdapSearchPage *epage)
-{
- guint id;
- gchar *base_dn, *filter, *attributes;
- GdaLdapSearchScope scope;
- GError *lerror = NULL;
- filter_editor_get_settings (FILTER_EDITOR (epage->priv->search_entry),
- &base_dn, &filter, &attributes, &scope);
-
- id = browser_connection_ldap_search (epage->priv->bcnc,
- base_dn, filter,
- attributes, scope,
- BROWSER_CONNECTION_JOB_CALLBACK (search_done_cb),
- g_object_ref (G_OBJECT (epage)), &lerror);
-
- if (id == 0) {
+ else {
TO_IMPLEMENT;
- g_clear_error (&lerror);
}
-
- g_free (base_dn);
- g_free (filter);
- g_free (attributes);
}
static void
diff --git a/tools/browser/ldap-browser/mgr-ldap-entries.c b/tools/browser/ldap-browser/mgr-ldap-entries.c
index a85bb7c..4f192e8 100644
--- a/tools/browser/ldap-browser/mgr-ldap-entries.c
+++ b/tools/browser/ldap-browser/mgr-ldap-entries.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2011 Murray Cumming <murrayc murrayc com>
- * Copyright (C) 2011 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2011 - 2014 Vivien Malerba <malerba gnome-db org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -141,22 +141,6 @@ mgr_ldap_entries_new (BrowserConnection *bcnc, const gchar *dn)
return (GdaTreeManager*) mgr;
}
-typedef struct {
- GMainLoop *loop;
- GdaLdapEntry **entries;
- GError *error;
-} AsyncExecData;
-
-static void
-update_children_cb (G_GNUC_UNUSED BrowserConnection *bcnc,
- gpointer out_result, AsyncExecData *data, GError *error)
-{
- data->entries = (GdaLdapEntry **) out_result;
- if (! data->entries && error)
- data->error = g_error_copy (error);
- g_main_loop_quit (data->loop);
-}
-
static gint
lentry_array_sort_func (gconstpointer a, gconstpointer b)
{
@@ -182,8 +166,8 @@ lentry_array_sort_func (gconstpointer a, gconstpointer b)
static GSList *
mgr_ldap_entries_update_children (GdaTreeManager *manager, GdaTreeNode *node,
- G_GNUC_UNUSED const GSList *children_nodes, gboolean *out_error,
- GError **error)
+ G_GNUC_UNUSED const GSList *children_nodes, gboolean *out_error,
+ GError **error)
{
MgrLdapEntries *mgr = MGR_LDAP_ENTRIES (manager);
gchar *real_dn = NULL;
@@ -200,37 +184,21 @@ mgr_ldap_entries_update_children (GdaTreeManager *manager, GdaTreeNode *node,
real_dn = g_value_dup_string (cvalue);
}
- AsyncExecData data;
- guint id;
- data.loop = NULL;
- data.entries = NULL;
- data.error = NULL;
+ GdaLdapEntry **entries;
gchar *attrs[] = {"objectClass", "cn", NULL};
+ entries = browser_connection_ldap_get_entry_children (mgr->priv->bcnc, real_dn, attrs, error);
- id = browser_connection_ldap_get_entry_children (mgr->priv->bcnc, real_dn, attrs,
- BROWSER_CONNECTION_JOB_CALLBACK (update_children_cb),
- &data, error);
- g_free (real_dn);
- if (id == 0) {
- if (out_error)
- *out_error = TRUE;
- return NULL;
- }
- data.loop = g_main_loop_new (NULL, FALSE);
- g_main_loop_run (data.loop);
- g_main_loop_unref (data.loop);
-
- if (data.entries) {
+ if (entries) {
guint i;
GSList *list = NULL;
GArray *sorted_array;
sorted_array = g_array_new (FALSE, FALSE, sizeof (GdaLdapEntry*));
- for (i = 0; data.entries [i]; i++) {
+ for (i = 0; entries [i]; i++) {
GdaLdapEntry *lentry;
- lentry = data.entries [i];
+ lentry = entries [i];
g_array_prepend_val (sorted_array, lentry);
}
- g_free (data.entries);
+ g_free (entries);
g_array_sort (sorted_array, (GCompareFunc) lentry_array_sort_func);
@@ -297,10 +265,6 @@ mgr_ldap_entries_update_children (GdaTreeManager *manager, GdaTreeNode *node,
return list;
}
- else {
- g_propagate_error (error, data.error);
- if (out_error)
- *out_error = TRUE;
+ else
return NULL;
- }
}
diff --git a/tools/browser/login-dialog.c b/tools/browser/login-dialog.c
index a8db035..e1b470d 100644
--- a/tools/browser/login-dialog.c
+++ b/tools/browser/login-dialog.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 - 2012 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2009 - 2014 Vivien Malerba <malerba gnome-db org>
* Copyright (C) 2010 David King <davidk openismus com>
* Copyright (C) 2011 Murray Cumming <murrayc murrayc com>
*
@@ -23,7 +23,6 @@
#include "login-dialog.h"
#include "browser-spinner.h"
#include "support.h"
-#include <libgda/thread-wrapper/gda-thread-wrapper.h>
/*
* Main static functions
@@ -32,7 +31,7 @@ static void login_dialog_class_init (LoginDialogClass * class);
static void login_dialog_init (LoginDialog *dialog);
static void login_dialog_dispose (GObject *object);
-static GdaConnection *real_open_connection (GdaThreadWrapper *wrapper, const GdaDsnInfo *cncinfo, GError
**error);
+static GdaConnection *real_open_connection (const GdaDsnInfo *cncinfo, GError **error);
/* get a pointer to the parents to be able to call their destructor */
static GObjectClass *parent_class = NULL;
@@ -41,7 +40,6 @@ struct _LoginDialogPrivate
{
GtkWidget *login;
GtkWidget *spinner;
- GdaThreadWrapper *wrapper;
};
/* module error */
@@ -170,8 +168,6 @@ login_dialog_dispose (GObject *object)
LoginDialog *dialog;
dialog = LOGIN_DIALOG (object);
if (dialog->priv) {
- if (dialog->priv->wrapper)
- g_object_unref (dialog->priv->wrapper);
g_free (dialog->priv);
dialog->priv = NULL;
}
@@ -227,12 +223,9 @@ login_dialog_run (LoginDialog *dialog, gboolean retry, GError **error)
if (result == GTK_RESPONSE_ACCEPT) {
const GdaDsnInfo *info;
GError *lerror = NULL;
-
- if (!dialog->priv->wrapper)
- dialog->priv->wrapper = gda_thread_wrapper_new ();
info = gdaui_login_get_connection_information (GDAUI_LOGIN (dialog->priv->login));
- cnc = real_open_connection (dialog->priv->wrapper, info, &lerror);
+ cnc = real_open_connection (info, &lerror);
browser_spinner_stop (BROWSER_SPINNER (dialog->priv->spinner));
if (cnc)
goto out;
@@ -268,70 +261,6 @@ login_dialog_run (LoginDialog *dialog, gboolean retry, GError **error)
return cnc;
}
-/*
- * executed in a sub thread
- */
-static GdaConnection *
-sub_thread_open_cnc (GdaDsnInfo *info, GError **error)
-{
-#ifndef DUMMY
- GdaConnection *cnc;
- if (info->name)
- cnc = gda_connection_open_from_dsn (info->name, info->auth_string,
- GDA_CONNECTION_OPTIONS_THREAD_SAFE |
- GDA_CONNECTION_OPTIONS_AUTO_META_DATA,
- error);
- else
- cnc = gda_connection_open_from_string (info->provider, info->cnc_string,
- info->auth_string,
- GDA_CONNECTION_OPTIONS_THREAD_SAFE |
- GDA_CONNECTION_OPTIONS_AUTO_META_DATA,
- error);
- return cnc;
-#else /* DUMMY defined */
- sleep (5);
- g_set_error (error, GDA_TOOLS_INTERNAL_COMMAND_ERROR, "%s", "Dummy error!");
- return NULL;
-#endif
-}
-
-static void
-dsn_info_free (GdaDsnInfo *info)
-{
- g_free (info->name);
- g_free (info->provider);
- g_free (info->cnc_string);
- g_free (info->auth_string);
- g_free (info);
-}
-
-typedef struct {
- guint cncid;
- GMainLoop *loop;
- GError **error;
- GdaThreadWrapper *wrapper;
-
- /* out */
- GdaConnection *cnc;
-} MainloopData;
-
-static gboolean
-check_for_cnc (MainloopData *data)
-{
- GdaConnection *cnc;
- GError *lerror = NULL;
- cnc = gda_thread_wrapper_fetch_result (data->wrapper, FALSE, data->cncid, &lerror);
- if (cnc || (!cnc && lerror)) {
- /* waiting is finished! */
- data->cnc = cnc;
- if (lerror)
- g_propagate_error (data->error, lerror);
- g_main_loop_quit (data->loop);
- return FALSE;
- }
- return TRUE;
-}
-
/**
* real_open_connection
* @cncinfo: a pointer to a #GdaDsnInfo, describing the connection to open
@@ -342,46 +271,24 @@ check_for_cnc (MainloopData *data)
* Returns: a new #GdaConnection, or %NULL if an error occurred
*/
static GdaConnection *
-real_open_connection (GdaThreadWrapper *wrapper, const GdaDsnInfo *cncinfo, GError **error)
+real_open_connection (const GdaDsnInfo *cncinfo, GError **error)
{
-
- GdaDsnInfo *info;
- guint cncid;
+#ifdef DUMMY
+ sleep (5);
+ g_set_error (error, GDA_TOOLS_INTERNAL_COMMAND_ERROR, "%s", "Dummy error!");
+ return NULL;
+#endif
- info = g_new0 (GdaDsnInfo, 1);
+ GdaConnection *cnc;
if (cncinfo->name)
- info->name = g_strdup (cncinfo->name);
- if (cncinfo->provider)
- info->provider = g_strdup (cncinfo->provider);
- if (cncinfo->cnc_string)
- info->cnc_string = g_strdup (cncinfo->cnc_string);
- if (cncinfo->auth_string)
- info->auth_string = g_strdup (cncinfo->auth_string);
-
- cncid = gda_thread_wrapper_execute (wrapper,
- (GdaThreadWrapperFunc) sub_thread_open_cnc,
- (gpointer) info,
- (GDestroyNotify) dsn_info_free,
- error);
- if (cncid == 0)
- return NULL;
-
- GMainLoop *loop;
- MainloopData data;
-
- loop = g_main_loop_new (NULL, FALSE);
+ cnc = gda_connection_open_from_dsn (cncinfo->name, cncinfo->auth_string,
+ GDA_CONNECTION_OPTIONS_AUTO_META_DATA,
+ error);
+ else
+ cnc = gda_connection_open_from_string (cncinfo->provider, cncinfo->cnc_string,
+ cncinfo->auth_string,
+ GDA_CONNECTION_OPTIONS_AUTO_META_DATA,
+ error);
- data.cncid = cncid;
- data.error = error;
- data.loop = loop;
- data.cnc = NULL;
- data.wrapper = wrapper;
-
- g_timeout_add (200, (GSourceFunc) check_for_cnc, &data);
- g_main_loop_run (loop);
- g_main_loop_unref (loop);
-
- if (data.cnc)
- g_object_set (data.cnc, "monitor-wrapped-in-mainloop", TRUE, NULL);
- return data.cnc;
+ return cnc;
}
diff --git a/tools/browser/mgr-favorites.c b/tools/browser/mgr-favorites.c
index 5358fce..9fe0102 100644
--- a/tools/browser/mgr-favorites.c
+++ b/tools/browser/mgr-favorites.c
@@ -781,20 +781,6 @@ mgr_favorites_update_children (GdaTreeManager *manager, GdaTreeNode *node, const
return g_slist_reverse (nodes_list);
}
-static void
-icon_fetched_cb (G_GNUC_UNUSED BrowserConnection *bcnc,
- GdkPixbuf *pixbuf, GdaTreeNode *node, G_GNUC_UNUSED GError *error)
-{
- if (pixbuf) {
- GValue *av;
- av = gda_value_new (G_TYPE_OBJECT);
- g_value_set_object (av, pixbuf);
- gda_tree_node_set_node_attribute (node, "icon", av, NULL);
- gda_value_free (av);
- }
- g_object_unref (node);
-}
-
#ifdef HAVE_LDAP
static gboolean
icons_resol_cb (MgrFavorites *mgr)
@@ -807,10 +793,15 @@ icons_resol_cb (MgrFavorites *mgr)
mgr->priv->icons_resol_list = g_slist_delete_link (mgr->priv->icons_resol_list,
mgr->priv->icons_resol_list);
- if (browser_connection_ldap_icon_for_dn (mgr->priv->bcnc, data->dn,
- (BrowserConnectionJobCallback) icon_fetched_cb,
- g_object_ref (data->node), NULL) == 0)
- g_object_unref (data->node);
+ GdkPixbuf *pixbuf;
+ pixbuf = browser_connection_ldap_icon_for_dn (mgr->priv->bcnc, data->dn, NULL);
+ if (pixbuf) {
+ GValue *av;
+ av = gda_value_new (G_TYPE_OBJECT);
+ g_value_set_object (av, pixbuf);
+ gda_tree_node_set_node_attribute ((GdaTreeNode*) data->node, "icon", av, NULL);
+ gda_value_free (av);
+ }
icon_resolution_data_free (data);
}
diff --git a/tools/browser/query-exec/query-console-page.c b/tools/browser/query-exec/query-console-page.c
index 5dd65ec..7992823 100644
--- a/tools/browser/query-exec/query-console-page.c
+++ b/tools/browser/query-exec/query-console-page.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 - 2012 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2009 - 2014 Vivien Malerba <malerba gnome-db org>
* Copyright (C) 2010 David King <davidk openismus com>
* Copyright (C) 2011 Murray Cumming <murrayc murrayc com>
*
@@ -35,63 +35,6 @@
#include <libgda-ui/libgda-ui.h>
#include <libgda/gda-debug-macros.h>
-/*
- * Statement execution structures
- */
-typedef struct {
- GTimeVal start_time;
- GdaBatch *batch; /* ref held here */
- QueryEditorHistoryBatch *hist_batch; /* ref held here */
- GSList *statements; /* list of ExecutionStatament */
-} ExecutionBatch;
-static void execution_batch_free (ExecutionBatch *ebatch);
-
-typedef struct {
- GdaStatement *stmt /* no ref held here */;
- gboolean within_transaction;
- GError *exec_error;
- GObject *result;
- guint exec_id; /* 0 when execution not requested */
-} ExecutionStatement;
-static void execution_statement_free (ExecutionStatement *estmt);
-
-/*
- * Frees an @ExecutionBatch
- *
- * If necessary, may set up and idle handler to perform some
- * additionnal jobs
- */
-static void
-execution_batch_free (ExecutionBatch *ebatch)
-{
- GSList *list;
- for (list = ebatch->statements; list; list = list->next)
- execution_statement_free ((ExecutionStatement*) list->data);
- g_slist_free (ebatch->statements);
-
- g_object_unref (ebatch->batch);
- if (ebatch->hist_batch)
- query_editor_history_batch_unref (ebatch->hist_batch);
-
- g_free (ebatch);
-}
-
-static void
-execution_statement_free (ExecutionStatement *estmt)
-{
- if (estmt->exec_id > 0) {
- /* job started! */
- TO_IMPLEMENT;
- }
- else {
- if (estmt->exec_error)
- g_error_free (estmt->exec_error);
- if (estmt->result)
- g_object_unref (estmt->result);
- g_free (estmt);
- }
-}
-
struct _QueryConsolePagePrivate {
BrowserConnection *bcnc;
GdaSqlParser *parser;
@@ -119,7 +62,7 @@ struct _QueryConsolePagePrivate {
GtkWidget *query_result;
- ExecutionBatch *current_exec;
+ gboolean currently_executing;
gint fav_id;
GtkWidget *favorites_menu;
@@ -198,8 +141,6 @@ query_console_page_dispose (GObject *object)
/* free memory */
if (tconsole->priv) {
- if (tconsole->priv->current_exec)
- execution_batch_free (tconsole->priv->current_exec);
if (tconsole->priv->bcnc) {
g_signal_handlers_disconnect_by_func (tconsole->priv->bcnc,
G_CALLBACK (connection_busy_cb), tconsole);
@@ -980,120 +921,6 @@ sql_execute_clicked_cb (G_GNUC_UNUSED GtkButton *button, QueryConsolePage *tcons
}
static void
-query_exec_done_cb (BrowserConnection *bcnc, guint exec_id,
- GObject *out_result, GdaSet *out_last_inserted_row,
- GError *error, QueryConsolePage *tconsole)
-{
- gboolean alldone = TRUE;
-
- if (! tconsole->priv->current_exec)
- return;
-
- if (! tconsole->priv->current_exec->statements) {
- execution_batch_free (tconsole->priv->current_exec);
- tconsole->priv->current_exec = NULL;
- return;
- }
-
- ExecutionStatement *estmt;
- estmt = (ExecutionStatement*) tconsole->priv->current_exec->statements->data;
- g_assert (estmt->exec_id == exec_id);
- g_assert (!estmt->result);
- g_assert (!estmt->exec_error);
-
- ExecutionBatch *ebatch;
- ebatch = tconsole->priv->current_exec;
- query_editor_start_history_batch (tconsole->priv->history, ebatch->hist_batch);
- if (out_result)
- estmt->result = g_object_ref (out_result);
- if (error)
- estmt->exec_error = g_error_copy (error);
-
- QueryEditorHistoryItem *history;
- GdaSqlStatement *sqlst;
- g_object_get (G_OBJECT (estmt->stmt), "structure", &sqlst, NULL);
- if (!sqlst->sql) {
- gchar *sql;
- sql = gda_statement_to_sql (GDA_STATEMENT (estmt->stmt), NULL, NULL);
- history = query_editor_history_item_new (sql, estmt->result, estmt->exec_error);
- g_free (sql);
- }
- else
- history = query_editor_history_item_new (sqlst->sql,
- estmt->result, estmt->exec_error);
- gda_sql_statement_free (sqlst);
-
- history->within_transaction = estmt->within_transaction;
-
- /* display a message if a transaction has been started */
- if (! history->within_transaction &&
- browser_connection_get_transaction_status (tconsole->priv->bcnc) &&
- gda_statement_get_statement_type (estmt->stmt) != GDA_SQL_STATEMENT_BEGIN) {
- browser_window_show_notice_printf (BROWSER_WINDOW (gtk_widget_get_toplevel ((GtkWidget*)
tconsole)),
- GTK_MESSAGE_INFO,
- "QueryExecTransactionStarted",
- "%s", _("A transaction has automatically been started\n"
- "during this statement's execution, this usually\n"
- "happens when blobs are selected (and the
transaction\n"
- "will have to remain opened while the blobs are
still\n"
- "accessible, clear the corresponding history item
before\n"
- "closing the transaction)."));
- }
-
- query_editor_add_history_item (tconsole->priv->history, history);
- query_editor_history_item_unref (history);
-
- if (estmt->exec_error)
- browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) tconsole)),
- _("Error executing query:\n%s"),
- estmt->exec_error && estmt->exec_error->message ?
- estmt->exec_error->message : _("No detail"));
- else
- browser_window_push_status (BROWSER_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) tconsole)),
- "QueryConsolePage", _("Statement executed"), TRUE);
-
- /* get rid of estmt */
- estmt->exec_id = 0;
- execution_statement_free (estmt);
- tconsole->priv->current_exec->statements =
- g_slist_delete_link (tconsole->priv->current_exec->statements,
- tconsole->priv->current_exec->statements);
- if (error)
- goto onerror;
-
- /* more to do ? */
- if (tconsole->priv->current_exec->statements) {
- estmt = (ExecutionStatement*) tconsole->priv->current_exec->statements->data;
- estmt->within_transaction =
- browser_connection_get_transaction_status (tconsole->priv->bcnc) ? TRUE : FALSE;
- estmt->exec_id = browser_connection_execute_statement_cb (tconsole->priv->bcnc,
- estmt->stmt,
- tconsole->priv->params,
- GDA_STATEMENT_MODEL_RANDOM_ACCESS,
- FALSE,
- (BrowserConnectionExecuteCallback)
query_exec_done_cb,
- tconsole, &(estmt->exec_error));
- if (estmt->exec_id == 0) {
- browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) tconsole)),
- _("Error executing query:\n%s"),
- estmt->exec_error && estmt->exec_error->message ?
- estmt->exec_error->message : _("No detail"));
- goto onerror;
- }
- }
-
- if (! tconsole->priv->current_exec->statements) {
- execution_batch_free (tconsole->priv->current_exec);
- tconsole->priv->current_exec = NULL;
- }
- return;
-
- onerror:
- execution_batch_free (tconsole->priv->current_exec);
- tconsole->priv->current_exec = NULL;
-}
-
-static void
actually_execute (QueryConsolePage *tconsole, const gchar *sql, GdaSet *params,
gboolean add_editor_history)
{
@@ -1101,6 +928,15 @@ actually_execute (QueryConsolePage *tconsole, const gchar *sql, GdaSet *params,
GError *error = NULL;
const gchar *remain;
+ /* if a query is being executed, then show an error */
+ if (tconsole->priv->currently_executing) {
+ browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) tconsole)),
+ _("A query is already being executed, "
+ "to execute another query, open a new connection."));
+ return;
+ }
+ tconsole->priv->currently_executing = TRUE;
+
if (!tconsole->priv->parser)
tconsole->priv->parser = browser_connection_create_parser (tconsole->priv->bcnc);
@@ -1113,15 +949,6 @@ actually_execute (QueryConsolePage *tconsole, const gchar *sql, GdaSet *params,
return;
}
- /* if a query is being executed, then show an error */
- if (tconsole->priv->current_exec) {
- g_object_unref (batch);
- browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) tconsole)),
- _("A query is already being executed, "
- "to execute another query, open a new connection."));
- return;
- }
-
if (add_editor_history) {
/* mark the current SQL to be kept by the editor as an internal history */
query_editor_keep_current_state (tconsole->priv->editor);
@@ -1129,45 +956,72 @@ actually_execute (QueryConsolePage *tconsole, const gchar *sql, GdaSet *params,
/* actual Execution */
const GSList *stmt_list, *list;
- ExecutionBatch *ebatch;
- ebatch = g_new0 (ExecutionBatch, 1);
- ebatch->batch = batch;
- g_get_current_time (&(ebatch->start_time));
- ebatch->hist_batch = query_editor_history_batch_new (ebatch->start_time, params);
+ GTimeVal start_time;
+ g_get_current_time (&start_time);
+ QueryEditorHistoryBatch *hist_batch;
+ hist_batch = query_editor_history_batch_new (start_time, params);
+ query_editor_start_history_batch (tconsole->priv->history, hist_batch);
+ query_editor_history_batch_unref (hist_batch);
+
+ gboolean within_transaction;
stmt_list = gda_batch_get_statements (batch);
for (list = stmt_list; list; list = list->next) {
- ExecutionStatement *estmt;
- estmt = g_new0 (ExecutionStatement, 1);
- estmt->stmt = GDA_STATEMENT (list->data);
- ebatch->statements = g_slist_prepend (ebatch->statements, estmt);
-
- if (list != stmt_list)
- continue;
-
- /* only the 1st statement is actually executed, to be able to
- * stop others following statements to be executed if there is an
- * execution error.
- */
- estmt->within_transaction =
- browser_connection_get_transaction_status (tconsole->priv->bcnc) ? TRUE : FALSE;
- estmt->exec_id = browser_connection_execute_statement_cb (tconsole->priv->bcnc,
- estmt->stmt,
- params,
- GDA_STATEMENT_MODEL_RANDOM_ACCESS,
- FALSE,
- (BrowserConnectionExecuteCallback)
query_exec_done_cb,
- tconsole, &(estmt->exec_error));
- if (estmt->exec_id == 0) {
+ GdaStatement *stmt;
+ GObject *result;
+ GError *lerror = NULL;
+ within_transaction = browser_connection_get_transaction_status (tconsole->priv->bcnc) ? TRUE
: FALSE;
+ stmt = GDA_STATEMENT (list->data);
+ result = browser_connection_execute_statement (tconsole->priv->bcnc, stmt, params,
+ GDA_STATEMENT_MODEL_RANDOM_ACCESS,
+ NULL, &lerror);
+ if (result) {
+ QueryEditorHistoryItem *history;
+ GdaSqlStatement *sqlst;
+ g_object_get (G_OBJECT (stmt), "structure", &sqlst, NULL);
+ if (!sqlst->sql) {
+ gchar *sql;
+ sql = gda_statement_to_sql (stmt, NULL, NULL);
+ history = query_editor_history_item_new (sql, result, lerror);
+ g_free (sql);
+ }
+ else
+ history = query_editor_history_item_new (sqlst->sql, result, lerror);
+ gda_sql_statement_free (sqlst);
+
+ history->within_transaction = within_transaction;
+
+ /* display a message if a transaction has been started */
+ if (! history->within_transaction &&
+ browser_connection_get_transaction_status (tconsole->priv->bcnc) &&
+ gda_statement_get_statement_type (stmt) != GDA_SQL_STATEMENT_BEGIN) {
+ browser_window_show_notice_printf (BROWSER_WINDOW (gtk_widget_get_toplevel
((GtkWidget*) tconsole)),
+ GTK_MESSAGE_INFO,
+ "QueryExecTransactionStarted",
+ "%s", _("A transaction has automatically
been started\n"
+ "during this statement's
execution, this usually\n"
+ "happens when blobs are selected
(and the transaction\n"
+ "will have to remain opened while
the blobs are still\n"
+ "accessible, clear the
corresponding history item before\n"
+ "closing the transaction)."));
+ }
+
+ query_editor_add_history_item (tconsole->priv->history, history);
+ query_editor_history_item_unref (history);
+
+ browser_window_push_status (BROWSER_WINDOW (gtk_widget_get_toplevel ((GtkWidget*)
tconsole)),
+ "QueryConsolePage", _("Statement executed"), TRUE);
+ }
+ else {
browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) tconsole)),
- _("Error executing query: %s"),
- estmt->exec_error && estmt->exec_error->message ?
estmt->exec_error->message : _("No detail"));
- execution_batch_free (ebatch);
- return;
+ _("Error executing query:\n%s"),
+ lerror && lerror->message ? lerror->message : _("No detail"));
+ g_clear_error (&lerror);
+ break;
}
}
- ebatch->statements = g_slist_reverse (ebatch->statements);
- tconsole->priv->current_exec = ebatch;
+ g_object_unref (batch);
+ tconsole->priv->currently_executing = FALSE;
}
static void
diff --git a/tools/browser/schema-browser/table-info.c b/tools/browser/schema-browser/table-info.c
index ad6e6be..0bfd706 100644
--- a/tools/browser/schema-browser/table-info.c
+++ b/tools/browser/schema-browser/table-info.c
@@ -510,24 +510,6 @@ insert_form_params_changed_cb (GdauiBasicForm *form, G_GNUC_UNUSED GdaHolder *pa
gdaui_basic_form_is_valid (form));
}
-static void statement_executed_cb (G_GNUC_UNUSED BrowserConnection *bcnc,
- G_GNUC_UNUSED guint exec_id,
- G_GNUC_UNUSED GObject *out_result,
- G_GNUC_UNUSED GdaSet *out_last_inserted_row, GError *error,
- TableInfo *tinfo)
-{
- if (error)
- browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) tinfo)),
- _("Error executing query:\n%s"),
- error->message ?
- error->message : _("No detail"));
- else
- browser_window_show_notice_printf (BROWSER_WINDOW (gtk_widget_get_toplevel ((GtkWidget*)
tinfo)),
- GTK_MESSAGE_INFO,
- "DataInsertQuery",
- "%s", _("Data successfully inserted"));
-}
-
static void
insert_response_cb (GtkWidget *dialog, gint response_id, TableInfo *tinfo)
{
@@ -539,12 +521,18 @@ insert_response_cb (GtkWidget *dialog, gint response_id, TableInfo *tinfo)
stmt = g_object_get_data (G_OBJECT (dialog), "stmt");
params = g_object_get_data (G_OBJECT (dialog), "params");
- if (! browser_connection_execute_statement_cb (tinfo->priv->bcnc,
+ GObject *result;
+ result = browser_connection_execute_statement (tinfo->priv->bcnc,
stmt, params,
- GDA_STATEMENT_MODEL_RANDOM_ACCESS,
- FALSE,
- (BrowserConnectionExecuteCallback)
statement_executed_cb,
- tinfo, &lerror)) {
+ GDA_STATEMENT_MODEL_RANDOM_ACCESS, NULL,
&lerror);
+ if (result) {
+ browser_window_show_notice_printf (BROWSER_WINDOW (gtk_widget_get_toplevel
((GtkWidget*) tinfo)),
+ GTK_MESSAGE_INFO,
+ "DataInsertQuery",
+ "%s", _("Data successfully inserted"));
+ g_object_unref (result);
+ }
+ else {
browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) tinfo)),
_("Error executing query: %s"),
lerror && lerror->message ? lerror->message : _("No detail"));
@@ -572,22 +560,21 @@ typedef struct {
gboolean model_rerunning;
} FKBindData;
+/*
+ * @result: (transfer full)
+ */
static void
-fk_bind_select_executed_cb (G_GNUC_UNUSED BrowserConnection *bcnc,
- G_GNUC_UNUSED guint exec_id,
- GObject *out_result,
- G_GNUC_UNUSED GdaSet *out_last_inserted_row, G_GNUC_UNUSED GError *error,
- FKBindData *fkdata)
+fk_bind_select_executed_cb (GObject *result, FKBindData *fkdata)
{
gint i;
GdaDataModel *model;
- if (! out_result)
+ if (! result)
return;
if (fkdata->model)
g_object_unref (fkdata->model);
- model = GDA_DATA_MODEL (out_result);
+ model = GDA_DATA_MODEL (result);
for (i = 0; i < fkdata->cols_nb; i++) {
GdaHolder *h;
GdaSetSource *source;
@@ -621,7 +608,7 @@ fk_bind_select_executed_cb (G_GNUC_UNUSED BrowserConnection *bcnc,
}
}
}
- fkdata->model = g_object_ref (out_result);
+ fkdata->model = GDA_DATA_MODEL (result);
fkdata->model_rerunning = FALSE;
}
@@ -656,13 +643,13 @@ action_insert_cb (G_GNUC_UNUSED GtkAction *action, TableInfo *tinfo)
fkdata_list; fkdata_list = fkdata_list->next) {
FKBindData *fkdata = (FKBindData *) fkdata_list->data;
if (fkdata->model && !fkdata->model_rerunning) {
- if (browser_connection_execute_statement_cb (tinfo->priv->bcnc,
- fkdata->stmt, NULL,
-
GDA_STATEMENT_MODEL_RANDOM_ACCESS,
- FALSE,
-
(BrowserConnectionExecuteCallback) fk_bind_select_executed_cb,
- fkdata, NULL) != 0)
- fkdata->model_rerunning = TRUE;
+ GObject *result;
+ fkdata->model_rerunning = TRUE;
+ result = browser_connection_execute_statement (tinfo->priv->bcnc,
+ fkdata->stmt, NULL,
+
GDA_STATEMENT_MODEL_RANDOM_ACCESS, NULL,
+ NULL);
+ fk_bind_select_executed_cb (result, fkdata);
}
}
return;
@@ -873,21 +860,18 @@ action_insert_cb (G_GNUC_UNUSED GtkAction *action, TableInfo *tinfo)
memcpy (fkdata->fk_cols_array, fk->fk_cols_array, sizeof (gint) *
fk->cols_nb);
fkdata->chash = tinfo->priv->insert_columns_hash;
fkdata->stmt = stmt;
- eid = browser_connection_execute_statement_cb (tinfo->priv->bcnc, stmt, NULL,
+
+ GObject *result;
+ result = browser_connection_execute_statement (tinfo->priv->bcnc, stmt, NULL,
GDA_STATEMENT_MODEL_RANDOM_ACCESS,
- FALSE,
-
(BrowserConnectionExecuteCallback) fk_bind_select_executed_cb,
- fkdata, NULL);
- if (! eid) {
- g_free (fkdata->fk_cols_array);
- g_object_unref (fkdata->stmt);
- g_free (fkdata);
- }
+ NULL, NULL);
fkdata->insert_params = g_object_ref (params);
/* attach the kfdata to @popup to be able to re-run the SELECT
* everytime the window is shown */
fkdata_list = g_slist_prepend (fkdata_list, fkdata);
+
+ fk_bind_select_executed_cb (result, fkdata);
}
g_object_unref (b);
diff --git a/tools/browser/support.c b/tools/browser/support.c
index 838b935..23b432f 100644
--- a/tools/browser/support.c
+++ b/tools/browser/support.c
@@ -363,7 +363,7 @@ browser_make_tab_label_with_pixbuf (const gchar *label,
*
* Get a pointer to an internal #GdkPixbuf for the requested @type. Don't unref it!
*
- * Returns: an already existing #GdkPixbuf, or %NULL if the icon was not found
+ * Returns: (transfer none): an already existing #GdkPixbuf, or %NULL if the icon was not found
*/
GdkPixbuf *
browser_get_pixbuf_icon (BrowserIconType type)
diff --git a/tools/gda-sql.c b/tools/gda-sql.c
index 15d0c58..db4fb92 100644
--- a/tools/gda-sql.c
+++ b/tools/gda-sql.c
@@ -1347,11 +1347,9 @@ open_connection (SqlConsole *console, const gchar *cnc_name, const gchar *cnc_st
if (info && !real_provider)
newcnc = gda_connection_open_from_dsn (real_cnc_string, real_auth_string,
- GDA_CONNECTION_OPTIONS_THREAD_SAFE |
GDA_CONNECTION_OPTIONS_AUTO_META_DATA, error);
else
newcnc = gda_connection_open_from_string (NULL, real_cnc_string, real_auth_string,
- GDA_CONNECTION_OPTIONS_THREAD_SAFE |
GDA_CONNECTION_OPTIONS_AUTO_META_DATA, error);
g_free (real_cnc_string);
@@ -3152,8 +3150,7 @@ extra_command_bind_cnc (ToolCommand *command, guint argc, const gchar **argv,
vprovider = gda_vprovider_hub_new ();
g_assert (vprovider);
- virtual = gda_virtual_connection_open_extended (vprovider, GDA_CONNECTION_OPTIONS_THREAD_SAFE |
- GDA_CONNECTION_OPTIONS_AUTO_META_DATA, NULL);
+ virtual = gda_virtual_connection_open (vprovider, GDA_CONNECTION_OPTIONS_AUTO_META_DATA, NULL);
if (!virtual) {
g_set_error (error, GDA_TOOLS_ERROR, GDA_TOOLS_INTERNAL_COMMAND_ERROR,
"%s", _("Could not create virtual connection"));
diff --git a/tools/tools-favorites.c b/tools/tools-favorites.c
index 92b2379..bb17d23 100644
--- a/tools/tools-favorites.c
+++ b/tools/tools-favorites.c
@@ -22,7 +22,6 @@
#include <glib/gi18n-lib.h>
#include "tools-favorites.h"
#include "tool-utils.h"
-#include <libgda/thread-wrapper/gda-thread-wrapper.h>
#include <libgda/gda-sql-builder.h>
#include <sql-parser/gda-sql-parser.h>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]