[libgda] Major rework of the way multi threading is handled



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 
-           &quot;<link linkend="GdaConnection--thread-owner">thread-owner</link>&quot; 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: "[&lt;username&gt;[:&lt;password&gt;] ]&lt;DSN&gt;" 
+ * (if &lt;username&gt; and/or &lt;password&gt; are provided, and @auth_string is %NULL, then these username
+ * and passwords will be used). Note that if provided, &lt;username&gt; and &lt;password&gt; 
+ * 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: "[&lt;username&gt;[:&lt;password&gt;] ]&lt;DSN&gt;" 
- * (if &lt;username&gt; and/or &lt;password&gt; are provided, and @auth_string is %NULL, then these username
- * and passwords will be used). Note that if provided, &lt;username&gt; and &lt;password&gt; 
- * 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 &lt;key&gt;=&lt;value&gt; 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: 
+ * "[&lt;provider&gt;://][&lt;username&gt;[:&lt;password&gt;] ]&lt;connection_params&gt;"
+ * (if &lt;username&gt; and/or &lt;password&gt; are provided, and @auth_string is %NULL, then these username
+ * and passwords will be used, and if &lt;provider&gt; is provided and @provider_name is %NULL then this
+ * provider will be used). Note that if provided, &lt;username&gt;, &lt;password&gt; and  &lt;provider&gt;
+ * 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 "&lt;provider_name&gt;://&lt;real cnc string&gt;" 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 &lt;key&gt;=&lt;value&gt; 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: 
- * "[&lt;provider&gt;://][&lt;username&gt;[:&lt;password&gt;] ]&lt;connection_params&gt;"
- * (if &lt;username&gt; and/or &lt;password&gt; are provided, and @auth_string is %NULL, then these username
- * and passwords will be used, and if &lt;provider&gt; is provided and @provider_name is %NULL then this
- * provider will be used). Note that if provided, &lt;username&gt;, &lt;password&gt; and  &lt;provider&gt;
- * 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 "&lt;provider_name&gt;://&lt;real cnc string&gt;" 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, &params, &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, &params, &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 (&registering);
+               g_mutex_init (&spare_mutex);
+               if (!spare_array)
+                       spare_array = g_ptr_array_new ();
+               g_mutex_unlock (&registering);
+       }
+
+       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*) &notif, 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, &current);
+       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, &current, _("Distinguished Name:"), -1,
-                                                         "section", NULL);
-               gtk_text_buffer_insert (tbuffer, &current, "\n", -1);
-               gtk_text_buffer_insert_with_tags_by_name (tbuffer, &current, " ", -1, "starter", NULL);
-               gtk_text_buffer_insert_with_tags_by_name (tbuffer, &current, entry->dn, -1,
-                                                         "data", NULL);
+       guint i;
+       GtkTextIter current;
+
+       gtk_text_buffer_get_start_iter (tbuffer, &current);
+
+       /* DN */
+       gtk_text_buffer_insert_with_tags_by_name (tbuffer, &current, _("Distinguished Name:"), -1,
+                                                 "section", NULL);
+       gtk_text_buffer_insert (tbuffer, &current, "\n", -1);
+       gtk_text_buffer_insert_with_tags_by_name (tbuffer, &current, " ", -1, "starter", NULL);
+       gtk_text_buffer_insert_with_tags_by_name (tbuffer, &current, entry->dn, -1,
+                                                 "data", NULL);
+       gtk_text_buffer_insert (tbuffer, &current, "\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, &current, tmp, -1, "section", NULL);
+               g_free (tmp);
                gtk_text_buffer_insert (tbuffer, &current, "\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, &current, tmp, -1, "section", 
NULL);
-                       g_free (tmp);
-                       gtk_text_buffer_insert (tbuffer, &current, "\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, &current, " ", -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, &current, TRUE);
-
-                                       GdkPixbuf *pixbuf;
-                                       pixbuf = data_to_pixbuf (cvalue);
-                                       if (pixbuf) {
-                                               gtk_text_buffer_insert_pixbuf (tbuffer, &current, 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, &current,
-                                                                                         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, &current);
-                                       gtk_text_buffer_delete_mark (tbuffer, mark);
-                                       
-                                       gtk_text_buffer_insert_with_tags_by_name (tbuffer, &current,
-                                                                                 "\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, &current, " ", -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, &current, TRUE);
+
+                               GdkPixbuf *pixbuf;
+                               pixbuf = data_to_pixbuf (cvalue);
+                               if (pixbuf) {
+                                       gtk_text_buffer_insert_pixbuf (tbuffer, &current, 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, &current,
-                                                                                         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, &current,
-                                                                                         tmp, -1,
-                                                                                         tag, NULL);
-                                               }
-                                               else
-                                                       gtk_text_buffer_insert_with_tags_by_name (tbuffer, 
&current, 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, 
&current,
-                                                                                                 " ", 1,
-                                                                                                 "data", 
NULL);
-                                                       gtk_text_buffer_insert_with_tags_by_name (tbuffer, 
&current,
-                                                                                                 extrainfo, 
-1,
-                                                                                                 "convdata", 
NULL);
-                                                       g_free (extrainfo);
-                                               }
-                                               g_free (tmp);
-                                       }
-                                       else {
-                                               gtk_text_buffer_insert_with_tags_by_name (tbuffer, &current, 
_("Can't display attribute value"), -1,
-                                                                                         "error", NULL);
-                                       }
                                        gtk_text_buffer_insert_with_tags_by_name (tbuffer, &current,
-                                                                                 "\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, &current);
+                               gtk_text_buffer_delete_mark (tbuffer, mark);
+                                       
+                               gtk_text_buffer_insert_with_tags_by_name (tbuffer, &current,
+                                                                         "\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, &current,
+                                                                                 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, &current,
+                                                                                 tmp, -1,
+                                                                                 tag, NULL);
+                                       }
+                                       else
+                                               gtk_text_buffer_insert_with_tags_by_name (tbuffer, &current, 
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, &current,
+                                                                                         " ", 1,
+                                                                                         "data", NULL);
+                                               gtk_text_buffer_insert_with_tags_by_name (tbuffer, &current,
+                                                                                         extrainfo, -1,
+                                                                                         "convdata", NULL);
+                                               g_free (extrainfo);
+                                       }
+                                       g_free (tmp);
+                               }
+                               else {
+                                       gtk_text_buffer_insert_with_tags_by_name (tbuffer, &current, _("Can't 
display attribute value"), -1,
+                                                                                 "error", NULL);
+                               }
+                               gtk_text_buffer_insert_with_tags_by_name (tbuffer, &current,
+                                                                         "\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]