[libgda] LDAP: execute all API calls in worker thread



commit 4b349c46e54e39cd1d3fcf6646798f120340a2fa
Author: Vivien Malerba <malerba gnome-db org>
Date:   Sun Nov 30 22:31:22 2014 +0100

    LDAP: execute all API calls in worker thread

 libgda/gda-blob-op.c                     |    8 +-
 libgda/gda-connection-internal.h         |    2 +-
 libgda/gda-connection-private.h          |    1 +
 libgda/gda-connection.c                  |   28 +-
 libgda/gda-data-select.c                 |   14 +-
 libgda/gda-server-provider-private.h     |    4 +-
 libgda/gda-server-provider.c             |  154 +++---
 libgda/libgda.symbols                    |    3 +
 providers/ldap/gda-ldap-provider.c       |  159 +++++-
 providers/ldap/gda-ldap-util.c           |  461 +++++++++++-----
 providers/ldap/gda-ldap-util.h           |    7 +-
 providers/ldap/gda-ldap.h                |   20 +-
 providers/ldap/gdaprov-data-model-ldap.c |  852 +++++++++++++++++++-----------
 13 files changed, 1144 insertions(+), 569 deletions(-)
---
diff --git a/libgda/gda-blob-op.c b/libgda/gda-blob-op.c
index b4b367a..d118558 100644
--- a/libgda/gda-blob-op.c
+++ b/libgda/gda-blob-op.c
@@ -223,7 +223,7 @@ gda_blob_op_get_length (GdaBlobOp *op)
                gda_lockable_lock ((GdaLockable*) op->priv->cnc); /* CNC LOCK */
 
                GMainContext *context;
-               context = _gda_server_provider_get_real_main_context (op->priv->cnc);
+               context = gda_server_provider_get_real_main_context (op->priv->cnc);
 
                WorkerData data;
                data.op = op;
@@ -286,7 +286,7 @@ gda_blob_op_read (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size)
                gda_lockable_lock ((GdaLockable*) op->priv->cnc); /* CNC LOCK */
 
                GMainContext *context;
-               context = _gda_server_provider_get_real_main_context (op->priv->cnc);
+               context = gda_server_provider_get_real_main_context (op->priv->cnc);
 
                WorkerData data;
                data.op = op;
@@ -378,7 +378,7 @@ gda_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset)
                gda_lockable_lock ((GdaLockable*) op->priv->cnc); /* CNC LOCK */
 
                GMainContext *context;
-               context = _gda_server_provider_get_real_main_context (op->priv->cnc);
+               context = gda_server_provider_get_real_main_context (op->priv->cnc);
 
                WorkerData data;
                data.op = op;
@@ -442,7 +442,7 @@ gda_blob_op_write_all (GdaBlobOp *op, GdaBlob *blob)
                        gda_lockable_lock ((GdaLockable*) op->priv->cnc); /* CNC LOCK */
 
                        GMainContext *context;
-                       context = _gda_server_provider_get_real_main_context (op->priv->cnc);
+                       context = gda_server_provider_get_real_main_context (op->priv->cnc);
 
                        WorkerData data;
                        data.op = op;
diff --git a/libgda/gda-connection-internal.h b/libgda/gda-connection-internal.h
index b264a18..dc58f2c 100644
--- a/libgda/gda-connection-internal.h
+++ b/libgda/gda-connection-internal.h
@@ -48,7 +48,7 @@ guint              _gda_connection_get_exec_slowdown (GdaConnection *cnc);
 
 void               _gda_connection_status_start_batch (GdaConnection *cnc, GdaConnectionStatus status);
 void               _gda_connection_status_stop_batch (GdaConnection *cnc);
-void               _gda_connection_set_status (GdaConnection *cnc, GdaConnectionStatus status);
+void               gda_connection_set_status (GdaConnection *cnc, GdaConnectionStatus status);
 
 /*
  * Opens a connection to an SQLite database. This function is intended to be used
diff --git a/libgda/gda-connection-private.h b/libgda/gda-connection-private.h
index d62d72b..4aedb51 100644
--- a/libgda/gda-connection-private.h
+++ b/libgda/gda-connection-private.h
@@ -53,6 +53,7 @@ void                             gda_connection_internal_set_provider_data
                                                                                  GDestroyNotify 
destroy_func);
 GdaServerProviderConnectionData *gda_connection_internal_get_provider_data_error (GdaConnection *cnc, GError 
**error);
 void                             _gda_connection_internal_set_worker_thread (GdaConnection *cnc, GThread 
*thread);
+GdaWorker                       *gda_connection_internal_get_worker (GdaServerProviderConnectionData *data);
 
 /*
  * Connection's events
diff --git a/libgda/gda-connection.c b/libgda/gda-connection.c
index 42c6d9a..3f0b14a 100644
--- a/libgda/gda-connection.c
+++ b/libgda/gda-connection.c
@@ -1578,15 +1578,17 @@ assert_status_transaction (GdaConnectionStatus old, GdaConnectionStatus new)
        }
 }
 
-/*
- * _gda_connection_set_status:
+/**
+ * gda_connection_set_status: (skip)
+ * @cnc: a #GdaConnection
  *
- * Set @cnc's new status, may emit the "status-changed" signal along the way
+ * Set @cnc's new status, may emit the "status-changed" signal along the way. This function is reserved to 
database
+ * provider's implementation
  *
  * WARNING: @cnc _MUST_ be locked before this function is called
  */
 void
-_gda_connection_set_status (GdaConnection *cnc, GdaConnectionStatus status)
+gda_connection_set_status (GdaConnection *cnc, GdaConnectionStatus status)
 {
        if (!cnc || (status == cnc->priv->status))
                return;
@@ -5914,6 +5916,24 @@ _gda_connection_internal_set_worker_thread (GdaConnection *cnc, GThread *thread)
 }
 
 /**
+ * gda_connection_internal_get_worker: (skip)
+ * @data: (allow-none): a #GdaServerProviderConnectionData, or %NULL
+ *
+ * Retreive a pointer to the #GdaWorker used internally by the connection. This function is reserved to
+ * database provider's implementation and should not be used otherwise.
+ *
+ * Returns: (transfer none): the #GdaWorker, or %NULL
+ */
+GdaWorker *
+gda_connection_internal_get_worker (GdaServerProviderConnectionData *data)
+{
+       if (data)
+               return data->worker;
+       else
+               return NULL;
+}
+
+/**
  * gda_connection_internal_get_provider_data_error: (skip)
  * @cnc: a #GdaConnection object
  * @error: (allow-none): a place to store errors, or %NULL
diff --git a/libgda/gda-data-select.c b/libgda/gda-data-select.c
index e9e4d0c..26bd0e8 100644
--- a/libgda/gda-data-select.c
+++ b/libgda/gda-data-select.c
@@ -42,7 +42,7 @@
 #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 () */
+#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)))
 
@@ -3910,7 +3910,7 @@ static gint
 _gda_data_select_fetch_nb_rows (GdaDataSelect *model)
 {
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (model->priv->cnc);
+       context = gda_server_provider_get_real_main_context (model->priv->cnc);
 
        gint nbrows = -1;
        gint *result;
@@ -3949,7 +3949,7 @@ 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);
+       context = gda_server_provider_get_real_main_context (model->priv->cnc);
 
        WorkerData jdata;
        jdata.model = model;
@@ -3982,7 +3982,7 @@ static gboolean
 _gda_data_select_store_all (GdaDataSelect *model, GError **error)
 {
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (model->priv->cnc);
+       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,
@@ -4010,7 +4010,7 @@ 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);
+       context = gda_server_provider_get_real_main_context (model->priv->cnc);
 
        WorkerData jdata;
        jdata.model = model;
@@ -4043,7 +4043,7 @@ 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);
+       context = gda_server_provider_get_real_main_context (model->priv->cnc);
 
        WorkerData jdata;
        jdata.model = model;
@@ -4076,7 +4076,7 @@ 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);
+       context = gda_server_provider_get_real_main_context (model->priv->cnc);
 
        WorkerData jdata;
        jdata.model = model;
diff --git a/libgda/gda-server-provider-private.h b/libgda/gda-server-provider-private.h
index 0c3ff43..0c0abe5 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 - 2013 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 Murray Cumming <murrayc murrayc com>
  *
@@ -40,7 +40,7 @@ struct _GdaServerProviderPrivate {
 /*
  * Getting the GMainContext to use with the GdaWorker
  */
-GMainContext *_gda_server_provider_get_real_main_context (GdaConnection *cnc);
+GMainContext *gda_server_provider_get_real_main_context (GdaConnection *cnc);
 
 /*
  * GdaServerProvider's virtual functions access
diff --git a/libgda/gda-server-provider.c b/libgda/gda-server-provider.c
index afa7187..13691f5 100644
--- a/libgda/gda-server-provider.c
+++ b/libgda/gda-server-provider.c
@@ -495,17 +495,19 @@ _gda_server_provider_create_worker (GdaServerProvider *provider, gboolean for_cn
        return (fset->create_worker) (provider, for_cnc);
 }
 
-/*
- * Obtain a #GMainContext on which to iterate.
+/**
+ * gda_server_provider_get_real_main_context: (skip)
  * @cnc: (allow-none): a #GdaConnection, or %NULL
  *
+ * Obtain a #GMainContext on which to iterate. This function is reserved to database provider's 
implementations.
+ *
  * NB: if @cnc is NOT %NULL and has a #GdaWorker associated, and if we are in its worker thread, then this 
function
  *     returns %NULL (to avoid generating contexts which are never used)
  *
  * Returns: a #GMainContext, or %NULL. Don't forget to call g_main_context_unref() when done
  */
 GMainContext *
-_gda_server_provider_get_real_main_context (GdaConnection *cnc)
+gda_server_provider_get_real_main_context (GdaConnection *cnc)
 {
        GMainContext *context;
        if (cnc) {
@@ -556,7 +558,7 @@ gda_server_provider_get_version (GdaServerProvider *provider)
        g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (NULL);
+       context = gda_server_provider_get_real_main_context (NULL);
 
        GdaWorker *worker;
        worker = _gda_server_provider_create_worker (provider, FALSE);
@@ -602,7 +604,7 @@ gda_server_provider_get_name (GdaServerProvider *provider)
        g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (NULL);
+       context = gda_server_provider_get_real_main_context (NULL);
 
        GdaWorker *worker;
        worker = _gda_server_provider_create_worker (provider, FALSE);
@@ -662,7 +664,7 @@ gda_server_provider_get_server_version (GdaServerProvider *provider, GdaConnecti
        }
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerGetInfoData data;
        data.worker = cdata->worker;
@@ -739,7 +741,7 @@ gda_server_provider_supports_operation (GdaServerProvider *provider, GdaConnecti
                worker = _gda_server_provider_create_worker (provider, FALSE);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerSupportsOperationData data;
        data.worker = worker;
@@ -951,7 +953,7 @@ gda_server_provider_create_operation (GdaServerProvider *provider, GdaConnection
                worker = _gda_server_provider_create_worker (provider, FALSE);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerCreateOperationData data;
        data.worker = worker;
@@ -1078,7 +1080,7 @@ gda_server_provider_render_operation (GdaServerProvider *provider, GdaConnection
                worker = _gda_server_provider_create_worker (provider, FALSE);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerRenderOperationData data;
        data.worker = worker;
@@ -1161,7 +1163,7 @@ gda_server_provider_perform_operation (GdaServerProvider *provider, GdaConnectio
                worker = _gda_server_provider_create_worker (provider, FALSE);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerPerformOperationData data;
        data.worker = worker;
@@ -1261,7 +1263,7 @@ gda_server_provider_supports_feature (GdaServerProvider *provider, GdaConnection
                worker = _gda_server_provider_create_worker (provider, FALSE);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerSupportsFeatureData data;
        data.worker = worker;
@@ -1339,7 +1341,7 @@ gda_server_provider_get_data_handler_g_type (GdaServerProvider *provider, GdaCon
                worker = _gda_server_provider_create_worker (provider, FALSE);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerTypeData data;
        data.worker = worker;
@@ -1399,7 +1401,7 @@ gda_server_provider_get_data_handler_dbms (GdaServerProvider *provider, GdaConne
                worker = _gda_server_provider_create_worker (provider, FALSE);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerTypeData data;
        data.worker = worker;
@@ -1474,7 +1476,7 @@ gda_server_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConne
                worker = _gda_server_provider_create_worker (provider, FALSE);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerTypeData data;
        data.worker = worker;
@@ -1704,7 +1706,7 @@ gda_server_provider_escape_string (GdaServerProvider *provider, GdaConnection *c
                worker = _gda_server_provider_create_worker (provider, FALSE);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerEscapeData data;
        data.worker = worker;
@@ -1774,7 +1776,7 @@ gda_server_provider_unescape_string (GdaServerProvider *provider, GdaConnection
                worker = _gda_server_provider_create_worker (provider, FALSE);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerEscapeData data;
        data.worker = worker;
@@ -1852,7 +1854,7 @@ gda_server_provider_create_parser (GdaServerProvider *provider, GdaConnection *c
                worker = _gda_server_provider_create_worker (provider, FALSE);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerParserData data;
        data.worker = worker;
@@ -1957,7 +1959,7 @@ _gda_server_provider_create_connection (GdaServerProvider *provider, const gchar
        g_return_val_if_fail (!dsn_string || !cnc_string, FALSE);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (NULL);
+       context = gda_server_provider_get_real_main_context (NULL);
 
        GdaWorker *worker;
        worker = _gda_server_provider_create_worker (provider, FALSE);
@@ -2096,7 +2098,7 @@ stage2_open_connection (GdaWorker *worker, GdaConnection *cnc, gpointer result)
                if (!cdata) {
                        g_warning ("Internal error: connection reported as opened, yet no provider data set");
                        result = NULL;
-                       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_CLOSED);
+                       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_CLOSED);
                }
                else {
                        g_signal_emit_by_name (G_OBJECT (cnc), "opened");
@@ -2167,7 +2169,7 @@ _gda_server_provider_open_connection (GdaServerProvider *provider, GdaConnection
        if (cb_func) {
                if (!gda_worker_set_callback (worker, context,
                                              (GdaWorkerCallback) server_provider_job_done_callback, 
provider, error)) {
-                       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_CLOSED);
+                       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_CLOSED);
                        gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
                        gda_worker_unref (worker);
                        return FALSE;
@@ -2195,7 +2197,7 @@ _gda_server_provider_open_connection (GdaServerProvider *provider, GdaConnection
                                                (GdaWorkerFunc) worker_open_connection,
                                                jdata, NULL, NULL, error);
                if (job_id == 0) {
-                       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_CLOSED);
+                       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_CLOSED);
                        gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
                        WorkerOpenConnectionData_free (jdata);
                        return FALSE; /* error */
@@ -2300,10 +2302,10 @@ stage2_close_connection (GdaConnection *cnc, gpointer result)
                        if (cdata->provider_data_destroy_func)
                                cdata->provider_data_destroy_func (cdata);
                }
-               _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_CLOSED);
+               gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_CLOSED);
        }
        else
-               _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
+               gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
 
        gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
 
@@ -2336,7 +2338,7 @@ _gda_server_provider_close_connection (GdaServerProvider *provider, GdaConnectio
        }
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerCloseConnectionData *jdata;
        jdata = g_slice_new (WorkerCloseConnectionData);
@@ -2344,7 +2346,7 @@ _gda_server_provider_close_connection (GdaServerProvider *provider, GdaConnectio
        jdata->provider = provider;
        jdata->cnc = g_object_ref (cnc);
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
 
        GdaWorker *worker;
        worker = cdata->worker;
@@ -2420,7 +2422,7 @@ _gda_server_provider_statement_prepare (GdaServerProvider *provider, GdaConnecti
        worker = gda_worker_ref (cdata->worker);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerPrepareStatementData data;
        data.worker = worker;
@@ -2428,14 +2430,14 @@ _gda_server_provider_statement_prepare (GdaServerProvider *provider, GdaConnecti
        data.cnc = cnc;
        data.stmt = stmt;
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
        gpointer retval;
        gda_worker_do_job (worker, context, 0, &retval, NULL,
                           (GdaWorkerFunc) worker_statement_prepare, (gpointer) &data, NULL, NULL, NULL);
        if (context)
                g_main_context_unref (context);
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
        gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
 
        gda_worker_unref (worker);
@@ -2536,7 +2538,7 @@ _gda_server_provider_statement_execute (GdaServerProvider *provider, GdaConnecti
        worker = gda_worker_ref (cdata->worker);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerExecuteStatementData data;
        data.worker = worker;
@@ -2548,14 +2550,14 @@ _gda_server_provider_statement_execute (GdaServerProvider *provider, GdaConnecti
        data.col_types = col_types;
        data.last_inserted_row = last_inserted_row;
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
        gpointer retval;
        gda_worker_do_job (worker, context, 0, &retval, NULL,
                           (GdaWorkerFunc) worker_statement_execute, (gpointer) &data, NULL, NULL, error);
        if (context)
                g_main_context_unref (context);
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
        gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
 
        gda_worker_unref (worker);
@@ -2625,7 +2627,7 @@ _gda_server_provider_statement_to_sql  (GdaServerProvider *provider, GdaConnecti
                worker = _gda_server_provider_create_worker (provider, FALSE);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerStmtToSQLData data;
        data.worker = worker;
@@ -2636,14 +2638,14 @@ _gda_server_provider_statement_to_sql  (GdaServerProvider *provider, GdaConnecti
        data.flags = flags;
        data.params_used = params_used;
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
        gpointer retval;
        gda_worker_do_job (worker, context, 0, &retval, NULL,
                           (GdaWorkerFunc) worker_stmt_to_sql, (gpointer) &data, NULL, NULL, error);
        if (context)
                g_main_context_unref (context);
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
        if (cnc)
                gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
 
@@ -2706,7 +2708,7 @@ _gda_server_provider_identifier_quote (GdaServerProvider *provider, GdaConnectio
                worker = _gda_server_provider_create_worker (provider, FALSE);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerIdentifierQuoteData data;
        data.worker = worker;
@@ -2716,14 +2718,14 @@ _gda_server_provider_identifier_quote (GdaServerProvider *provider, GdaConnectio
        data.for_meta_store = for_meta_store;
        data.force_quotes = force_quotes;
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
        gpointer retval;
        gda_worker_do_job (worker, context, 0, &retval, NULL,
                           (GdaWorkerFunc) worker_identifier_quote, (gpointer) &data, NULL, NULL, NULL);
        if (context)
                g_main_context_unref (context);
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
        if (cnc)
                gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
 
@@ -2927,7 +2929,7 @@ _gda_server_provider_meta_0arg (GdaServerProvider *provider, GdaConnection *cnc,
        worker = gda_worker_ref (cdata->worker);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerMetaData data;
        data.worker = worker;
@@ -2942,14 +2944,14 @@ _gda_server_provider_meta_0arg (GdaServerProvider *provider, GdaConnection *cnc,
        data.values[2] = NULL;
        data.values[3] = NULL;
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
        gpointer retval;
        gda_worker_do_job (worker, context, 0, &retval, NULL,
                           (GdaWorkerFunc) worker_meta, (gpointer) &data, NULL, NULL, NULL);
        if (context)
                g_main_context_unref (context);
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
        if (cnc)
                gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
 
@@ -2988,7 +2990,7 @@ _gda_server_provider_meta_1arg (GdaServerProvider *provider, GdaConnection *cnc,
        worker = gda_worker_ref (cdata->worker);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerMetaData data;
        data.worker = worker;
@@ -3003,14 +3005,14 @@ _gda_server_provider_meta_1arg (GdaServerProvider *provider, GdaConnection *cnc,
        data.values[2] = NULL;
        data.values[3] = NULL;
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
        gpointer retval;
        gda_worker_do_job (worker, context, 0, &retval, NULL,
                           (GdaWorkerFunc) worker_meta, (gpointer) &data, NULL, NULL, NULL);
        if (context)
                g_main_context_unref (context);
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
        if (cnc)
                gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
 
@@ -3049,7 +3051,7 @@ _gda_server_provider_meta_2arg (GdaServerProvider *provider, GdaConnection *cnc,
        worker = gda_worker_ref (cdata->worker);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerMetaData data;
        data.worker = worker;
@@ -3064,14 +3066,14 @@ _gda_server_provider_meta_2arg (GdaServerProvider *provider, GdaConnection *cnc,
        data.values[2] = NULL;
        data.values[3] = NULL;
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
        gpointer retval;
        gda_worker_do_job (worker, context, 0, &retval, NULL,
                           (GdaWorkerFunc) worker_meta, (gpointer) &data, NULL, NULL, NULL);
        if (context)
                g_main_context_unref (context);
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
        if (cnc)
                gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
 
@@ -3111,7 +3113,7 @@ _gda_server_provider_meta_3arg (GdaServerProvider *provider, GdaConnection *cnc,
        worker = gda_worker_ref (cdata->worker);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerMetaData data;
        data.worker = worker;
@@ -3126,14 +3128,14 @@ _gda_server_provider_meta_3arg (GdaServerProvider *provider, GdaConnection *cnc,
        data.values[2] = value2;
        data.values[3] = NULL;
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
        gpointer retval;
        gda_worker_do_job (worker, context, 0, &retval, NULL,
                           (GdaWorkerFunc) worker_meta, (gpointer) &data, NULL, NULL, NULL);
        if (context)
                g_main_context_unref (context);
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
        if (cnc)
                gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
 
@@ -3173,7 +3175,7 @@ _gda_server_provider_meta_4arg (GdaServerProvider *provider, GdaConnection *cnc,
        worker = gda_worker_ref (cdata->worker);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerMetaData data;
        data.worker = worker;
@@ -3188,14 +3190,14 @@ _gda_server_provider_meta_4arg (GdaServerProvider *provider, GdaConnection *cnc,
        data.values[2] = value2;
        data.values[3] = value3;
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
        gpointer retval;
        gda_worker_do_job (worker, context, 0, &retval, NULL,
                           (GdaWorkerFunc) worker_meta, (gpointer) &data, NULL, NULL, NULL);
        if (context)
                g_main_context_unref (context);
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
        if (cnc)
                gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
 
@@ -3266,7 +3268,7 @@ _gda_server_provider_begin_transaction (GdaServerProvider *provider, GdaConnecti
        worker = gda_worker_ref (cdata->worker);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerTransactionData data;
        data.worker = worker;
@@ -3275,14 +3277,14 @@ _gda_server_provider_begin_transaction (GdaServerProvider *provider, GdaConnecti
        data.name = name;
        data.level = level;
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
        gpointer retval;
        gda_worker_do_job (worker, context, 0, &retval, NULL,
                           (GdaWorkerFunc) worker_begin_transaction, (gpointer) &data, NULL, NULL, error);
        if (context)
                g_main_context_unref (context);
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
        gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
 
        gda_worker_unref (worker);
@@ -3336,7 +3338,7 @@ _gda_server_provider_commit_transaction (GdaServerProvider *provider, GdaConnect
        worker = gda_worker_ref (cdata->worker);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerTransactionData data;
        data.worker = worker;
@@ -3344,14 +3346,14 @@ _gda_server_provider_commit_transaction (GdaServerProvider *provider, GdaConnect
        data.cnc = cnc;
        data.name = name;
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
        gpointer retval;
        gda_worker_do_job (worker, context, 0, &retval, NULL,
                           (GdaWorkerFunc) worker_commit_transaction, (gpointer) &data, NULL, NULL, error);
        if (context)
                g_main_context_unref (context);
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
        gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
 
        gda_worker_unref (worker);
@@ -3405,7 +3407,7 @@ _gda_server_provider_rollback_transaction (GdaServerProvider *provider, GdaConne
        worker = gda_worker_ref (cdata->worker);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerTransactionData data;
        data.worker = worker;
@@ -3413,14 +3415,14 @@ _gda_server_provider_rollback_transaction (GdaServerProvider *provider, GdaConne
        data.cnc = cnc;
        data.name = name;
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
        gpointer retval;
        gda_worker_do_job (worker, context, 0, &retval, NULL,
                           (GdaWorkerFunc) worker_rollback_transaction, (gpointer) &data, NULL, NULL, error);
        if (context)
                g_main_context_unref (context);
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
        gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
 
        gda_worker_unref (worker);
@@ -3466,7 +3468,7 @@ _gda_server_provider_add_savepoint (GdaServerProvider *provider, GdaConnection *
        worker = gda_worker_ref (cdata->worker);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerTransactionData data;
        data.worker = worker;
@@ -3474,14 +3476,14 @@ _gda_server_provider_add_savepoint (GdaServerProvider *provider, GdaConnection *
        data.cnc = cnc;
        data.name = name;
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
        gpointer retval;
        gda_worker_do_job (worker, context, 0, &retval, NULL,
                           (GdaWorkerFunc) worker_add_savepoint, (gpointer) &data, NULL, NULL, error);
        if (context)
                g_main_context_unref (context);
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
        gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
 
        gda_worker_unref (worker);
@@ -3527,7 +3529,7 @@ _gda_server_provider_rollback_savepoint (GdaServerProvider *provider, GdaConnect
        worker = gda_worker_ref (cdata->worker);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerTransactionData data;
        data.worker = worker;
@@ -3535,14 +3537,14 @@ _gda_server_provider_rollback_savepoint (GdaServerProvider *provider, GdaConnect
        data.cnc = cnc;
        data.name = name;
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
        gpointer retval;
        gda_worker_do_job (worker, context, 0, &retval, NULL,
                           (GdaWorkerFunc) worker_rollback_savepoint, (gpointer) &data, NULL, NULL, error);
        if (context)
                g_main_context_unref (context);
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
        gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
 
        gda_worker_unref (worker);
@@ -3588,7 +3590,7 @@ _gda_server_provider_delete_savepoint (GdaServerProvider *provider, GdaConnectio
        worker = gda_worker_ref (cdata->worker);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerTransactionData data;
        data.worker = worker;
@@ -3596,14 +3598,14 @@ _gda_server_provider_delete_savepoint (GdaServerProvider *provider, GdaConnectio
        data.cnc = cnc;
        data.name = name;
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
        gpointer retval;
        gda_worker_do_job (worker, context, 0, &retval, NULL,
                           (GdaWorkerFunc) worker_delete_savepoint, (gpointer) &data, NULL, NULL, error);
        if (context)
                g_main_context_unref (context);
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
        gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
 
        gda_worker_unref (worker);
@@ -3738,7 +3740,7 @@ _gda_server_provider_xa (GdaServerProvider *provider, GdaConnection *cnc, const
        worker = gda_worker_ref (cdata->worker);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerXAData data;
        data.worker = worker;
@@ -3747,14 +3749,14 @@ _gda_server_provider_xa (GdaServerProvider *provider, GdaConnection *cnc, const
        data.trx = trx;
        data.type = type;
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
        gpointer retval;
        gda_worker_do_job (worker, context, 0, &retval, NULL,
                           (GdaWorkerFunc) worker_xa, (gpointer) &data, NULL, NULL, error);
        if (context)
                g_main_context_unref (context);
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
        gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
 
        gda_worker_unref (worker);
@@ -3783,7 +3785,7 @@ _gda_server_provider_xa_recover (GdaServerProvider *provider, GdaConnection *cnc
        worker = gda_worker_ref (cdata->worker);
 
        GMainContext *context;
-       context = _gda_server_provider_get_real_main_context (cnc);
+       context = gda_server_provider_get_real_main_context (cnc);
 
        WorkerXAData data;
        data.worker = worker;
@@ -3792,14 +3794,14 @@ _gda_server_provider_xa_recover (GdaServerProvider *provider, GdaConnection *cnc
        data.trx = NULL;
        data.type = GDA_XA_RECOVER;
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_BUSY);
        gpointer retval;
        gda_worker_do_job (worker, context, 0, &retval, NULL,
                           (GdaWorkerFunc) worker_xa, (gpointer) &data, NULL, NULL, error);
        if (context)
                g_main_context_unref (context);
 
-       _gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_connection_set_status (cnc, GDA_CONNECTION_STATUS_IDLE);
        gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
 
        gda_worker_unref (worker);
diff --git a/libgda/libgda.symbols b/libgda/libgda.symbols
index 33ad7ec..a1a4647 100644
--- a/libgda/libgda.symbols
+++ b/libgda/libgda.symbols
@@ -139,6 +139,7 @@
        gda_connection_insert_row_into_table_v
        gda_connection_internal_change_transaction_state
        gda_connection_internal_get_provider_data_error
+       gda_connection_internal_get_worker
        gda_connection_internal_reset_transaction_status
        gda_connection_internal_savepoint_added
        gda_connection_internal_savepoint_removed
@@ -166,6 +167,7 @@
        gda_connection_rollback_savepoint
        gda_connection_rollback_transaction
        gda_connection_set_main_context
+       gda_connection_set_status
        gda_connection_statement_execute
        gda_connection_statement_execute_non_select
        gda_connection_statement_execute_select
@@ -591,6 +593,7 @@
        gda_server_provider_get_default_dbms_type
        gda_server_provider_get_impl_functions_for_class
        gda_server_provider_get_name
+       gda_server_provider_get_real_main_context
        gda_server_provider_get_server_version
        gda_server_provider_get_type
        gda_server_provider_get_version
diff --git a/providers/ldap/gda-ldap-provider.c b/providers/ldap/gda-ldap-provider.c
index 85b4c74..9a0e26a 100644
--- a/providers/ldap/gda-ldap-provider.c
+++ b/providers/ldap/gda-ldap-provider.c
@@ -6,7 +6,7 @@
  * Copyright (C) 2004 Julio M. Merino Vidal <jmmv menta net>
  * Copyright (C) 2004 J�rg Billeter <j bitron ch>
  * Copyright (C) 2004 Szalai Ferenc <szferi einstein ki iif hu>
- * Copyright (C) 2005 - 2012 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2005 - 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
@@ -37,6 +37,8 @@
 #include "gda-ldap-provider.h"
 #include "gdaprov-data-model-ldap.h"
 #include "gda-ldap-util.h"
+#include <libgda/gda-server-provider-private.h> /* for gda_server_provider_get_real_main_context () */
+#include <libgda/gda-connection-internal.h> /* for gda_connection_set_status() */
 
 static void gda_ldap_provider_class_init (GdaLdapProviderClass *klass);
 static void gda_ldap_provider_init       (GdaLdapProvider *provider,
@@ -48,6 +50,7 @@ static const gchar *gda_ldap_provider_get_version (GdaServerProvider *provider);
 static GdaConnection *gda_ldap_provider_create_connection (GdaServerProvider *provider);
 static gboolean gda_ldap_provider_prepare_connection (GdaServerProvider *provider, GdaConnection *cnc, 
                                                      GdaQuarkList *params, GdaQuarkList *auth);
+static gboolean gda_ldap_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc);
 static GObject *gda_ldap_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
                                                     GdaStatement *stmt, GdaSet *params,
                                                     GdaStatementModelUsage model_usage,
@@ -83,7 +86,7 @@ GdaServerProviderBase ldap_base_functions = {
        NULL,
        NULL,
        gda_ldap_provider_prepare_connection,
-       NULL,
+       gda_ldap_provider_close_connection,
        NULL,
        NULL,
        NULL,
@@ -268,6 +271,8 @@ LdapAuthMapping mappings[] = {
 };
 
 /*
+ * Function called during initialization phase => no need to use the GdaWorker object
+ *
  * Using @url and @username, performs the following tasks:
  * - bind to the LDAP server anonymously
  * - search the directory to identify the entry for the provided user name,
@@ -631,49 +636,112 @@ gda_ldap_provider_prepare_connection (GdaServerProvider *provider, GdaConnection
        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);
-       gda_ldap_may_unbind (cdata);
+       gda_ldap_may_unbind (GDA_LDAP_CONNECTION (cnc));
        return TRUE;
 }
 
 /*
+ * Close connection request
+ *
+ * In this function, the following _must_ be done:
+ *   - Actually close the connection to the database using @cnc's associated LdapConnectionData structure
+ *   - Free the LdapConnectionData structure and its contents
+ *
+ * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR connection event must be added to 
@cnc)
+ */
+static gboolean
+gda_ldap_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc)
+{
+       LdapConnectionData *cdata;
+       g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+       g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+
+       /* Close the connection using the C API */
+       cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (cnc));
+       if (!cdata)
+               return FALSE;
+
+       if (cdata->handle) {
+               ldap_unbind_ext (cdata->handle, NULL, NULL);
+               cdata->handle = NULL;
+       }
+
+       GdaServerProviderBase *fset;
+       fset = gda_server_provider_get_impl_functions_for_class (parent_class, 
GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
+       return fset->close_connection (provider, cnc);
+}
+
+
+gpointer
+worker_gda_ldap_may_unbind (LdapConnectionData *cdata, GError **error)
+{
+       if (cdata->handle) {
+                ldap_unbind_ext (cdata->handle, NULL, NULL);
+               cdata->handle = NULL;
+       }
+
+       return NULL;
+}
+
+/*
  * Unbinds the connection if possible (i.e. if cdata->keep_bound_count is 0)
  * This allows to avoid keeping the connection to the LDAP server if unused
  */
 void
-gda_ldap_may_unbind (LdapConnectionData *cdata)
+gda_ldap_may_unbind (GdaLdapConnection *cnc)
 {
-       if (!cdata || (cdata->keep_bound_count > 0))
+       gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+       LdapConnectionData *cdata;
+       cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (cnc));
+       if (!cdata || (cdata->keep_bound_count > 0)) {
+               gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
                return;
-       if (cdata->handle) {
-                ldap_unbind_ext (cdata->handle, NULL, NULL);
-               cdata->handle = NULL;
        }
+
+       GdaServerProviderConnectionData *pcdata;
+       pcdata = gda_connection_internal_get_provider_data_error ((GdaConnection*) cnc, NULL);
+
+       GdaWorker *worker;
+       worker = gda_worker_ref (gda_connection_internal_get_worker (pcdata));
+
+       GMainContext *context;
+       context = gda_server_provider_get_real_main_context ((GdaConnection *) cnc);
+
+       gpointer retval;
+       gda_worker_do_job (worker, context, 0, &retval, NULL,
+                          (GdaWorkerFunc) worker_gda_ldap_may_unbind, (gpointer) cdata, NULL, NULL, NULL);
+       if (context)
+               g_main_context_unref (context);
+
+       gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+       gda_worker_unref (worker);
 }
 
 /*
  * Makes sure the connection is opened
  */
 gboolean
-gda_ldap_ensure_bound (LdapConnectionData *cdata, GError **error)
+gda_ldap_ensure_bound (GdaLdapConnection *cnc, GError **error)
 {
+       LdapConnectionData *cdata;
+       cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (cnc));
+
        if (!cdata)
                return FALSE;
        else if (cdata->handle)
                return TRUE;
 
-       return gda_ldap_rebind (cdata, error);
+       return gda_ldap_rebind (cnc, error);
 }
 
-/*
- * Reopens a connection after the server has closed it (possibly because of a timeout)
- *
- * If it fails, then @cdata is left unchanged, otherwise it is modified to be useable again.
- */
-gboolean
-gda_ldap_rebind (LdapConnectionData *cdata, GError **error)
+
+gpointer
+worker_gda_ldap_rebind (LdapConnectionData *cdata, GError **error)
 {
        if (!cdata)
-               return FALSE;
+               return NULL;
 
        /*g_print ("Trying to reconnect...\n");*/
        LDAP *ld;
@@ -682,7 +750,7 @@ gda_ldap_rebind (LdapConnectionData *cdata, GError **error)
        if (res != LDAP_SUCCESS) {
                g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_OPEN_ERROR,
                             "%s", ldap_err2string (res));
-               return FALSE;
+               return NULL;
        }
 
        /* set protocol version to 3 by default */
@@ -697,7 +765,7 @@ gda_ldap_rebind (LdapConnectionData *cdata, GError **error)
                        g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_OPEN_ERROR,
                                     "%s", ldap_err2string (res));
                        ldap_unbind_ext (ld, NULL, NULL);
-                       return FALSE;
+                       return NULL;
                }
         }
 
@@ -721,7 +789,7 @@ gda_ldap_rebind (LdapConnectionData *cdata, GError **error)
                g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_OPEN_ERROR,
                             "%s", ldap_err2string (res));
                ldap_unbind_ext (ld, NULL, NULL);
-                return FALSE;
+                return NULL;
        }
 
        /* time limit */
@@ -731,7 +799,7 @@ gda_ldap_rebind (LdapConnectionData *cdata, GError **error)
                g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_OPEN_ERROR,
                             "%s", ldap_err2string (res));
                ldap_unbind_ext (ld, NULL, NULL);
-                return FALSE;
+                return NULL;
        }
 
        /* size limit */
@@ -741,7 +809,7 @@ gda_ldap_rebind (LdapConnectionData *cdata, GError **error)
                g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_OPEN_ERROR,
                             "%s", ldap_err2string (res));
                ldap_unbind_ext (ld, NULL, NULL);
-                return FALSE;
+                return NULL;
        }
 
        /* all ok */
@@ -752,7 +820,46 @@ gda_ldap_rebind (LdapConnectionData *cdata, GError **error)
        cdata->handle = ld;
 
        /*g_print ("Reconnected!\n");*/
-       return TRUE;
+       return (gpointer) 0x01;
+}
+
+/*
+ * Reopens a connection after the server has closed it (possibly because of a timeout)
+ */
+gboolean
+gda_ldap_rebind (GdaLdapConnection *cnc, GError **error)
+{
+       g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), FALSE);
+       gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+       LdapConnectionData *cdata;
+       cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (cnc));
+        if (!cdata) {
+               gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+               g_warning ("cdata != NULL failed");
+               return FALSE;
+       }
+
+       GdaServerProviderConnectionData *pcdata;
+       pcdata = gda_connection_internal_get_provider_data_error ((GdaConnection*) cnc, NULL);
+
+       GdaWorker *worker;
+       worker = gda_worker_ref (gda_connection_internal_get_worker (pcdata));
+
+       GMainContext *context;
+       context = gda_server_provider_get_real_main_context ((GdaConnection *) cnc);
+
+       gpointer retval;
+       gda_worker_do_job (worker, context, 0, &retval, NULL,
+                          (GdaWorkerFunc) worker_gda_ldap_rebind, (gpointer) cdata, NULL, NULL, error);
+       if (context)
+               g_main_context_unref (context);
+
+       gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+       gda_worker_unref (worker);
+
+       return retval ? TRUE : FALSE;
 }
 
 /*
@@ -967,9 +1074,7 @@ gda_ldap_provider_statement_execute (GdaServerProvider *provider, GdaConnection
        }
 
        /* check connection to LDAP is Ok */
-       LdapConnectionData *cdata;
-        cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (cnc));
-       if (! gda_ldap_ensure_bound (cdata, error))
+       if (! gda_ldap_ensure_bound (GDA_LDAP_CONNECTION (cnc), error))
                return NULL;
 
        GdaServerProviderBase *fset;
diff --git a/providers/ldap/gda-ldap-util.c b/providers/ldap/gda-ldap-util.c
index 3c0eea9..b4f09bb 100644
--- a/providers/ldap/gda-ldap-util.c
+++ b/providers/ldap/gda-ldap-util.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 - 2012 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2011 - 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,9 +22,10 @@
 #include <glib/gi18n-lib.h>
 #include "gda-ldap.h"
 #include "gda-ldap-util.h"
-#include <sqlite/virtual/gda-ldap-connection.h>
 #include <gda-util.h>
 #include <libgda/gda-debug-macros.h>
+#include <libgda/gda-server-provider-private.h> /* for gda_server_provider_get_real_main_context () */
+#include <libgda/gda-connection-internal.h> /* for gda_connection_set_status() */
 
 static void
 ldap_attribute_free (LdapAttribute *lat)
@@ -330,36 +331,35 @@ gda_ldap_get_type_info (const gchar *oid)
        return retval ? retval : &unknown_type;
 }
 
-/**
- * gda_ldap_get_attr_info:
- *
- * Returns: the #LdapAttribute for @attribute, or %NULL
- */
-LdapAttribute *
-gda_ldap_get_attr_info (LdapConnectionData *cdata, const gchar *attribute)
+typedef struct {
+       GdaLdapConnection *cnc;
+       LdapConnectionData *cdata;
+       const gchar *attribute;
+} WorkerLdapAttrInfoData;
+
+static LdapAttribute *
+worker_gda_ldap_get_attr_info (WorkerLdapAttrInfoData *data, GError **error)
 {
        LdapAttribute *retval = NULL;
-       if (! attribute || !cdata)
-               return NULL;
 
-       if (cdata->attributes_hash)
-               return g_hash_table_lookup (cdata->attributes_hash, attribute);
+       if (data->cdata->attributes_hash)
+               return g_hash_table_lookup (data->cdata->attributes_hash, data->attribute);
 
        /* initialize known types */
-       cdata->attributes_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
+       data->cdata->attributes_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                        NULL,
                                                        (GDestroyNotify) ldap_attribute_free);
        
 
-       if (cdata->attributes_cache_file) {
+       if (data->cdata->attributes_cache_file) {
                /* try to load from cache file, which must contain one line per attribute:
                 * <syntax oid>,0|1,<attribute name>
                 */
-               gchar *data;
-               if (g_file_get_contents (cdata->attributes_cache_file, &data, NULL, NULL)) {
+               gchar *fdata;
+               if (g_file_get_contents (data->cdata->attributes_cache_file, &fdata, NULL, NULL)) {
                        gchar *start, *ptr;
                        gchar **array;
-                       start = data;
+                       start = fdata;
                        while (1) {
                                gboolean done = FALSE;
                                for (ptr = start; *ptr && (*ptr != '\n'); ptr++);
@@ -376,7 +376,7 @@ gda_ldap_get_attr_info (LdapConnectionData *cdata, const gchar *attribute)
                                                lat->name = g_strdup (array[2]);
                                                lat->type = gda_ldap_get_type_info (array[0]);
                                                lat->single_value = (*array[1] == '0' ? FALSE : TRUE);
-                                               g_hash_table_insert (cdata->attributes_hash,
+                                               g_hash_table_insert (data->cdata->attributes_hash,
                                                                     lat->name, lat);
                                                /*g_print ("CACHE ADDED [%s][%p][%d] for OID %s\n",
                                                  lat->name, lat->type, lat->single_value,
@@ -389,8 +389,8 @@ gda_ldap_get_attr_info (LdapConnectionData *cdata, const gchar *attribute)
                                else
                                        start = ptr+1;
                        }
-                       g_free (data);
-                       return g_hash_table_lookup (cdata->attributes_hash, attribute);
+                       g_free (fdata);
+                       return g_hash_table_lookup (data->cdata->attributes_hash, data->attribute);
                }
        }
 
@@ -403,25 +403,25 @@ gda_ldap_get_attr_info (LdapConnectionData *cdata, const gchar *attribute)
        char *schema_attrs[] = {"attributeTypes", NULL};
        
        /* look for subschema */
-       if (! gda_ldap_ensure_bound (cdata, NULL))
+       if (! gda_ldap_ensure_bound (data->cnc, NULL))
                return NULL;
 
-       res = ldap_search_ext_s (cdata->handle, "", LDAP_SCOPE_BASE,
+       res = ldap_search_ext_s (data->cdata->handle, "", LDAP_SCOPE_BASE,
                                 "(objectclass=*)",
                                 subschemasubentry, 0,
                                 NULL, NULL, NULL, 0,
                                 &msg);
        if (res != LDAP_SUCCESS) {
-               gda_ldap_may_unbind (cdata);
+               gda_ldap_may_unbind (data->cnc);
                return NULL;
        }
 
-       if ((entry = ldap_first_entry (cdata->handle, msg))) {
+       if ((entry = ldap_first_entry (data->cdata->handle, msg))) {
                char *attr;
                BerElement *ber;
-               if ((attr = ldap_first_attribute (cdata->handle, entry, &ber))) {
+               if ((attr = ldap_first_attribute (data->cdata->handle, entry, &ber))) {
                        BerValue **bvals;
-                       if ((bvals = ldap_get_values_len (cdata->handle, entry, attr))) {
+                       if ((bvals = ldap_get_values_len (data->cdata->handle, entry, attr))) {
                                subschema = g_strdup (bvals[0]->bv_val);
                                ldap_value_free_len (bvals);
                        }
@@ -433,41 +433,41 @@ gda_ldap_get_attr_info (LdapConnectionData *cdata, const gchar *attribute)
        ldap_msgfree (msg);
 
        if (! subschema) {
-               gda_ldap_may_unbind (cdata);
+               gda_ldap_may_unbind (data->cnc);
                return NULL;
        }
 
        /* look for attributeTypes */
-       res = ldap_search_ext_s (cdata->handle, subschema, LDAP_SCOPE_BASE,
+       res = ldap_search_ext_s (data->cdata->handle, subschema, LDAP_SCOPE_BASE,
                                 "(objectclass=*)",
                                 schema_attrs, 0,
                                 NULL, NULL, NULL, 0,
                                 &msg);
        g_free (subschema);
        if (res != LDAP_SUCCESS) {
-               gda_ldap_may_unbind (cdata);
+               gda_ldap_may_unbind (data->cnc);
                return NULL;
        }
 
-       if (cdata->attributes_cache_file)
+       if (data->cdata->attributes_cache_file)
                string = g_string_new ("# Cache file. This file can safely be removed, in this case\n"
                                       "# it will be automatically recreated.\n"
                                       "# DO NOT MODIFY\n");
-       for (entry = ldap_first_entry (cdata->handle, msg);
+       for (entry = ldap_first_entry (data->cdata->handle, msg);
             entry;
-            entry = ldap_next_entry (cdata->handle, msg)) {
+            entry = ldap_next_entry (data->cdata->handle, msg)) {
                char *attr;
                BerElement *ber;
-               for (attr = ldap_first_attribute (cdata->handle, msg, &ber);
+               for (attr = ldap_first_attribute (data->cdata->handle, msg, &ber);
                     attr;
-                    attr = ldap_next_attribute (cdata->handle, msg, ber)) {
+                    attr = ldap_next_attribute (data->cdata->handle, msg, ber)) {
                        if (strcasecmp(attr, "attributeTypes")) {
                                ldap_memfree (attr);
                                continue;
                        }
 
                        BerValue **bvals;
-                       bvals = ldap_get_values_len (cdata->handle, entry, attr);
+                       bvals = ldap_get_values_len (data->cdata->handle, entry, attr);
                        if (bvals) {
                                gint i;
                                for (i = 0; bvals[i]; i++) {
@@ -484,7 +484,7 @@ gda_ldap_get_attr_info (LdapConnectionData *cdata, const gchar *attribute)
                                                lat->name = g_strdup (at->at_names [0]);
                                                lat->type = gda_ldap_get_type_info (at->at_syntax_oid);
                                                lat->single_value = (at->at_single_value == 0 ? FALSE : TRUE);
-                                               g_hash_table_insert (cdata->attributes_hash,
+                                               g_hash_table_insert (data->cdata->attributes_hash,
                                                                     lat->name, lat);
                                                /*g_print ("ADDED [%s][%p][%d] for OID %s\n",
                                                  lat->name, lat->type, lat->single_value,
@@ -510,21 +510,66 @@ gda_ldap_get_attr_info (LdapConnectionData *cdata, const gchar *attribute)
        ldap_msgfree (msg);
 
        if (string) {
-               if (! g_file_set_contents (cdata->attributes_cache_file, string->str, -1, NULL)) {
+               if (! g_file_set_contents (data->cdata->attributes_cache_file, string->str, -1, NULL)) {
                        gchar *dirname;
-                       dirname = g_path_get_dirname (cdata->attributes_cache_file);
+                       dirname = g_path_get_dirname (data->cdata->attributes_cache_file);
                        g_mkdir_with_parents (dirname, 0700);
                        g_free (dirname);
-                       g_file_set_contents (cdata->attributes_cache_file, string->str, -1, NULL);
+                       g_file_set_contents (data->cdata->attributes_cache_file, string->str, -1, NULL);
                }
                g_string_free (string, TRUE);
        }
 
-       gda_ldap_may_unbind (cdata);
-       retval = g_hash_table_lookup (cdata->attributes_hash, attribute);
+       gda_ldap_may_unbind (data->cnc);
+       retval = g_hash_table_lookup (data->cdata->attributes_hash, data->attribute);
        return retval;
 }
 
+/**
+ * gda_ldap_get_attr_info:
+ * @cnc: a #GdaLdapConnection
+ * @cdata:
+ * @attribute:
+ *
+ * Returns: (transfer none): the #LdapAttribute for @attribute, or %NULL
+ */
+LdapAttribute *
+gda_ldap_get_attr_info (GdaLdapConnection *cnc, LdapConnectionData *cdata, const gchar *attribute)
+{
+       g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+       if (! attribute || !cdata)
+               return NULL;
+
+       gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+       GdaServerProviderConnectionData *pcdata;
+       pcdata = gda_connection_internal_get_provider_data_error ((GdaConnection*) cnc, NULL);
+
+       GdaWorker *worker;
+       worker = gda_worker_ref (gda_connection_internal_get_worker (pcdata));
+
+       GMainContext *context;
+       context = gda_server_provider_get_real_main_context ((GdaConnection *) cnc);
+
+       WorkerLdapAttrInfoData data;
+       data.cnc = cnc;
+       data.cdata = cdata;
+       data.attribute = attribute;
+
+       gda_connection_set_status ((GdaConnection*) cnc, GDA_CONNECTION_STATUS_BUSY);
+       gpointer retval;
+       gda_worker_do_job (worker, context, 0, &retval, NULL,
+                          (GdaWorkerFunc) worker_gda_ldap_get_attr_info, (gpointer) &data, NULL, NULL, NULL);
+       if (context)
+               g_main_context_unref (context);
+
+       gda_connection_set_status ((GdaConnection*) cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+       gda_worker_unref (worker);
+       return (LdapAttribute*) retval;
+}
+
 /*
  * Classes
  */
@@ -532,32 +577,21 @@ static gchar **make_array_from_strv (char **values, guint *out_size);
 static void classes_h_func (GdaLdapClass *lcl, gchar **supclasses, LdapConnectionData *cdata);
 static gint classes_sort (GdaLdapClass *lcl1, GdaLdapClass *lcl2);
 
-/**
- * gdaprov_ldap_get_class_info:
- * @cnc: a #GdaLdapConnection (not %NULL)
- * @classname: the class name (not %NULL)
- *
- * Returns: the #GdaLdapClass for @classname, or %NULL
- */
-GdaLdapClass *
-gdaprov_ldap_get_class_info (GdaLdapConnection *cnc, const gchar *classname)
-{
-       GdaLdapClass *retval = NULL;
+typedef struct {
+       GdaLdapConnection *cnc;
        LdapConnectionData *cdata;
-       g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), NULL);
-       g_return_val_if_fail (classname, NULL);
-       
-        cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (cnc));
-        if (!cdata)
-               return NULL;
+       const gchar *classname;
+} WorkerLdapClassInfoData;
 
-       if (cdata->classes_hash)
-               return g_hash_table_lookup (cdata->classes_hash, classname);
+static GdaLdapClass *
+worker_gdaprov_ldap_get_class_info (WorkerLdapClassInfoData *data, GError **error)
+{
+       GdaLdapClass *retval = NULL;
 
        /* initialize known classes */
-       cdata->classes_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                                    NULL,
-                                                    (GDestroyNotify) ldap_class_free);
+       data->cdata->classes_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                          NULL,
+                                                          (GDestroyNotify) ldap_class_free);
 
        LDAPMessage *msg, *entry;
        int res;
@@ -567,25 +601,25 @@ gdaprov_ldap_get_class_info (GdaLdapConnection *cnc, const gchar *classname)
        char *schema_attrs[] = {"objectClasses", NULL};
        
        /* look for subschema */
-       if (! gda_ldap_ensure_bound (cdata, NULL))
+       if (! gda_ldap_ensure_bound (data->cnc, NULL))
                return NULL;
 
-       res = ldap_search_ext_s (cdata->handle, "", LDAP_SCOPE_BASE,
+       res = ldap_search_ext_s (data->cdata->handle, "", LDAP_SCOPE_BASE,
                                 "(objectclass=*)",
                                 subschemasubentry, 0,
                                 NULL, NULL, NULL, 0,
                                 &msg);
        if (res != LDAP_SUCCESS) {
-               gda_ldap_may_unbind (cdata);
+               gda_ldap_may_unbind (data->cnc);
                return NULL;
        }
 
-       if ((entry = ldap_first_entry (cdata->handle, msg))) {
+       if ((entry = ldap_first_entry (data->cdata->handle, msg))) {
                char *attr;
                BerElement *ber;
-               if ((attr = ldap_first_attribute (cdata->handle, entry, &ber))) {
+               if ((attr = ldap_first_attribute (data->cdata->handle, entry, &ber))) {
                        BerValue **bvals;
-                       if ((bvals = ldap_get_values_len (cdata->handle, entry, attr))) {
+                       if ((bvals = ldap_get_values_len (data->cdata->handle, entry, attr))) {
                                subschema = g_strdup (bvals[0]->bv_val);
                                ldap_value_free_len (bvals);
                        }
@@ -597,39 +631,39 @@ gdaprov_ldap_get_class_info (GdaLdapConnection *cnc, const gchar *classname)
        ldap_msgfree (msg);
 
        if (! subschema) {
-               gda_ldap_may_unbind (cdata);
+               gda_ldap_may_unbind (data->cnc);
                return NULL;
        }
 
        /* look for attributeTypes */
-       res = ldap_search_ext_s (cdata->handle, subschema, LDAP_SCOPE_BASE,
+       res = ldap_search_ext_s (data->cdata->handle, subschema, LDAP_SCOPE_BASE,
                                 "(objectclass=*)",
                                 schema_attrs, 0,
                                 NULL, NULL, NULL, 0,
                                 &msg);
        g_free (subschema);
        if (res != LDAP_SUCCESS) {
-               gda_ldap_may_unbind (cdata);
+               gda_ldap_may_unbind (data->cnc);
                return NULL;
        }
 
        GHashTable *h_refs;
        h_refs = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_strfreev);
-       for (entry = ldap_first_entry (cdata->handle, msg);
+       for (entry = ldap_first_entry (data->cdata->handle, msg);
             entry;
-            entry = ldap_next_entry (cdata->handle, msg)) {
+            entry = ldap_next_entry (data->cdata->handle, msg)) {
                char *attr;
                BerElement *ber;
-               for (attr = ldap_first_attribute (cdata->handle, msg, &ber);
+               for (attr = ldap_first_attribute (data->cdata->handle, msg, &ber);
                     attr;
-                    attr = ldap_next_attribute (cdata->handle, msg, ber)) {
+                    attr = ldap_next_attribute (data->cdata->handle, msg, ber)) {
                        if (strcasecmp(attr, "objectClasses")) {
                                ldap_memfree (attr);
                                continue;
                        }
 
                        BerValue **bvals;
-                       bvals = ldap_get_values_len (cdata->handle, entry, attr);
+                       bvals = ldap_get_values_len (data->cdata->handle, entry, attr);
                        if (bvals) {
                                gint i;
                                for (i = 0; bvals[i]; i++) {
@@ -655,7 +689,7 @@ gdaprov_ldap_get_class_info (GdaLdapConnection *cnc, const gchar *classname)
                                                        g_print ("  oc_names[%d] = %s\n",
                                                                 k, lcl->names[k]);
 #endif
-                                                       g_hash_table_insert (cdata->classes_hash,
+                                                       g_hash_table_insert (data->cdata->classes_hash,
                                                                             lcl->names[k],
                                                                             lcl);
                                                }
@@ -692,7 +726,7 @@ gdaprov_ldap_get_class_info (GdaLdapConnection *cnc, const gchar *classname)
                                                if (refs)
                                                        g_hash_table_insert (h_refs, lcl, refs);
                                                else
-                                                       cdata->top_classes = g_slist_insert_sorted 
(cdata->top_classes,
+                                                       data->cdata->top_classes = g_slist_insert_sorted 
(data->cdata->top_classes,
                                                                             lcl, (GCompareFunc) 
classes_sort);
 #ifdef CLASS_DEBUG
                                                for (k = 0; oc->oc_sup_oids && oc->oc_sup_oids[k]; k++)
@@ -732,14 +766,69 @@ gdaprov_ldap_get_class_info (GdaLdapConnection *cnc, const gchar *classname)
        ldap_msgfree (msg);
 
        /* create hierarchy */
-       g_hash_table_foreach (h_refs, (GHFunc) classes_h_func, cdata);
+       g_hash_table_foreach (h_refs, (GHFunc) classes_h_func, data->cdata);
        g_hash_table_destroy (h_refs);
 
-       retval = g_hash_table_lookup (cdata->classes_hash, classname);
-       gda_ldap_may_unbind (cdata);
+       retval = g_hash_table_lookup (data->cdata->classes_hash, data->classname);
+       gda_ldap_may_unbind (data->cnc);
        return retval;
 }
 
+/**
+ * gdaprov_ldap_get_class_info:
+ * @cnc: a #GdaLdapConnection (not %NULL)
+ * @classname: the class name (not %NULL)
+ *
+ * Returns: the #GdaLdapClass for @classname, or %NULL
+ */
+GdaLdapClass *
+gdaprov_ldap_get_class_info (GdaLdapConnection *cnc, const gchar *classname)
+{
+       g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), NULL);
+       g_return_val_if_fail (classname, NULL);
+
+       gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+       LdapConnectionData *cdata;
+        cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (cnc));
+        if (!cdata) {
+               gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+                return NULL;
+       }
+
+       if (cdata->classes_hash) {
+               gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+               return g_hash_table_lookup (cdata->classes_hash, classname);
+       }
+
+       GdaServerProviderConnectionData *pcdata;
+       pcdata = gda_connection_internal_get_provider_data_error ((GdaConnection*) cnc, NULL);
+
+       GdaWorker *worker;
+       worker = gda_worker_ref (gda_connection_internal_get_worker (pcdata));
+
+       GMainContext *context;
+       context = gda_server_provider_get_real_main_context ((GdaConnection *) cnc);
+
+       WorkerLdapClassInfoData data;
+       data.cnc = cnc;
+       data.cdata = cdata;
+       data.classname = classname;
+
+       gda_connection_set_status ((GdaConnection*) cnc, GDA_CONNECTION_STATUS_BUSY);
+       gpointer retval;
+       gda_worker_do_job (worker, context, 0, &retval, NULL,
+                          (GdaWorkerFunc) worker_gdaprov_ldap_get_class_info, (gpointer) &data, NULL, NULL, 
NULL);
+       if (context)
+               g_main_context_unref (context);
+
+       gda_connection_set_status ((GdaConnection*) cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+       gda_worker_unref (worker);
+       return (GdaLdapClass*) retval;
+}
+
 static gint
 my_sort_func (gconstpointer a, gconstpointer b)
 {
@@ -831,14 +920,14 @@ gdaprov_ldap_get_top_classes (GdaLdapConnection *cnc)
  * to the specified GType if any)
  */
 GType
-gda_ldap_get_g_type (LdapConnectionData *cdata, const gchar *attribute_name, const gchar *specified_gtype)
+gda_ldap_get_g_type (GdaLdapConnection *cnc, LdapConnectionData *cdata, const gchar *attribute_name, const 
gchar *specified_gtype)
 {
        GType coltype = GDA_TYPE_NULL;
        if (specified_gtype)
                coltype = gda_g_type_from_string (specified_gtype);
        if ((coltype == G_TYPE_INVALID) || (coltype == GDA_TYPE_NULL)) {
                LdapAttribute *lat;
-               lat = gda_ldap_get_attr_info (cdata, attribute_name);
+               lat = gda_ldap_get_attr_info (cnc, cdata, attribute_name);
                if (lat)
                        coltype = lat->type->gtype;
        }
@@ -1166,7 +1255,6 @@ gboolean
 gda_ldap_parse_dn (const char *attr, gchar **out_userdn)
 {
        LDAPDN tmpDN;
-
        if (out_userdn)
                *out_userdn = NULL;
 
@@ -1209,27 +1297,24 @@ attr_array_sort_func (gconstpointer a, gconstpointer b)
        return strcmp (att1->attr_name, att2->attr_name);
 }
 
-GdaLdapEntry *
-gdaprov_ldap_describe_entry (GdaLdapConnection *cnc, const gchar *dn, GError **error)
-{
+typedef struct {
+       GdaLdapConnection *cnc;
        LdapConnectionData *cdata;
-       g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), NULL);
-       g_return_val_if_fail (!dn || (dn && *dn), NULL);
+       const gchar *dn;
+} WorkerLdapDescrEntryData;
 
-        cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (cnc));
-        if (!cdata)
-                return NULL;
-
-
-       if (! gda_ldap_ensure_bound (cdata, error))
+static GdaLdapEntry *
+worker_gdaprov_ldap_describe_entry (WorkerLdapDescrEntryData *data, GError **error)
+{
+       if (! gda_ldap_ensure_bound (data->cnc, error))
                return NULL;
 
        int res;
        LDAPMessage *msg = NULL;
        const gchar *real_dn;
-       real_dn = dn ? dn : cdata->base_dn;
+       real_dn = data->dn ? data->dn : data->cdata->base_dn;
  retry:
-       res = ldap_search_ext_s (cdata->handle, real_dn, LDAP_SCOPE_BASE,
+       res = ldap_search_ext_s (data->cdata->handle, real_dn, LDAP_SCOPE_BASE,
                                 "(objectClass=*)", NULL, 0,
                                 NULL, NULL, NULL, -1,
                                 &msg);
@@ -1243,10 +1328,10 @@ gdaprov_ldap_describe_entry (GdaLdapConnection *cnc, const gchar *dn, GError **e
                GdaLdapEntry *lentry;
                GArray *array = NULL;
 
-               nb_entries = ldap_count_entries (cdata->handle, msg);
+               nb_entries = ldap_count_entries (data->cdata->handle, msg);
                if (nb_entries == 0) {
                        ldap_msgfree (msg);
-                       gda_ldap_may_unbind (cdata);
+                       gda_ldap_may_unbind (data->cnc);
                        return NULL;
                }
                else if (nb_entries > 1) {
@@ -1254,7 +1339,7 @@ gdaprov_ldap_describe_entry (GdaLdapConnection *cnc, const gchar *dn, GError **e
                                     GDA_SERVER_PROVIDER_INTERNAL_ERROR,
                                     _("LDAP server returned more than one entry with DN '%s'"),
                                     real_dn);
-                       gda_ldap_may_unbind (cdata);
+                       gda_ldap_may_unbind (data->cnc);
                        return NULL;
                }
 
@@ -1262,13 +1347,13 @@ gdaprov_ldap_describe_entry (GdaLdapConnection *cnc, const gchar *dn, GError **e
                lentry->dn = g_strdup (real_dn);
                lentry->attributes_hash = g_hash_table_new (g_str_hash, g_str_equal);
                array = g_array_new (TRUE, FALSE, sizeof (GdaLdapAttribute*));
-               ldap_row = ldap_first_entry (cdata->handle, msg);
-               for (attr = ldap_first_attribute (cdata->handle, ldap_row, &ber);
+               ldap_row = ldap_first_entry (data->cdata->handle, msg);
+               for (attr = ldap_first_attribute (data->cdata->handle, ldap_row, &ber);
                     attr;
-                    attr = ldap_next_attribute (cdata->handle, ldap_row, ber)) {
+                    attr = ldap_next_attribute (data->cdata->handle, ldap_row, ber)) {
                        BerValue **bvals;
                        GArray *varray = NULL;
-                       bvals = ldap_get_values_len (cdata->handle, ldap_row, attr);
+                       bvals = ldap_get_values_len (data->cdata->handle, ldap_row, attr);
                        if (bvals) {
                                gint i;
                                for (i = 0; bvals [i]; i++) {
@@ -1276,9 +1361,9 @@ gdaprov_ldap_describe_entry (GdaLdapConnection *cnc, const gchar *dn, GError **e
                                                varray = g_array_new (TRUE, FALSE, sizeof (GValue *));
                                        GValue *value;
                                        GType type;
-                                       type = gda_ldap_get_g_type (cdata, attr, NULL);
+                                       type = gda_ldap_get_g_type (data->cnc, data->cdata, attr, NULL);
                                        /*g_print ("Type for attr %s is %s\n", attr, gda_g_type_to_string 
(type)); */
-                                       value = gda_ldap_attr_value_to_g_value (cdata, type, bvals[i]);
+                                       value = gda_ldap_attr_value_to_g_value (data->cdata, type, bvals[i]);
                                        g_array_append_val (varray, value);
                                }
                                ldap_value_free_len (bvals);
@@ -1305,13 +1390,13 @@ gdaprov_ldap_describe_entry (GdaLdapConnection *cnc, const gchar *dn, GError **e
                        lentry->nb_attributes = array->len;
                        g_array_free (array, FALSE);
                }
-               gda_ldap_may_unbind (cdata);
+               gda_ldap_may_unbind (data->cnc);
                return lentry;
        }
        case LDAP_SERVER_DOWN: {
                gint i;
                for (i = 0; i < 5; i++) {
-                       if (gda_ldap_rebind (cdata, NULL))
+                       if (gda_ldap_rebind (data->cnc, NULL))
                                goto retry;
                        g_usleep (G_USEC_PER_SEC * 2);
                }
@@ -1319,15 +1404,58 @@ gdaprov_ldap_describe_entry (GdaLdapConnection *cnc, const gchar *dn, GError **e
        default: {
                /* error */
                int ldap_errno;
-               ldap_get_option (cdata->handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
+               ldap_get_option (data->cdata->handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
                g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_OTHER_ERROR,
                             "%s", ldap_err2string(ldap_errno));
-               gda_ldap_may_unbind (cdata);
+               gda_ldap_may_unbind (data->cnc);
                return NULL;
        }
        }
 }
 
+GdaLdapEntry *
+gdaprov_ldap_describe_entry (GdaLdapConnection *cnc, const gchar *dn, GError **error)
+{
+       g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), NULL);
+       g_return_val_if_fail (!dn || (dn && *dn), NULL);
+
+       gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+       LdapConnectionData *cdata;
+        cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (cnc));
+        if (!cdata) {
+               gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+                return NULL;
+       }
+
+       GdaServerProviderConnectionData *pcdata;
+       pcdata = gda_connection_internal_get_provider_data_error ((GdaConnection*) cnc, NULL);
+
+       GdaWorker *worker;
+       worker = gda_worker_ref (gda_connection_internal_get_worker (pcdata));
+
+       GMainContext *context;
+       context = gda_server_provider_get_real_main_context ((GdaConnection *) cnc);
+
+       WorkerLdapDescrEntryData data;
+       data.cnc = cnc;
+       data.cdata = cdata;
+       data.dn = dn;
+
+       gda_connection_set_status ((GdaConnection*) cnc, GDA_CONNECTION_STATUS_BUSY);
+       gpointer retval;
+       gda_worker_do_job (worker, context, 0, &retval, NULL,
+                          (GdaWorkerFunc) worker_gdaprov_ldap_describe_entry, (gpointer) &data, NULL, NULL, 
error);
+       if (context)
+               g_main_context_unref (context);
+
+       gda_connection_set_status ((GdaConnection*) cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+       gda_worker_unref (worker);
+       return (GdaLdapEntry*) retval;
+}
+
 static gint
 entry_array_sort_func (gconstpointer a, gconstpointer b)
 {
@@ -1337,26 +1465,21 @@ entry_array_sort_func (gconstpointer a, gconstpointer b)
        return strcmp (e2->dn, e1->dn);
 }
 
-GdaLdapEntry **
-gdaprov_ldap_get_entry_children (GdaLdapConnection *cnc, const gchar *dn, gchar **attributes,
-                                GError **error)
-{
+typedef struct {
+       GdaLdapConnection *cnc;
        LdapConnectionData *cdata;
-       g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), NULL);
-       g_return_val_if_fail (!dn || (dn && *dn), NULL);
-
-        cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (cnc));
-        if (!cdata)
-                return NULL;
-
-       if (! gda_ldap_ensure_bound (cdata, error))
-               return NULL;
+       const gchar *dn;
+       gchar **attributes;
+} WorkerEntryChildrenData;
 
+GdaLdapEntry **
+worker_gdaprov_ldap_get_entry_children (WorkerEntryChildrenData *data, GError **error)
+{
        int res;
        LDAPMessage *msg = NULL;
  retry:
-       res = ldap_search_ext_s (cdata->handle, dn ? dn : cdata->base_dn, LDAP_SCOPE_ONELEVEL,
-                                "(objectClass=*)", attributes, 0,
+       res = ldap_search_ext_s (data->cdata->handle, data->dn ? data->dn : data->cdata->base_dn, 
LDAP_SCOPE_ONELEVEL,
+                                "(objectClass=*)", data->attributes, 0,
                                 NULL, NULL, NULL, -1,
                                 &msg);
 
@@ -1367,12 +1490,12 @@ gdaprov_ldap_get_entry_children (GdaLdapConnection *cnc, const gchar *dn, gchar
                GArray *children;
 
                children = g_array_new (TRUE, FALSE, sizeof (GdaLdapEntry *));
-               for (ldap_row = ldap_first_entry (cdata->handle, msg);
+               for (ldap_row = ldap_first_entry (data->cdata->handle, msg);
                     ldap_row;
-                    ldap_row = ldap_next_entry (cdata->handle, ldap_row)) {
+                    ldap_row = ldap_next_entry (data->cdata->handle, ldap_row)) {
                        char *attr;
                        GdaLdapEntry *lentry = NULL;
-                       attr = ldap_get_dn (cdata->handle, ldap_row);
+                       attr = ldap_get_dn (data->cdata->handle, ldap_row);
                        if (attr) {
                                gchar *userdn = NULL;
                                if (gda_ldap_parse_dn (attr, &userdn)) {
@@ -1397,17 +1520,17 @@ gdaprov_ldap_get_entry_children (GdaLdapConnection *cnc, const gchar *dn, gchar
                                             _("Could not parse distinguished name returned by LDAP server"));
                                break;
                        }
-                       else if (attributes) {
+                       else if (data->attributes) {
                                BerElement* ber;
                                GArray *array; /* array of GdaLdapAttribute pointers */
                                lentry->attributes_hash = g_hash_table_new (g_str_hash, g_str_equal);
                                array = g_array_new (TRUE, FALSE, sizeof (GdaLdapAttribute*));
-                               for (attr = ldap_first_attribute (cdata->handle, ldap_row, &ber);
+                               for (attr = ldap_first_attribute (data->cdata->handle, ldap_row, &ber);
                                     attr;
-                                    attr = ldap_next_attribute (cdata->handle, ldap_row, ber)) {
+                                    attr = ldap_next_attribute (data->cdata->handle, ldap_row, ber)) {
                                        BerValue **bvals;
                                        GArray *varray = NULL;
-                                       bvals = ldap_get_values_len (cdata->handle, ldap_row, attr);
+                                       bvals = ldap_get_values_len (data->cdata->handle, ldap_row, attr);
                                        if (bvals) {
                                                gint i;
                                                for (i = 0; bvals [i]; i++) {
@@ -1415,9 +1538,9 @@ gdaprov_ldap_get_entry_children (GdaLdapConnection *cnc, const gchar *dn, gchar
                                                                varray = g_array_new (TRUE, FALSE, sizeof 
(GValue *));
                                                        GValue *value;
                                                        GType type;
-                                                       type = gda_ldap_get_g_type (cdata, attr, NULL);
+                                                       type = gda_ldap_get_g_type (data->cnc, data->cdata, 
attr, NULL);
                                                        /*g_print ("%d Type for attr %s is %s\n", i, attr, 
gda_g_type_to_string (type));*/
-                                                       value = gda_ldap_attr_value_to_g_value (cdata, type, 
bvals[i]);
+                                                       value = gda_ldap_attr_value_to_g_value (data->cdata, 
type, bvals[i]);
                                                        g_array_append_val (varray, value);
                                                }
                                                ldap_value_free_len (bvals);
@@ -1447,7 +1570,7 @@ gdaprov_ldap_get_entry_children (GdaLdapConnection *cnc, const gchar *dn, gchar
                        g_array_append_val (children, lentry);
                }
                ldap_msgfree (msg);
-               gda_ldap_may_unbind (cdata);
+               gda_ldap_may_unbind (data->cnc);
                if (children) {
                        g_array_sort (children, (GCompareFunc) entry_array_sort_func);
                        return (GdaLdapEntry**) g_array_free (children, FALSE);
@@ -1458,7 +1581,7 @@ gdaprov_ldap_get_entry_children (GdaLdapConnection *cnc, const gchar *dn, gchar
        case LDAP_SERVER_DOWN: {
                gint i;
                for (i = 0; i < 5; i++) {
-                       if (gda_ldap_rebind (cdata, NULL))
+                       if (gda_ldap_rebind (data->cnc, NULL))
                                goto retry;
                        g_usleep (G_USEC_PER_SEC * 2);
                }
@@ -1466,15 +1589,63 @@ gdaprov_ldap_get_entry_children (GdaLdapConnection *cnc, const gchar *dn, gchar
        default: {
                /* error */
                int ldap_errno;
-               ldap_get_option (cdata->handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
+               ldap_get_option (data->cdata->handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
                g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_OTHER_ERROR,
                             "%s", ldap_err2string(ldap_errno));
-               gda_ldap_may_unbind (cdata);
+               gda_ldap_may_unbind (data->cnc);
                return NULL;
        }
        }
 }
 
+GdaLdapEntry **
+gdaprov_ldap_get_entry_children (GdaLdapConnection *cnc, const gchar *dn, gchar **attributes, GError **error)
+{
+       g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), NULL);
+       g_return_val_if_fail (!dn || (dn && *dn), NULL);
+
+       if (! gda_ldap_ensure_bound (cnc, error))
+               return NULL;
+
+       gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+       LdapConnectionData *cdata;
+       cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (cnc));
+        if (!cdata) {
+               gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+               g_warning ("cdata != NULL failed");
+               return NULL;
+       }
+
+       GdaServerProviderConnectionData *pcdata;
+       pcdata = gda_connection_internal_get_provider_data_error ((GdaConnection*) cnc, NULL);
+
+       GdaWorker *worker;
+       worker = gda_worker_ref (gda_connection_internal_get_worker (pcdata));
+
+       GMainContext *context;
+       context = gda_server_provider_get_real_main_context ((GdaConnection *) cnc);
+
+       WorkerEntryChildrenData data;
+       data.cnc = cnc;
+       data.cdata = cdata;
+       data.dn = dn;
+       data.attributes = attributes;
+
+       gda_connection_set_status ((GdaConnection*) cnc, GDA_CONNECTION_STATUS_BUSY);
+       gpointer retval;
+       gda_worker_do_job (worker, context, 0, &retval, NULL,
+                          (GdaWorkerFunc) worker_gdaprov_ldap_get_entry_children, (gpointer) &data, NULL, 
NULL, error);
+       if (context)
+               g_main_context_unref (context);
+
+       gda_connection_set_status ((GdaConnection*) cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+       gda_worker_unref (worker);
+       return (GdaLdapEntry **) retval;
+}
+
 gchar **
 gdaprov_ldap_dn_split (const gchar *dn, gboolean all)
 {
@@ -1572,7 +1743,7 @@ def_cmp_func (GdaLdapAttributeDefinition *def1, GdaLdapAttributeDefinition *def2
 }
 
 static GSList *
-handle_ldap_class (LdapConnectionData *cdata, GdaLdapClass *kl, GSList *retlist, GHashTable *hash)
+handle_ldap_class (GdaLdapConnection *cnc, LdapConnectionData *cdata, GdaLdapClass *kl, GSList *retlist, 
GHashTable *hash)
 {
        guint j;
        /*g_print ("Class [%s] (%s)\n", kl->oid, kl->names[0]);*/
@@ -1580,7 +1751,7 @@ handle_ldap_class (LdapConnectionData *cdata, GdaLdapClass *kl, GSList *retlist,
                /*g_print ("  attr [%s] REQ\n", kl->req_attributes [j]);*/
                GdaLdapAttributeDefinition *def;
                LdapAttribute *latt;
-               latt = gda_ldap_get_attr_info (cdata, kl->req_attributes [j]);
+               latt = gda_ldap_get_attr_info (cnc, cdata, kl->req_attributes [j]);
                def = g_hash_table_lookup (hash, kl->req_attributes [j]);
                if (def)
                        def->required = TRUE;
@@ -1597,7 +1768,7 @@ handle_ldap_class (LdapConnectionData *cdata, GdaLdapClass *kl, GSList *retlist,
                /*g_print ("  attr [%s] OPT\n", kl->opt_attributes [j]);*/
                GdaLdapAttributeDefinition *def;
                LdapAttribute *latt;
-               latt = gda_ldap_get_attr_info (cdata, kl->opt_attributes [j]);
+               latt = gda_ldap_get_attr_info (cnc, cdata, kl->opt_attributes [j]);
                def = g_hash_table_lookup (hash, kl->opt_attributes [j]);
                if (!def) {
                        def = g_new0 (GdaLdapAttributeDefinition, 1);
@@ -1612,7 +1783,7 @@ handle_ldap_class (LdapConnectionData *cdata, GdaLdapClass *kl, GSList *retlist,
        /* handle parents */
        GSList *list;
        for (list = kl->parents; list; list = list->next)
-               retlist = handle_ldap_class (cdata, (GdaLdapClass*) list->data, retlist, hash);
+               retlist = handle_ldap_class (cnc, cdata, (GdaLdapClass*) list->data, retlist, hash);
 
        return retlist;
 }
@@ -1648,7 +1819,7 @@ gdaprov_ldap_get_attributes_list (GdaLdapConnection *cnc, GdaLdapAttribute *obje
                        /*g_warning (_("Can't get information about '%s' class"), tmp);*/
                        continue;
                }
-               retlist = handle_ldap_class (cdata, kl, retlist, hash);
+               retlist = handle_ldap_class (cnc, cdata, kl, retlist, hash);
        }
        g_hash_table_destroy (hash);
 
diff --git a/providers/ldap/gda-ldap-util.h b/providers/ldap/gda-ldap-util.h
index 3b76d7f..e3b32d8 100644
--- a/providers/ldap/gda-ldap-util.h
+++ b/providers/ldap/gda-ldap-util.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 - 2012 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2011 - 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
@@ -26,6 +26,7 @@
 
 #include <glib.h>
 #include "gda-ldap.h"
+#include <virtual/gda-ldap-connection.h>
 
 /*
  * Attributes
@@ -43,8 +44,8 @@ typedef struct {
 } LdapAttribute;
 
 LdapAttrType  *gda_ldap_get_type_info (const gchar *oid);
-LdapAttribute *gda_ldap_get_attr_info (LdapConnectionData *cdata, const gchar *attribute);
-GType          gda_ldap_get_g_type    (LdapConnectionData *cdata, const gchar *attribute, const gchar 
*specified_gtype);
+LdapAttribute *gda_ldap_get_attr_info (GdaLdapConnection *cnc, LdapConnectionData *cdata, const gchar 
*attribute);
+GType          gda_ldap_get_g_type    (GdaLdapConnection *cnc, LdapConnectionData *cdata, const gchar 
*attribute, const gchar *specified_gtype);
 
 /*
  * Misc.
diff --git a/providers/ldap/gda-ldap.h b/providers/ldap/gda-ldap.h
index e815082..77a81a5 100644
--- a/providers/ldap/gda-ldap.h
+++ b/providers/ldap/gda-ldap.h
@@ -2,7 +2,7 @@
  * Copyright (C) 2001 - 2002 Gonzalo Paniagua Javier <gonzalo gnome-db org>
  * Copyright (C) 2001 - 2002 Rodrigo Moya <rodrigo gnome-db org>
  * Copyright (C) 2003 Danilo Schoeneberg <dj starfire-programming net>
- * Copyright (C) 2005 - 2012 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2005 - 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
@@ -33,6 +33,18 @@
 #include <glib.h>
 #include <libgda/libgda.h>
 #include <libgda/gda-connection-private.h>
+#include <virtual/gda-ldap-connection.h>
+
+/*
+ * Note about thread safety:
+ * the doc says: "libldap is thread safe in the sense that multiple
+ * threads can use separate LDAP* handles without running into concurrency
+ * issues; except for library initialization, all accesses to common data
+ * (i.e. global variables) is read-only."
+ *
+ * Here each LDAP handle is treated in its own thread, and function like ldap_str2dn(), ldap_dnfree(),
+ * are considered thread safe.
+ */
 
 /*
  * Provider's specific connection data
@@ -57,8 +69,8 @@ typedef struct {
        GHashTable   *classes_hash; /* key = class name, value = a #LdapClass */
 } LdapConnectionData;
 
-void     gda_ldap_may_unbind (LdapConnectionData *cdata);
-gboolean gda_ldap_ensure_bound (LdapConnectionData *cdata, GError **error);
-gboolean gda_ldap_rebind (LdapConnectionData *cdata, GError **error);
+void     gda_ldap_may_unbind (GdaLdapConnection *cnc);
+gboolean gda_ldap_ensure_bound (GdaLdapConnection *cnc, GError **error);
+gboolean gda_ldap_rebind (GdaLdapConnection *cnc, GError **error);
 
 #endif
diff --git a/providers/ldap/gdaprov-data-model-ldap.c b/providers/ldap/gdaprov-data-model-ldap.c
index 6a7143f..591dcac 100644
--- a/providers/ldap/gdaprov-data-model-ldap.c
+++ b/providers/ldap/gdaprov-data-model-ldap.c
@@ -30,6 +30,8 @@
 #include "gda-ldap-util.h"
 #include "gdaprov-data-model-ldap.h"
 #include <libgda/gda-debug-macros.h>
+#include <libgda/gda-server-provider-private.h> /* for gda_server_provider_get_real_main_context () */
+#include <libgda/gda-connection-internal.h> /* for gda_connection_set_status() */
 
 #define GDA_DEBUG_SUBSEARCHES
 #undef GDA_DEBUG_SUBSEARCHES
@@ -65,7 +67,7 @@ struct _LdapPart {
 #define LDAP_PART(x) ((LdapPart*)(x))
 
 static LdapPart *ldap_part_new (LdapPart *parent, const gchar *base_dn, GdaLdapSearchScope scope);
-static void ldap_part_free (LdapPart *part, LdapConnectionData *cdata);
+static void ldap_part_free (LdapPart *part, GdaLdapConnection *cdata);
 static gboolean ldap_part_split (LdapPart *part, GdaDataModelLdap *model, gboolean *out_error);
 static LdapPart *ldap_part_next (LdapPart *part, gboolean executed);
 #ifdef GDA_DEBUG_SUBSEARCHES
@@ -295,11 +297,10 @@ gda_data_model_ldap_dispose (GObject *object)
                        g_array_free (model->priv->column_mv_actions, TRUE);
 
                if (model->priv->top_exec) {
-                       LdapConnectionData *cdata;
                        if (!model->priv->cnc)
                                g_warning ("LDAP connection's cnc private attribute should not be NULL, 
please report this bug to http://bugzilla.gnome.org/ for the \"libgda\" product.");
-                       cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (model->priv->cnc));
-                       ldap_part_free (model->priv->top_exec, cdata);
+                       else
+                               ldap_part_free (model->priv->top_exec, GDA_LDAP_CONNECTION 
(model->priv->cnc));
                }
 
                if (model->priv->cnc) {
@@ -556,7 +557,7 @@ _ldap_compute_columns (GdaConnection *cnc, const gchar *attributes,
                        }
                }
 
-               coltype = gda_ldap_get_g_type (cdata, sub [0], sub [1]);
+               coltype = gda_ldap_get_g_type ((GdaLdapConnection*) cnc, cdata, sub [0], sub [1]);
                tmp = g_strdup (sub [0]);
                if (attrs)
                        g_array_append_val (attrs, tmp);
@@ -701,38 +702,37 @@ csv_quote (const gchar *string)
        return retval;
 }
 
+typedef struct {
+       GdaLdapConnection *cnc;
+       LdapConnectionData *cdata;
+       GdaDataModelLdap *imodel;
+       GdaDataModelIter *iter;
+} WorkerIterData;
+
 static void
-update_iter_from_ldap_row (GdaDataModelLdap *imodel, GdaDataModelIter *iter)
+worker_update_iter_from_ldap_row (WorkerIterData *data, GError **error)
 {
        gboolean update_model;
        BerElement* ber;
        char *attr;
        GdaHolder *holder;
        gint j, nb;
-       LdapConnectionData *cdata;
        GSList *holders_set = NULL;
 
-       g_return_if_fail (imodel->priv->cnc);
-       cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (imodel->priv->cnc));
-       g_return_if_fail (cdata);
-
-       /* LDAP connection must have been kept opened */
-       g_assert (cdata->handle);
-
-       g_object_get (G_OBJECT (iter), "update-model", &update_model, NULL);
-       g_object_set (G_OBJECT (iter), "update-model", FALSE, NULL);
+       g_object_get (G_OBJECT (data->iter), "update-model", &update_model, NULL);
+       g_object_set (G_OBJECT (data->iter), "update-model", FALSE, NULL);
                
        /* column 0 is the DN */
-       holder = GDA_HOLDER (GDA_SET (iter)->holders->data);
-       attr = ldap_get_dn (cdata->handle, imodel->priv->current_exec->ldap_row);
+       holder = GDA_HOLDER (GDA_SET (data->iter)->holders->data);
+       attr = ldap_get_dn (data->cdata->handle, data->imodel->priv->current_exec->ldap_row);
        if (attr) {
                gchar *userdn;
                if (gda_ldap_parse_dn (attr, &userdn)) {
-                       if (imodel->priv->base_dn && *imodel->priv->base_dn &&
-                           imodel->priv->use_rdn &&
-                           g_str_has_suffix (userdn, imodel->priv->base_dn)) {
+                       if (data->imodel->priv->base_dn && *data->imodel->priv->base_dn &&
+                           data->imodel->priv->use_rdn &&
+                           g_str_has_suffix (userdn, data->imodel->priv->base_dn)) {
                                gint i;
-                               i = strlen (userdn) - strlen (imodel->priv->base_dn);
+                               i = strlen (userdn) - strlen (data->imodel->priv->base_dn);
                                if (i > 0) {
                                        userdn [i] = 0;
                                        for (i--; (i >= 0) && (userdn [i] != ','); i--);
@@ -750,34 +750,34 @@ update_iter_from_ldap_row (GdaDataModelLdap *imodel, GdaDataModelIter *iter)
        else
                gda_holder_force_invalid (holder);
 
-       nb = g_slist_length (((GdaSet*) iter)->holders);
+       nb = g_slist_length (((GdaSet*) data->iter)->holders);
        for (j = 1; j < nb; j++) {
-               holder = (GdaHolder*) (g_slist_nth_data (((GdaSet*) iter)->holders, j));
+               holder = (GdaHolder*) (g_slist_nth_data (((GdaSet*) data->iter)->holders, j));
                gda_holder_set_value (holder, NULL, NULL);
        }
 
-       if (imodel->priv->row_mult)
+       if (data->imodel->priv->row_mult)
                goto out;
 
-       for (attr = ldap_first_attribute (cdata->handle, imodel->priv->current_exec->ldap_row, &ber);
+       for (attr = ldap_first_attribute (data->cdata->handle, data->imodel->priv->current_exec->ldap_row, 
&ber);
             attr;
-            attr = ldap_next_attribute (cdata->handle, imodel->priv->current_exec->ldap_row, ber)) {
+            attr = ldap_next_attribute (data->cdata->handle, data->imodel->priv->current_exec->ldap_row, 
ber)) {
                BerValue **bvals;
                gboolean holder_added_to_cm = FALSE;
 
-               holder = gda_set_get_holder ((GdaSet*) iter, attr);
+               holder = gda_set_get_holder ((GdaSet*) data->iter, attr);
                if (!holder)
                        continue;
 
-               j = g_slist_index (((GdaSet*) iter)->holders, holder);
+               j = g_slist_index (((GdaSet*) data->iter)->holders, holder);
 
-               bvals = ldap_get_values_len (cdata->handle,
-                                            imodel->priv->current_exec->ldap_row, attr);
+               bvals = ldap_get_values_len (data->cdata->handle,
+                                            data->imodel->priv->current_exec->ldap_row, attr);
                if (bvals) {
                        if (bvals[0] && bvals[1]) {
                                /* multiple values */
                                MultipleValueAction act;
-                               act = g_array_index (imodel->priv->column_mv_actions,
+                               act = g_array_index (data->imodel->priv->column_mv_actions,
                                                     MultipleValueAction, j-1);
                                switch (act) {
                                case MULTIPLE_VALUE_ACTION_SET_NULL:
@@ -808,8 +808,8 @@ update_iter_from_ldap_row (GdaDataModelLdap *imodel, GdaDataModelIter *iter)
                                        break;
                                case MULTIPLE_VALUE_ACTION_MULTIPLY: {
                                        ColumnMultiplier *cm;
-                                       if (! imodel->priv->row_mult) {
-                                               imodel->priv->row_mult = row_multiplier_new ();
+                                       if (! data->imodel->priv->row_mult) {
+                                               data->imodel->priv->row_mult = row_multiplier_new ();
                                                /* create @cm for the previous columns */
                                                GSList *list;
                                                for (list = holders_set; list; list = list->next) {
@@ -817,7 +817,7 @@ update_iter_from_ldap_row (GdaDataModelLdap *imodel, GdaDataModelIter *iter)
                                                        ch = (GdaHolder*) list->data;
                                                        cm = column_multiplier_new (ch,
                                                                       gda_holder_get_value (ch));
-                                                       g_array_append_val (imodel->priv->row_mult->cms, cm);
+                                                       g_array_append_val 
(data->imodel->priv->row_mult->cms, cm);
                                                }
                                        }
                                        /* add new @cm */
@@ -825,12 +825,12 @@ update_iter_from_ldap_row (GdaDataModelLdap *imodel, GdaDataModelIter *iter)
                                        gint i;
                                        for (i = 0; bvals[i]; i++) {
                                                GValue *value;
-                                               value = gda_ldap_attr_value_to_g_value (cdata,
+                                               value = gda_ldap_attr_value_to_g_value (data->cdata,
                                                                                        gda_holder_get_g_type 
(holder),
                                                                                        bvals[i]);
                                                g_array_append_val (cm->values, value); /* value can be %NULL 
*/
                                        }
-                                       g_array_append_val (imodel->priv->row_mult->cms, cm);
+                                       g_array_append_val (data->imodel->priv->row_mult->cms, cm);
                                        holder_added_to_cm = TRUE;
                                        break;
                                }
@@ -873,7 +873,7 @@ update_iter_from_ldap_row (GdaDataModelLdap *imodel, GdaDataModelIter *iter)
                        else if (bvals[0]) {
                                /* convert string to the correct type */
                                GValue *value;
-                               value = gda_ldap_attr_value_to_g_value (cdata, gda_holder_get_g_type (holder),
+                               value = gda_ldap_attr_value_to_g_value (data->cdata, gda_holder_get_g_type 
(holder),
                                                                        bvals[0]);
                                if (value)
                                        gda_holder_take_value (holder, value, NULL);
@@ -888,10 +888,10 @@ update_iter_from_ldap_row (GdaDataModelLdap *imodel, GdaDataModelIter *iter)
                        gda_holder_set_value (holder, NULL, NULL);
                ldap_memfree (attr);
                holders_set = g_slist_prepend (holders_set, holder);
-               if (imodel->priv->row_mult && !holder_added_to_cm) {
+               if (data->imodel->priv->row_mult && !holder_added_to_cm) {
                        ColumnMultiplier *cm;
                        cm = column_multiplier_new (holder, gda_holder_get_value (holder));
-                       g_array_append_val (imodel->priv->row_mult->cms, cm);
+                       g_array_append_val (data->imodel->priv->row_mult->cms, cm);
                }
        }
        if (holders_set)
@@ -901,26 +901,76 @@ update_iter_from_ldap_row (GdaDataModelLdap *imodel, GdaDataModelIter *iter)
                ber_free (ber, 0);
 
  out:
-       if (imodel->priv->row_mult)
-               row_multiplier_set_holders (imodel->priv->row_mult);
+       if (data->imodel->priv->row_mult)
+               row_multiplier_set_holders (data->imodel->priv->row_mult);
 
-       if (gda_data_model_iter_is_valid (iter)) {
-               imodel->priv->iter_row ++;
-               if ((imodel->priv->iter_row == imodel->priv->n_rows - 1) && imodel->priv->truncated) {
+       if (gda_data_model_iter_is_valid (data->iter)) {
+               data->imodel->priv->iter_row ++;
+               if ((data->imodel->priv->iter_row == data->imodel->priv->n_rows - 1) && 
data->imodel->priv->truncated) {
                        GError *e = NULL;
                        g_set_error (&e, GDA_DATA_MODEL_ERROR,
                                     GDA_DATA_MODEL_TRUNCATED_ERROR,
                                     "%s", _("Truncated result because LDAP server limit encountered"));
-                       add_exception (imodel, e);
+                       add_exception (data->imodel, e);
                }
        }
        else
-               imodel->priv->iter_row = 0;
+               data->imodel->priv->iter_row = 0;
 
-       g_object_set (G_OBJECT (iter), "current-row", imodel->priv->iter_row,
+       g_object_set (G_OBJECT (data->iter), "current-row", data->imodel->priv->iter_row,
                      "update-model", update_model, NULL);
 }
 
+static void
+update_iter_from_ldap_row (GdaDataModelLdap *imodel, GdaDataModelIter *iter)
+{
+       g_return_if_fail (imodel);
+       g_return_if_fail (iter);
+       g_return_if_fail (imodel->priv->cnc);
+
+       GdaConnection *cnc;
+       cnc = imodel->priv->cnc;
+       gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+       LdapConnectionData *cdata;
+       cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (cnc));
+        if (!cdata) {
+               gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+               g_warning ("cdata != NULL failed");
+               return;
+       }
+
+       /* LDAP connection must have been kept opened */
+       g_assert (cdata->handle);
+
+       GdaServerProviderConnectionData *pcdata;
+       pcdata = gda_connection_internal_get_provider_data_error ((GdaConnection*) cnc, NULL);
+
+       GdaWorker *worker;
+       worker = gda_worker_ref (gda_connection_internal_get_worker (pcdata));
+
+       GMainContext *context;
+       context = gda_server_provider_get_real_main_context ((GdaConnection *) cnc);
+
+       WorkerIterData data;
+       data.cnc = (GdaLdapConnection*) cnc;
+       data.cdata = cdata;
+       data.imodel = imodel;
+       data.iter = iter;
+
+       gda_connection_set_status ((GdaConnection*) cnc, GDA_CONNECTION_STATUS_BUSY);
+       gpointer retval;
+       gda_worker_do_job (worker, context, 0, &retval, NULL,
+                          (GdaWorkerFunc) worker_update_iter_from_ldap_row, (gpointer) &data, NULL, NULL, 
NULL);
+       if (context)
+               g_main_context_unref (context);
+
+       gda_connection_set_status ((GdaConnection*) cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+       gda_worker_unref (worker);
+}
+
 /*
  * Add an exception to @model
  * WARNING: steals @e
@@ -933,36 +983,28 @@ add_exception (GdaDataModelLdap *model, GError *e)
        g_array_append_val (model->priv->exceptions, e);
 }
 
-/*
- * Execute model->priv->current_exec and either:
- *     - sets model->priv->current_exec->ldap_msg, or
- *     - create some children and execute one, or
- *     - sets model->priv->current_exec->ldap_msg to %NULL if an error occurred
- *
- * In any case model->priv->current_exec->executed is set to %TRUE and should be %FALSE when entering
- * the function (ie. for any LdapConnectionData this function has to be called at most once)
- */
-static void
-execute_ldap_search (GdaDataModelLdap *model)
+typedef struct {
+       GdaLdapConnection *cnc;
+       LdapConnectionData *cdata;
+       GdaDataModelLdap *model;
+} WorkerSearchData;
+
+static gpointer
+worker_execute_ldap_search (WorkerSearchData *data, GError **error)
 {
        LDAPMessage *msg = NULL;
        int lscope, res = 0;
-       LdapConnectionData *cdata;
-
-       g_return_if_fail (model->priv->cnc);
-       cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (model->priv->cnc));
-       g_return_if_fail (cdata);
 
        GError *e = NULL;
-       if (! gda_ldap_ensure_bound (cdata, &e)) {
-               add_exception (model, e);
-               return;
+       if (! gda_ldap_ensure_bound (data->cnc, &e)) {
+               add_exception (data->model, e);
+               return NULL;
        }
 
-       g_assert (model->priv->current_exec);
-       g_assert (! model->priv->current_exec->executed);
+       g_assert (data->model->priv->current_exec);
+       g_assert (! data->model->priv->current_exec->executed);
 
-       switch (model->priv->current_exec->scope) {
+       switch (data->model->priv->current_exec->scope) {
        default:
        case GDA_LDAP_SEARCH_BASE:
                lscope = LDAP_SCOPE_BASE;
@@ -976,9 +1018,9 @@ execute_ldap_search (GdaDataModelLdap *model)
        }
        
 #ifdef GDA_DEBUG_SUBSEARCHES
-       if (model->priv->scope == GDA_LDAP_SEARCH_SUBTREE) {
-               g_print ("Model %p model->priv->top_exec:\n", model);
-               ldap_part_dump (model->priv->top_exec);
+       if (data->model->priv->scope == GDA_LDAP_SEARCH_SUBTREE) {
+               g_print ("Model %p model->priv->top_exec:\n", data->model);
+               ldap_part_dump (data->model->priv->top_exec);
        }
 #endif
 
@@ -987,8 +1029,8 @@ execute_ldap_search (GdaDataModelLdap *model)
        static gint sims = 10;
  retry:
        if ((sims > 0) &&
-           (model->priv->scope == GDA_LDAP_SEARCH_SUBTREE) &&
-           (! model->priv->current_exec->parent || ! model->priv->current_exec->parent->parent)) {
+           (data->model->priv->scope == GDA_LDAP_SEARCH_SUBTREE) &&
+           (! data->model->priv->current_exec->parent || ! data->model->priv->current_exec->parent->parent)) 
{
                g_print ("Simulating LDAP_ADMINLIMIT_EXCEEDED\n");
                res = LDAP_ADMINLIMIT_EXCEEDED;
                sims --;
@@ -997,12 +1039,12 @@ execute_ldap_search (GdaDataModelLdap *model)
 #else
        retry:
 #endif
-       res = ldap_search_ext_s (cdata->handle, model->priv->current_exec->base_dn, lscope,
-                                model->priv->filter,
-                                (char**) model->priv->attributes->data, 0,
+       res = ldap_search_ext_s (data->cdata->handle, data->model->priv->current_exec->base_dn, lscope,
+                                data->model->priv->filter,
+                                (char**) data->model->priv->attributes->data, 0,
                                 NULL, NULL, NULL, -1,
                                 &msg);
-       model->priv->current_exec->executed = TRUE;
+       data->model->priv->current_exec->executed = TRUE;
 
 #define GDA_DEBUG_FORCE_ERROR
 #undef GDA_DEBUG_FORCE_ERROR
@@ -1011,25 +1053,25 @@ execute_ldap_search (GdaDataModelLdap *model)
        GError *e = NULL;
        int ldap_errno;
        g_print ("SIMULATING error\n");
-       ldap_get_option (cdata->handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
+       ldap_get_option (data->cdata->handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
        g_set_error (&e, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_OTHER_ERROR,
                     "%s", "Simulated error");
-       add_exception (model, e);
-       return;
+       add_exception (data->model, e);
+       return NULL;
 #else
        switch (res) {
        case LDAP_SUCCESS:
        case LDAP_NO_SUCH_OBJECT:
                /* all Ok */
-               model->priv->current_exec->ldap_msg = msg;
-               model->priv->current_exec->nb_entries = ldap_count_entries (cdata->handle, msg);
+               data->model->priv->current_exec->ldap_msg = msg;
+               data->model->priv->current_exec->nb_entries = ldap_count_entries (data->cdata->handle, msg);
 
                /* keep the connection opened for this LdapPart */
-               cdata->keep_bound_count ++;
+               data->cdata->keep_bound_count ++;
 
 #ifdef GDA_DEBUG_SUBSEARCHES
                g_print ("model->priv->current_exec->nb_entries = %d\n",
-                        model->priv->current_exec->nb_entries);
+                        data->model->priv->current_exec->nb_entries);
 #endif
                break;
        case LDAP_ADMINLIMIT_EXCEEDED:
@@ -1039,23 +1081,23 @@ execute_ldap_search (GdaDataModelLdap *model)
                g_print ("LIMIT_EXCEEDED!\n");
 #endif
                gboolean handled = FALSE;
-               if ((cdata->time_limit == 0) && (cdata->size_limit == 0) &&
-                   (model->priv->scope == GDA_LDAP_SEARCH_SUBTREE)) {
+               if ((data->cdata->time_limit == 0) && (data->cdata->size_limit == 0) &&
+                   (data->model->priv->scope == GDA_LDAP_SEARCH_SUBTREE)) {
                        gboolean split_error;
-                       if (ldap_part_split (model->priv->current_exec, model, &split_error)) {
+                       if (ldap_part_split (data->model->priv->current_exec, data->model, &split_error)) {
                                /* create some children to re-run the search */
                                if (msg)
                                        ldap_msgfree (msg);
-                               model->priv->current_exec = LDAP_PART 
(model->priv->current_exec->children->data);
-                               execute_ldap_search (model);
+                               data->model->priv->current_exec = LDAP_PART 
(data->model->priv->current_exec->children->data);
+                               worker_execute_ldap_search (data, NULL);
                                handled = TRUE;
                        }
                        else if (!split_error) {
                                LdapPart *next;
-                               next = ldap_part_next (model->priv->current_exec, FALSE);
+                               next = ldap_part_next (data->model->priv->current_exec, FALSE);
                                if (next) {
-                                       model->priv->current_exec = next;
-                                       execute_ldap_search (model);
+                                       data->model->priv->current_exec = next;
+                                       worker_execute_ldap_search (data, NULL);
                                        handled = TRUE;
                                }
                        }
@@ -1065,19 +1107,19 @@ execute_ldap_search (GdaDataModelLdap *model)
 #ifdef GDA_DEBUG_SUBSEARCHES
                        g_print ("Output truncated!\n");
 #endif
-                       model->priv->truncated = TRUE;
-                       model->priv->current_exec->ldap_msg = msg;
-                       model->priv->current_exec->nb_entries = ldap_count_entries (cdata->handle, msg);
+                       data->model->priv->truncated = TRUE;
+                       data->model->priv->current_exec->ldap_msg = msg;
+                       data->model->priv->current_exec->nb_entries = ldap_count_entries 
(data->cdata->handle, msg);
 
                        /* keep the connection opened for this LdapPart */
-                       cdata->keep_bound_count ++;
+                       data->cdata->keep_bound_count ++;
                }
                break;
        }
        case LDAP_SERVER_DOWN: {
                gint i;
                for (i = 0; i < 5; i++) {
-                       if (gda_ldap_rebind (cdata, NULL))
+                       if (gda_ldap_rebind (data->cnc, NULL))
                                goto retry;
                        g_usleep (G_USEC_PER_SEC * 2);
                }
@@ -1086,139 +1128,237 @@ execute_ldap_search (GdaDataModelLdap *model)
                /* error */
                GError *e = NULL;
                int ldap_errno;
-               ldap_get_option (cdata->handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
+               ldap_get_option (data->cdata->handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
                g_set_error (&e, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_OTHER_ERROR,
                             "%s", ldap_err2string (ldap_errno));
-               add_exception (model, e);
-               gda_ldap_may_unbind (cdata);
-               return;
+               add_exception (data->model, e);
+               gda_ldap_may_unbind (data->cnc);
+               return NULL;
        }
        }
 #endif /*GDA_DEBUG_FORCE_ERROR*/
 
-       if (model->priv->truncated) {
+       if (data->model->priv->truncated) {
                /* compute totel number of rows now that we know it */
-               if (model->priv->top_exec->ldap_msg)
-                       model->priv->n_rows = model->priv->current_exec->nb_entries;
+               if (data->model->priv->top_exec->ldap_msg)
+                       data->model->priv->n_rows = data->model->priv->current_exec->nb_entries;
                else {
                        LdapPart *iter;
-                       model->priv->n_rows = 0;
-                       for (iter = model->priv->top_exec; iter; iter = ldap_part_next (iter, TRUE))
-                               model->priv->n_rows += iter->nb_entries;
+                       data->model->priv->n_rows = 0;
+                       for (iter = data->model->priv->top_exec; iter; iter = ldap_part_next (iter, TRUE))
+                               data->model->priv->n_rows += iter->nb_entries;
                }
        }
 
 #ifdef GDA_DEBUG_NO
        gint tmpnb = 0;
-       if (model->priv->top_exec->ldap_msg)
-               tmpnb = model->priv->current_exec->nb_entries;
+       if (data->model->priv->top_exec->ldap_msg)
+               tmpnb = data->model->priv->current_exec->nb_entries;
        else {
                LdapPart *iter;
-               for (iter = model->priv->top_exec; iter; iter = ldap_part_next (iter, TRUE))
+               for (iter = data->model->priv->top_exec; iter; iter = ldap_part_next (iter, TRUE))
                        tmpnb += iter->nb_entries;
        }
        g_print ("So far found %d\n", tmpnb);
 #endif
+
+       return NULL;
 }
 
-static gboolean
-gda_data_model_ldap_iter_next (GdaDataModel *model, GdaDataModelIter *iter)
+/*
+ * Execute model->priv->current_exec and either:
+ *     - sets model->priv->current_exec->ldap_msg, or
+ *     - create some children and execute one, or
+ *     - sets model->priv->current_exec->ldap_msg to %NULL if an error occurred
+ *
+ * In any case model->priv->current_exec->executed is set to %TRUE and should be %FALSE when entering
+ * the function (ie. for any LdapConnectionData this function has to be called at most once)
+ */
+static void
+execute_ldap_search (GdaDataModelLdap *model)
 {
-       GdaDataModelLdap *imodel;
-       LdapConnectionData *cdata;
-       LdapPart *cpart;
+       g_return_if_fail (model);
+       g_return_if_fail (model->priv->cnc);
 
-        g_return_val_if_fail (GDA_IS_DATA_MODEL_LDAP (model), FALSE);
-        g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), FALSE);
-        imodel = GDA_DATA_MODEL_LDAP (model);
-        g_return_val_if_fail (imodel->priv, FALSE);
+       GdaConnection *cnc;
+       cnc = model->priv->cnc;
+       gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
 
-       if (! imodel->priv->cnc) {
-               /* error */
-               gda_data_model_iter_invalidate_contents (iter);
-               return FALSE;
+       LdapConnectionData *cdata;
+       cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (cnc));
+        if (!cdata) {
+               gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+               g_warning ("cdata != NULL failed");
+               return;
        }
 
-       cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (imodel->priv->cnc));
-       if (!cdata || ! gda_ldap_ensure_bound (cdata, NULL)) {
-               /* error */
-               gda_data_model_iter_invalidate_contents (iter);
-               return FALSE;
-       }
+       GdaServerProviderConnectionData *pcdata;
+       pcdata = gda_connection_internal_get_provider_data_error ((GdaConnection*) cnc, NULL);
+
+       GdaWorker *worker;
+       worker = gda_worker_ref (gda_connection_internal_get_worker (pcdata));
+
+       GMainContext *context;
+       context = gda_server_provider_get_real_main_context ((GdaConnection *) cnc);
+
+       WorkerSearchData data;
+       data.cnc = GDA_LDAP_CONNECTION (cnc);
+       data.cdata = cdata;
+       data.model = model;
+
+       gda_connection_set_status ((GdaConnection*) cnc, GDA_CONNECTION_STATUS_BUSY);
+       gpointer retval;
+       gda_worker_do_job (worker, context, 0, &retval, NULL,
+                          (GdaWorkerFunc) worker_execute_ldap_search, (gpointer) &data, NULL, NULL, NULL);
+       if (context)
+               g_main_context_unref (context);
+
+       gda_connection_set_status ((GdaConnection*) cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+       gda_worker_unref (worker);
+}
+
+
+static gpointer
+worker_gda_data_model_ldap_iter_next (WorkerIterData *data, GError **error)
+{
+       LdapPart *cpart;
 
        /* initialize LDAP search if necessary */
-       if (! imodel->priv->base_dn)
-               imodel->priv->base_dn = g_strdup (cdata->base_dn);
-       if (! imodel->priv->attributes)
-               imodel->priv->attributes = g_array_new (TRUE, FALSE, sizeof (gchar*));
-       if (! imodel->priv->top_exec) {
-               imodel->priv->top_exec = ldap_part_new (NULL, imodel->priv->base_dn, imodel->priv->scope);
-               imodel->priv->current_exec = imodel->priv->top_exec;
+       if (! data->imodel->priv->base_dn)
+               data->imodel->priv->base_dn = g_strdup (data->cdata->base_dn);
+       if (! data->imodel->priv->attributes)
+               data->imodel->priv->attributes = g_array_new (TRUE, FALSE, sizeof (gchar*));
+       if (! data->imodel->priv->top_exec) {
+               data->imodel->priv->top_exec = ldap_part_new (NULL, data->imodel->priv->base_dn, 
data->imodel->priv->scope);
+               data->imodel->priv->current_exec = data->imodel->priv->top_exec;
        }
 
-       while (imodel->priv->current_exec) {
-               cpart = imodel->priv->current_exec;
+       while (data->imodel->priv->current_exec) {
+               cpart = data->imodel->priv->current_exec;
                if (! cpart->executed)
-                       execute_ldap_search (imodel);
-               cpart = imodel->priv->current_exec;
+                       execute_ldap_search (data->imodel);
+               cpart = data->imodel->priv->current_exec;
                if (! cpart->ldap_msg) {
                        /* error somewhere */
-                       gda_data_model_iter_invalidate_contents (iter);
-                       gda_ldap_may_unbind (cdata);
-                       return FALSE;
+                       gda_data_model_iter_invalidate_contents (data->iter);
+                       gda_ldap_may_unbind (data->cnc);
+
+                       return NULL;
                }
 
                if (! cpart->ldap_row)
                        /* not yet on 1st row */
-                       cpart->ldap_row = ldap_first_entry (cdata->handle, cpart->ldap_msg);
+                       cpart->ldap_row = ldap_first_entry (data->cdata->handle, cpart->ldap_msg);
                else {
-                       if (imodel->priv->row_mult) {
-                               if (! row_multiplier_index_next (imodel->priv->row_mult)) {
-                                       row_multiplier_free (imodel->priv->row_mult);
-                                       imodel->priv->row_mult = NULL;
+                       if (data->imodel->priv->row_mult) {
+                               if (! row_multiplier_index_next (data->imodel->priv->row_mult)) {
+                                       row_multiplier_free (data->imodel->priv->row_mult);
+                                       data->imodel->priv->row_mult = NULL;
                                }
                        }
-                       if (! imodel->priv->row_mult) {
+                       if (! data->imodel->priv->row_mult) {
                                /* move to the next row */
-                               cpart->ldap_row = ldap_next_entry (cdata->handle, cpart->ldap_row);
+                               cpart->ldap_row = ldap_next_entry (data->cdata->handle, cpart->ldap_row);
                        }
                }
                
                if (cpart->ldap_row) {
-                       update_iter_from_ldap_row (imodel, iter);
+                       update_iter_from_ldap_row (data->imodel, data->iter);
                        break;
                }
                else {
                        /* nothing more for this part, switch to the next one */
-                       ldap_msgfree (imodel->priv->current_exec->ldap_msg);
-                       imodel->priv->current_exec->ldap_msg = NULL;
+                       ldap_msgfree (data->imodel->priv->current_exec->ldap_msg);
+                       data->imodel->priv->current_exec->ldap_msg = NULL;
 
-                       g_assert (cdata->keep_bound_count > 0);
-                       cdata->keep_bound_count --;
-                       gda_ldap_may_unbind (cdata);
+                       g_assert (data->cdata->keep_bound_count > 0);
+                       data->cdata->keep_bound_count --;
+                       gda_ldap_may_unbind (data->cnc);
 
-                       imodel->priv->current_exec = ldap_part_next (cpart, FALSE);
+                       data->imodel->priv->current_exec = ldap_part_next (cpart, FALSE);
                }
        }
 
-       if (!imodel->priv->current_exec) {
+       if (!data->imodel->priv->current_exec) {
                /* execution is over */
-               gda_data_model_iter_invalidate_contents (iter);
-                g_object_set (G_OBJECT (iter), "current-row", -1, NULL);
-               if (imodel->priv->truncated) {
+               gda_data_model_iter_invalidate_contents (data->iter);
+                g_object_set (G_OBJECT (data->iter), "current-row", -1, NULL);
+               if (data->imodel->priv->truncated) {
                        GError *e = NULL;
                        g_set_error (&e, GDA_DATA_MODEL_ERROR,
                                     GDA_DATA_MODEL_TRUNCATED_ERROR,
                                     "%s", _("Truncated result because LDAP server limit encountered"));
-                       add_exception (imodel, e);
+                       add_exception (data->imodel, e);
                }
-               g_signal_emit_by_name (iter, "end-of-data");
-               gda_ldap_may_unbind (cdata);
-                return FALSE;
+               g_signal_emit_by_name (data->iter, "end-of-data");
+               gda_ldap_may_unbind (data->cnc);
+
+                return NULL;
+       }
+
+       gda_ldap_may_unbind (data->cnc);
+       return (gpointer) 0x01;
+}
+
+static gboolean
+gda_data_model_ldap_iter_next (GdaDataModel *model, GdaDataModelIter *iter)
+{
+        g_return_val_if_fail (GDA_IS_DATA_MODEL_LDAP (model), FALSE);
+       g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), FALSE);
+       GdaDataModelLdap *imodel = (GdaDataModelLdap*) model;
+        g_return_val_if_fail (imodel->priv, FALSE);
+
+       if (! imodel->priv->cnc) {
+               /* error */
+               gda_data_model_iter_invalidate_contents (iter);
+               return FALSE;
+       }
+
+       GdaConnection *cnc;
+       cnc = imodel->priv->cnc;
+       gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+       LdapConnectionData *cdata;
+       cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (cnc));
+       if (!cdata || ! gda_ldap_ensure_bound ((GdaLdapConnection*) cnc, NULL)) {
+               /* error */
+               if (!cdata)
+                       g_warning ("cdata != NULL failed");                     
+               gda_data_model_iter_invalidate_contents (iter);
+               gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+               return FALSE;
        }
 
-       gda_ldap_may_unbind (cdata);
-       return TRUE;
+       GdaServerProviderConnectionData *pcdata;
+       pcdata = gda_connection_internal_get_provider_data_error ((GdaConnection*) cnc, NULL);
+
+       GdaWorker *worker;
+       worker = gda_worker_ref (gda_connection_internal_get_worker (pcdata));
+
+       GMainContext *context;
+       context = gda_server_provider_get_real_main_context ((GdaConnection *) cnc);
+
+       WorkerIterData data;
+       data.cnc = (GdaLdapConnection*) cnc;
+       data.cdata = cdata;
+       data.imodel = imodel;
+       data.iter = iter;
+
+       gda_connection_set_status ((GdaConnection*) cnc, GDA_CONNECTION_STATUS_BUSY);
+       gpointer retval;
+       gda_worker_do_job (worker, context, 0, &retval, NULL,
+                          (GdaWorkerFunc) worker_gda_data_model_ldap_iter_next, (gpointer) &data, NULL, 
NULL, NULL);
+       if (context)
+               g_main_context_unref (context);
+
+       gda_connection_set_status ((GdaConnection*) cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+       gda_worker_unref (worker);
+
+       return retval ? TRUE : FALSE;
 }
 
 static GdaValueAttribute
@@ -1280,25 +1420,74 @@ ldap_part_new (LdapPart *parent, const gchar *base_dn, GdaLdapSearchScope scope)
        return part;
 }
 
-static void
-ldap_part_free (LdapPart *part, LdapConnectionData *cdata)
+typedef struct {
+       GdaLdapConnection *cnc;
+       LdapConnectionData *cdata;
+       LdapPart *part;
+} WorkerLdapPartData;
+
+static gpointer
+worker_ldap_part_free (WorkerLdapPartData *data, GError **error)
 {
-       g_assert (part);
-       g_free (part->base_dn);
-       if (part->children) {
-               g_slist_foreach (part->children, (GFunc) ldap_part_free, cdata);
-               g_slist_free (part->children);
+       g_free (data->part->base_dn);
+       if (data->part->children) {
+               g_slist_foreach (data->part->children, (GFunc) ldap_part_free, data->cnc);
+               g_slist_free (data->part->children);
        }
-       if (part->ldap_msg) {
-               ldap_msgfree (part->ldap_msg);
+       if (data->part->ldap_msg) {
+               ldap_msgfree (data->part->ldap_msg);
 
                /* Release the connection being opened for this LdapPart */
-               g_assert (cdata);
-               g_assert (cdata->keep_bound_count > 0);
-               cdata->keep_bound_count --;
-               gda_ldap_may_unbind (cdata);
+               g_assert (data->cdata);
+               g_assert (data->cdata->keep_bound_count > 0);
+               data->cdata->keep_bound_count --;
+               gda_ldap_may_unbind (data->cnc);
+       }
+       g_free (data->part);
+       return NULL;
+}
+
+static void
+ldap_part_free (LdapPart *part, GdaLdapConnection *cnc)
+{
+       g_return_if_fail (part);
+       g_return_if_fail (cnc);
+
+       gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+       LdapConnectionData *cdata;
+       cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (cnc));
+        if (!cdata) {
+               gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+               g_warning ("cdata != NULL failed");
+               return;
        }
-       g_free (part);
+
+       GdaServerProviderConnectionData *pcdata;
+       pcdata = gda_connection_internal_get_provider_data_error ((GdaConnection*) cnc, NULL);
+
+       GdaWorker *worker;
+       worker = gda_worker_ref (gda_connection_internal_get_worker (pcdata));
+
+       GMainContext *context;
+       context = gda_server_provider_get_real_main_context ((GdaConnection *) cnc);
+
+       WorkerLdapPartData data;
+       data.cnc = cnc;
+       data.cdata = cdata;
+       data.part = part;
+
+       gda_connection_set_status ((GdaConnection*) cnc, GDA_CONNECTION_STATUS_BUSY);
+       gpointer retval;
+       gda_worker_do_job (worker, context, 0, &retval, NULL,
+                          (GdaWorkerFunc) worker_ldap_part_free, (gpointer) &data, NULL, NULL, NULL);
+       if (context)
+               g_main_context_unref (context);
+
+       gda_connection_set_status ((GdaConnection*) cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+       gda_worker_unref (worker);
 }
 
 /*
@@ -1391,9 +1580,7 @@ ldap_part_split (LdapPart *part, GdaDataModelLdap *model, gboolean *out_error)
                }
                if (!sub) {
                        /* error */
-                       LdapConnectionData *cdata;
-                       cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (model->priv->cnc));
-                       g_slist_foreach (part->children, (GFunc) ldap_part_free, cdata);
+                       g_slist_foreach (part->children, (GFunc) ldap_part_free, model->priv->cnc);
                        g_slist_free (part->children);
                        part->children = NULL;
                        break;
@@ -1562,7 +1749,7 @@ row_multiplier_index_next (RowMultiplier *rm)
 }
 
 /*
- * Writing support
+ * Writing data
  */
 
 typedef struct {
@@ -1571,108 +1758,54 @@ typedef struct {
 } FHData;
 static void removed_attrs_func (const gchar *attr_name, GdaLdapAttribute *attr, FHData *data);
 
-gboolean
-gdaprov_ldap_modify (GdaLdapConnection *cnc, GdaLdapModificationType modtype,
-                    GdaLdapEntry *entry, GdaLdapEntry *ref_entry, GError **error)
-{
+typedef struct {
+       GdaLdapConnection *cnc;
        LdapConnectionData *cdata;
-       int res;
-
-       g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), FALSE);
-       g_return_val_if_fail (entry, FALSE);
-       if (entry)
-               g_return_val_if_fail (gdaprov_ldap_is_dn (entry->dn), FALSE);
-       if (ref_entry)
-               g_return_val_if_fail (gdaprov_ldap_is_dn (ref_entry->dn), FALSE);
-
-       cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (cnc));
-       g_return_val_if_fail (cdata, FALSE);
-
-       if (! gda_ldap_ensure_bound (cdata, error))
-               return FALSE;
-
-       /* checks */
-       if ((modtype != GDA_LDAP_MODIFICATION_INSERT) &&
-           (modtype != GDA_LDAP_MODIFICATION_ATTR_ADD) &&
-           (modtype != GDA_LDAP_MODIFICATION_ATTR_DEL) &&
-           (modtype != GDA_LDAP_MODIFICATION_ATTR_REPL) &&
-           (modtype != GDA_LDAP_MODIFICATION_ATTR_DIFF)) {
-               g_warning (_("Unknown GdaLdapModificationType %d"), modtype);
-               gda_ldap_may_unbind (cdata);
-               return FALSE;
-       }
-
-       if (((modtype == GDA_LDAP_MODIFICATION_DELETE) || (modtype == GDA_LDAP_MODIFICATION_INSERT)) &&
-           !entry) {
-               g_warning ("%s", _("No GdaLdapEntry specified"));
-               gda_ldap_may_unbind (cdata);
-               return FALSE;
-       }
-
-       if ((modtype == GDA_LDAP_MODIFICATION_ATTR_ADD) && !entry) {
-               g_warning ("%s", _("No GdaLdapEntry specified to define attributes to add"));
-               gda_ldap_may_unbind (cdata);
-               return FALSE;
-       }
-
-       if ((modtype == GDA_LDAP_MODIFICATION_ATTR_DEL) && !entry) {
-               g_warning ("%s", _("No GdaLdapEntry specified to define attributes to remove"));
-               gda_ldap_may_unbind (cdata);
-               return FALSE;
-       }
+       GdaLdapModificationType modtype;
+       GdaLdapEntry *entry;
+       GdaLdapEntry *ref_entry;
+} WorkerLdapModData;
 
-       if ((modtype == GDA_LDAP_MODIFICATION_ATTR_REPL) && !entry) {
-               g_warning ("%s", _("No GdaLdapEntry specified to define attributes to replace"));
-               gda_ldap_may_unbind (cdata);
-               return FALSE;
-       }
-
-       if ((modtype == GDA_LDAP_MODIFICATION_ATTR_DIFF) && (!entry || !ref_entry)) {
-               g_warning ("%s", _("No GdaLdapEntry specified to compare attributes"));
-               gda_ldap_may_unbind (cdata);
-               return FALSE;
-       }
-       if ((modtype == GDA_LDAP_MODIFICATION_ATTR_DIFF) && strcmp (entry->dn, ref_entry->dn)) {
-               g_warning ("%s", _("GdaLdapEntry specified to compare have different DN"));
-               gda_ldap_may_unbind (cdata);
-               return FALSE;
-       }
+gpointer
+worker_gdaprov_ldap_modify (WorkerLdapModData *data, GError **error)
+{
+       int res;
 
        /* handle DELETE operation */
-       if (modtype == GDA_LDAP_MODIFICATION_DELETE) {
-               res = ldap_delete_ext_s (cdata->handle, entry->dn, NULL, NULL);
+       if (data->modtype == GDA_LDAP_MODIFICATION_DELETE) {
+               res = ldap_delete_ext_s (data->cdata->handle, data->entry->dn, NULL, NULL);
                if (res != LDAP_SUCCESS) {
                        g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_OTHER_ERROR,
                                     "%s", ldap_err2string (res));
-                       gda_ldap_may_unbind (cdata);
-                       return FALSE;
+                       gda_ldap_may_unbind (data->cnc);
+                       return NULL;
                }
                else {
-                       gda_ldap_may_unbind (cdata);
-                       return TRUE;
+                       gda_ldap_may_unbind (data->cnc);
+                       return (gpointer) 0x01;
                }
        }
 
        /* build array of modifications to perform */
        GArray *mods_array;
        mods_array = g_array_new (TRUE, FALSE, sizeof (LDAPMod*));
-       if (modtype == GDA_LDAP_MODIFICATION_ATTR_DIFF) {
+       if (data->modtype == GDA_LDAP_MODIFICATION_ATTR_DIFF) {
                /* index ref_entry's attributes */
                GHashTable *hash;
                guint i;
                hash = g_hash_table_new (g_str_hash, g_str_equal);
-               for (i = 0; i < ref_entry->nb_attributes; i++) {
+               for (i = 0; i < data->ref_entry->nb_attributes; i++) {
                        GdaLdapAttribute *attr;
-                       attr = ref_entry->attributes [i];
+                       attr = data->ref_entry->attributes [i];
                        g_hash_table_insert (hash, attr->attr_name, attr);
                }
                
-               for (i = 0; i < entry->nb_attributes; i++) {
+               for (i = 0; i < data->entry->nb_attributes; i++) {
                        LDAPMod *mod;
                        GdaLdapAttribute *attr, *ref_attr;
                        guint j;
 
-                       attr = entry->attributes [i];
+                       attr = data->entry->attributes [i];
                        ref_attr = g_hash_table_lookup (hash, attr->attr_name);
 
                        mod = g_new0 (LDAPMod, 1);
@@ -1686,37 +1819,37 @@ gdaprov_ldap_modify (GdaLdapConnection *cnc, GdaLdapModificationType modtype,
 
                        mod->mod_bvalues = g_new0 (struct berval *, attr->nb_values + 1); /* last is NULL */
                        for (j = 0; j < attr->nb_values; j++)
-                               mod->mod_bvalues[j] = gda_ldap_attr_g_value_to_value (cdata, attr->values 
[j]);
+                               mod->mod_bvalues[j] = gda_ldap_attr_g_value_to_value (data->cdata, 
attr->values [j]);
                        g_array_append_val (mods_array, mod);
                }
 
                FHData fhdata;
-               fhdata.cdata = cdata;
+               fhdata.cdata = data->cdata;
                fhdata.mods_array = mods_array;
                g_hash_table_foreach (hash, (GHFunc) removed_attrs_func, &fhdata);
                g_hash_table_destroy (hash);
        }
        else {
                guint i;
-               for (i = 0; i < entry->nb_attributes; i++) {
+               for (i = 0; i < data->entry->nb_attributes; i++) {
                        LDAPMod *mod;
                        GdaLdapAttribute *attr;
                        guint j;
 
-                       attr = entry->attributes [i];
+                       attr = data->entry->attributes [i];
                        mod = g_new0 (LDAPMod, 1);
                        mod->mod_op = LDAP_MOD_BVALUES;
-                       if ((modtype == GDA_LDAP_MODIFICATION_INSERT) ||
-                           (modtype == GDA_LDAP_MODIFICATION_ATTR_ADD))
+                       if ((data->modtype == GDA_LDAP_MODIFICATION_INSERT) ||
+                           (data->modtype == GDA_LDAP_MODIFICATION_ATTR_ADD))
                                mod->mod_op |= LDAP_MOD_ADD;
-                       else if (modtype == GDA_LDAP_MODIFICATION_ATTR_DEL)
+                       else if (data->modtype == GDA_LDAP_MODIFICATION_ATTR_DEL)
                                mod->mod_op |= LDAP_MOD_DELETE;
                        else
                                mod->mod_op |= LDAP_MOD_REPLACE;
                        mod->mod_type = attr->attr_name; /* no duplication */
                        mod->mod_bvalues = g_new0 (struct berval *, attr->nb_values + 1); /* last is NULL */
                        for (j = 0; j < attr->nb_values; j++)
-                               mod->mod_bvalues[j] = gda_ldap_attr_g_value_to_value (cdata, attr->values 
[j]);
+                               mod->mod_bvalues[j] = gda_ldap_attr_g_value_to_value (data->cdata, 
attr->values [j]);
                        g_array_append_val (mods_array, mod);
                }
        }
@@ -1724,10 +1857,10 @@ gdaprov_ldap_modify (GdaLdapConnection *cnc, GdaLdapModificationType modtype,
        gboolean retval = TRUE;
        if (mods_array->len > 0) {
                /* apply modifications */
-               if (modtype == GDA_LDAP_MODIFICATION_INSERT)
-                       res = ldap_add_ext_s (cdata->handle, entry->dn, (LDAPMod **) mods_array->data, NULL, 
NULL);
+               if (data->modtype == GDA_LDAP_MODIFICATION_INSERT)
+                       res = ldap_add_ext_s (data->cdata->handle, data->entry->dn, (LDAPMod **) 
mods_array->data, NULL, NULL);
                else
-                       res = ldap_modify_ext_s (cdata->handle, entry->dn, (LDAPMod **) mods_array->data, 
NULL, NULL);
+                       res = ldap_modify_ext_s (data->cdata->handle, data->entry->dn, (LDAPMod **) 
mods_array->data, NULL, NULL);
 
                if (res != LDAP_SUCCESS) {
                        g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_OTHER_ERROR,
@@ -1744,15 +1877,96 @@ gdaprov_ldap_modify (GdaLdapConnection *cnc, GdaLdapModificationType modtype,
                if (mod->mod_values) {
                        guint j;
                        for (j = 0; mod->mod_values [j]; j++)
-                               gda_ldap_attr_value_free (cdata, mod->mod_bvalues [j]);
+                               gda_ldap_attr_value_free (data->cdata, mod->mod_bvalues [j]);
                        g_free (mod->mod_values);
                }
                g_free (mod);
        }
        g_array_free (mods_array, TRUE);
 
-       gda_ldap_may_unbind (cdata);
-       return retval;
+       gda_ldap_may_unbind (data->cnc);
+       return retval ? (gpointer) 0x01 : NULL;
+}
+
+gboolean
+gdaprov_ldap_modify (GdaLdapConnection *cnc, GdaLdapModificationType modtype,
+                    GdaLdapEntry *entry, GdaLdapEntry *ref_entry, GError **error)
+{
+       /* checks */
+       if (! entry || ! entry->dn) {
+               g_warning ("%s", _("No GdaLdapEntry specified"));
+               return FALSE;
+       }
+       g_return_val_if_fail (gdaprov_ldap_is_dn (entry->dn), FALSE);
+       if (ref_entry)
+               g_return_val_if_fail (gdaprov_ldap_is_dn (ref_entry->dn), FALSE);
+
+       if ((modtype != GDA_LDAP_MODIFICATION_INSERT) &&
+           (modtype != GDA_LDAP_MODIFICATION_ATTR_ADD) &&
+           (modtype != GDA_LDAP_MODIFICATION_ATTR_DEL) &&
+           (modtype != GDA_LDAP_MODIFICATION_ATTR_REPL) &&
+           (modtype != GDA_LDAP_MODIFICATION_ATTR_DIFF)) {
+               g_warning (_("Unknown GdaLdapModificationType %d"), modtype);
+               return FALSE;
+       }
+
+       if (modtype == GDA_LDAP_MODIFICATION_ATTR_DIFF) {
+               if (!ref_entry) {
+                       g_warning ("%s", _("No GdaLdapEntry specified to compare attributes"));
+                       return FALSE;
+               }
+               if (strcmp (entry->dn, ref_entry->dn)) {
+                       g_warning ("%s", _("GdaLdapEntry specified to compare have different DN"));
+                       return FALSE;
+               }
+       }
+
+       g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), FALSE);
+
+       gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+       LdapConnectionData *cdata;
+       cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (cnc));
+        if (!cdata) {
+               gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+               g_warning ("cdata != NULL failed");
+               return FALSE;
+       }
+
+       if (! gda_ldap_ensure_bound (cnc, error)) {
+               gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+               return FALSE;
+       }
+
+               GdaServerProviderConnectionData *pcdata;
+       pcdata = gda_connection_internal_get_provider_data_error ((GdaConnection*) cnc, NULL);
+
+       GdaWorker *worker;
+       worker = gda_worker_ref (gda_connection_internal_get_worker (pcdata));
+
+       GMainContext *context;
+       context = gda_server_provider_get_real_main_context ((GdaConnection *) cnc);
+
+       WorkerLdapModData data;
+       data.cnc = cnc;
+       data.cdata = cdata;
+       data.modtype = modtype;
+       data.entry = entry;
+       data.ref_entry = ref_entry;
+
+       gda_connection_set_status ((GdaConnection*) cnc, GDA_CONNECTION_STATUS_BUSY);
+       gpointer retval;
+       gda_worker_do_job (worker, context, 0, &retval, NULL,
+                          (GdaWorkerFunc) worker_gdaprov_ldap_modify, (gpointer) &data, NULL, NULL, error);
+       if (context)
+               g_main_context_unref (context);
+
+       gda_connection_set_status ((GdaConnection*) cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+       gda_worker_unref (worker);
+
+       return retval ? TRUE : FALSE;
 }
 
 static void
@@ -1770,37 +1984,30 @@ removed_attrs_func (const gchar *attr_name, GdaLdapAttribute *attr, FHData *data
        g_array_append_val (data->mods_array, mod);
 }
 
-gboolean
-gdaprov_ldap_rename_entry (GdaLdapConnection *cnc, const gchar *current_dn, const gchar *new_dn,
-                          GError **error)
-{
-       g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), FALSE);
-       g_return_val_if_fail (current_dn && *current_dn, FALSE);
-       g_return_val_if_fail (gdaprov_ldap_is_dn (current_dn), FALSE);
-       g_return_val_if_fail (new_dn && *new_dn, FALSE);
-       g_return_val_if_fail (gdaprov_ldap_is_dn (new_dn), FALSE);
-
+typedef struct {
+       GdaLdapConnection *cnc;
        LdapConnectionData *cdata;
-       cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (cnc));
-       g_return_val_if_fail (cdata, FALSE);
-
-       if (! gda_ldap_ensure_bound (cdata, error))
-               return FALSE;
+       const gchar *current_dn;
+       const gchar *new_dn;
+} WorkerRenamEntryData;
 
+gpointer
+worker_gdaprov_ldap_rename_entry (WorkerRenamEntryData *data, GError **error)
+{
        gchar **carray, **narray;
        int res;
        gboolean retval = TRUE;
        gchar *parent = NULL;
 
-       carray = gda_ldap_dn_split (current_dn, FALSE);
-       narray = gda_ldap_dn_split (new_dn, FALSE);
+       carray = gda_ldap_dn_split (data->current_dn, FALSE);
+       narray = gda_ldap_dn_split (data->new_dn, FALSE);
 
        if (carray[1] && narray[1] && strcmp (carray[1], narray[1]))
                parent = narray [1];
        else if (! carray[1] && narray[1])
                parent = narray [1];
 
-       res = ldap_rename_s (cdata->handle, current_dn, narray[0], parent, 1, NULL, NULL);
+       res = ldap_rename_s (data->cdata->handle, data->current_dn, narray[0], parent, 1, NULL, NULL);
        g_strfreev (carray);
        g_strfreev (narray);
 
@@ -1810,6 +2017,59 @@ gdaprov_ldap_rename_entry (GdaLdapConnection *cnc, const gchar *current_dn, cons
                retval = FALSE;
        }
 
-       gda_ldap_may_unbind (cdata);
-       return retval;
+       gda_ldap_may_unbind (data->cnc);
+       return retval ? (gpointer) 0x01 : NULL;
+}
+
+gboolean
+gdaprov_ldap_rename_entry (GdaLdapConnection *cnc, const gchar *current_dn, const gchar *new_dn, GError 
**error)
+{
+       g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (cnc), FALSE);
+       g_return_val_if_fail (current_dn && *current_dn, FALSE);
+       g_return_val_if_fail (gdaprov_ldap_is_dn (current_dn), FALSE);
+       g_return_val_if_fail (new_dn && *new_dn, FALSE);
+       g_return_val_if_fail (gdaprov_ldap_is_dn (new_dn), FALSE);
+
+       gda_lockable_lock ((GdaLockable*) cnc); /* CNC LOCK */
+
+       if (! gda_ldap_ensure_bound (cnc, error)) {
+               gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+               return FALSE;
+       }
+
+       LdapConnectionData *cdata;
+       cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data 
(GDA_VIRTUAL_CONNECTION (cnc));
+        if (!cdata) {
+               gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+               g_warning ("cdata != NULL failed");
+               return FALSE;
+       }
+
+       GdaServerProviderConnectionData *pcdata;
+       pcdata = gda_connection_internal_get_provider_data_error ((GdaConnection*) cnc, NULL);
+
+       GdaWorker *worker;
+       worker = gda_worker_ref (gda_connection_internal_get_worker (pcdata));
+
+       GMainContext *context;
+       context = gda_server_provider_get_real_main_context ((GdaConnection *) cnc);
+
+       WorkerRenamEntryData data;
+       data.cnc = (GdaLdapConnection*) cnc;
+       data.cdata = cdata;
+       data.current_dn = current_dn;
+       data.new_dn = new_dn;
+
+       gda_connection_set_status ((GdaConnection*) cnc, GDA_CONNECTION_STATUS_BUSY);
+       gpointer retval;
+       gda_worker_do_job (worker, context, 0, &retval, NULL,
+                          (GdaWorkerFunc) worker_gdaprov_ldap_rename_entry, (gpointer) &data, NULL, NULL, 
error);
+       if (context)
+               g_main_context_unref (context);
+
+       gda_connection_set_status ((GdaConnection*) cnc, GDA_CONNECTION_STATUS_IDLE);
+       gda_lockable_unlock ((GdaLockable*) cnc); /* CNC UNLOCK */
+
+       gda_worker_unref (worker);
+       return retval ? TRUE : FALSE;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]