[libgda] Web provider improvements



commit 92efe739a0698e8ea424ead61f063e1ab184518a
Author: Vivien Malerba <malerba gnome-db org>
Date:   Thu Nov 26 20:28:58 2009 +0100

    Web provider improvements

 providers/mysql/gda-mysql-provider.c               |    7 +-
 providers/mysql/gda-mysql.h                        |    6 +-
 providers/postgres/gda-postgres-provider.c         |   23 +-
 providers/postgres/gda-postgres.h                  |    4 -
 providers/reuseable/gda-provider-reuseable.h       |    1 +
 providers/reuseable/mysql/gda-mysql-reuseable.c    |   25 +-
 .../reuseable/postgres/gda-postgres-reuseable.c    |    2 +
 providers/web/gda-web-provider.c                   |  599 +++++++++-----------
 providers/web/gda-web-util.c                       |   10 +
 providers/web/gda-web.h                            |    1 +
 providers/web/php/gda-tester.php                   |    4 +-
 providers/web/php/gda-worker.php                   |   63 ++-
 12 files changed, 393 insertions(+), 352 deletions(-)
---
diff --git a/providers/mysql/gda-mysql-provider.c b/providers/mysql/gda-mysql-provider.c
index c3a5443..4e5aeae 100644
--- a/providers/mysql/gda-mysql-provider.c
+++ b/providers/mysql/gda-mysql-provider.c
@@ -726,8 +726,9 @@ gda_mysql_provider_get_server_version (GdaServerProvider  *provider,
 	cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
 	if (!cdata) 
 		return FALSE;
-	TO_IMPLEMENT;
-	return NULL;
+	if (! ((GdaProviderReuseable*)cdata->reuseable)->server_version)
+		_gda_mysql_compute_version (cnc, cdata->reuseable, NULL);
+	return ((GdaProviderReuseable*)cdata->reuseable)->server_version;
 }
 
 /*
@@ -2237,7 +2238,7 @@ gda_mysql_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
 		cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
 		if (!cdata) 
 			return NULL;
-		case_sensitive = cdata->identifiers_case_sensitive;
+		case_sensitive = cdata->reuseable->identifiers_case_sensitive;
 	}
 	else if (((GdaMysqlProvider*) provider)->test_mode)
 		case_sensitive = ((GdaMysqlProvider*) provider)->test_identifiers_case_sensitive;
diff --git a/providers/mysql/gda-mysql.h b/providers/mysql/gda-mysql.h
index 84026e0..aa3f0b5 100644
--- a/providers/mysql/gda-mysql.h
+++ b/providers/mysql/gda-mysql.h
@@ -41,11 +41,7 @@
 typedef struct {
 	GdaMysqlReuseable *reuseable;
 	GdaConnection     *cnc;
-	MYSQL             *mysql;
-
-	/* specifies how case sensitiveness is */
-	gboolean           identifiers_case_sensitive;
-	
+	MYSQL             *mysql;	
 } MysqlConnectionData;
 
 #endif
diff --git a/providers/postgres/gda-postgres-provider.c b/providers/postgres/gda-postgres-provider.c
index 3df815f..f91fca8 100644
--- a/providers/postgres/gda-postgres-provider.c
+++ b/providers/postgres/gda-postgres-provider.c
@@ -203,7 +203,7 @@ gda_postgres_provider_class_init (GdaPostgresProviderClass *klass)
         provider_class->create_operation = gda_postgres_provider_create_operation;
         provider_class->render_operation = gda_postgres_provider_render_operation;
         provider_class->perform_operation = gda_postgres_provider_perform_operation;
-
+	
 	provider_class->begin_transaction = gda_postgres_provider_begin_transaction;
 	provider_class->commit_transaction = gda_postgres_provider_commit_transaction;
 	provider_class->rollback_transaction = gda_postgres_provider_rollback_transaction;
@@ -518,20 +518,9 @@ gda_postgres_provider_open_connection (GdaServerProvider *provider, GdaConnectio
         cdata->pconn = pconn;
 
 	/*
-         * Get the version as a float
-         */
-	PGresult *pg_res;
-        pg_res = _gda_postgres_PQexec_wrap (cnc, pconn, "SELECT version ()");
-	if (!pg_res) {
-		gda_postgres_free_cnc_data (cdata);
-		return FALSE;
-	}
-        cdata->version = g_strdup (PQgetvalue(pg_res, 0, 0));
-        PQclear (pg_res);
-
-	/*
          * Sets the DATE format for all the current session to YYYY-MM-DD
          */
+	PGresult *pg_res;
         pg_res = _gda_postgres_PQexec_wrap (cnc, pconn, "SET DATESTYLE TO 'ISO'");
 	if (!pg_res) {
 		gda_postgres_free_cnc_data (cdata);
@@ -645,9 +634,11 @@ gda_postgres_provider_get_server_version (GdaServerProvider *provider, GdaConnec
 
 	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
 	if (!cdata)
-		return FALSE;
+		return NULL;
 
-	return cdata->version;
+	if (! ((GdaProviderReuseable*)cdata->reuseable)->server_version)
+		_gda_postgres_compute_version (cnc, cdata->reuseable, NULL);
+	return ((GdaProviderReuseable*)cdata->reuseable)->server_version;
 }
 
 /*
@@ -2472,8 +2463,6 @@ gda_postgres_free_cnc_data (PostgresConnectionData *cdata)
 	if (cdata->pconn)
                 PQfinish (cdata->pconn);
 
-	g_free (cdata->version);
-
 	if (cdata->reuseable) {
 		GdaProviderReuseable *rdata = (GdaProviderReuseable*)cdata->reuseable;
 		rdata->operations->re_reset_data (rdata);
diff --git a/providers/postgres/gda-postgres.h b/providers/postgres/gda-postgres.h
index fc70a11..e9d0500 100644
--- a/providers/postgres/gda-postgres.h
+++ b/providers/postgres/gda-postgres.h
@@ -54,10 +54,6 @@ typedef struct {
 	GdaConnection        *cnc;
         PGconn               *pconn;
 	gboolean              pconn_is_busy;
-
-        /* Version of the backend to which we are connected */
-        gchar                *version;
-        gchar                *short_version;
 } PostgresConnectionData;
 
 #endif
diff --git a/providers/reuseable/gda-provider-reuseable.h b/providers/reuseable/gda-provider-reuseable.h
index 4c05b94..e7a0606 100644
--- a/providers/reuseable/gda-provider-reuseable.h
+++ b/providers/reuseable/gda-provider-reuseable.h
@@ -58,6 +58,7 @@ typedef struct {
  */
 struct _GdaProviderReuseable {
 	GdaProviderReuseableOperations *operations;
+	gchar                          *server_version;
 	guint                           major; /* major version */
 	guint                           minor; /* minor version */
 	guint                           micro; /* micro version */
diff --git a/providers/reuseable/mysql/gda-mysql-reuseable.c b/providers/reuseable/mysql/gda-mysql-reuseable.c
index 7ba7c0a..25e713b 100644
--- a/providers/reuseable/mysql/gda-mysql-reuseable.c
+++ b/providers/reuseable/mysql/gda-mysql-reuseable.c
@@ -123,11 +123,13 @@ _gda_mysql_reuseable_reset_data (GdaProviderReuseable *rdata)
 	GdaMysqlReuseable *reuseable;
 	reuseable = (GdaMysqlReuseable*) rdata;
 
+	g_free (rdata->server_version);
+
 	memset (reuseable, 0, sizeof (GdaMysqlReuseable));
 }
 
 static GdaDataModel *
-execute_select (GdaConnection *cnc, GdaMysqlReuseable *rdata, const gchar *sql)
+execute_select (GdaConnection *cnc, GdaMysqlReuseable *rdata, const gchar *sql, GError **error)
 {
 	GdaSqlParser *parser;
 	GdaStatement *stmt;
@@ -138,7 +140,7 @@ execute_select (GdaConnection *cnc, GdaMysqlReuseable *rdata, const gchar *sql)
 	g_object_unref (parser);
 	g_assert (stmt);
 
-	model = gda_connection_statement_execute_select (cnc, stmt, NULL, NULL);
+	model = gda_connection_statement_execute_select (cnc, stmt, NULL, error);
 	g_object_unref (stmt);
 
 	return model;
@@ -175,6 +177,7 @@ _gda_mysql_compute_version (GdaConnection *cnc, GdaMysqlReuseable *rdata, GError
 
 	const gchar *str;
 	str = g_value_get_string (cvalue);
+	((GdaProviderReuseable*)rdata)->server_version = g_strdup (str);
 
 	/* analyse string */
 	const gchar *ptr;
@@ -200,6 +203,24 @@ _gda_mysql_compute_version (GdaConnection *cnc, GdaMysqlReuseable *rdata, GError
 		 ((GdaProviderReuseable*)rdata)->minor,
 		 ((GdaProviderReuseable*)rdata)->micro);
 	*/
+
+	model = execute_select (cnc, rdata, "SHOW VARIABLES WHERE Variable_name = 'lower_case_table_names'", error);
+	if (!model)
+		return FALSE;
+	cvalue = gda_data_model_get_value_at (model, 0, 0, NULL);
+	if (!cvalue) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+                             GDA_SERVER_PROVIDER_INTERNAL_ERROR, "%s",
+                             _("Can't import data from web server"));
+		g_object_unref (model);
+		return FALSE;
+	}
+	str = g_value_get_string (cvalue);
+	rdata->identifiers_case_sensitive = FALSE;
+	if (atoi (str) == 0)
+		rdata->identifiers_case_sensitive = TRUE;
+	g_object_unref (model);
+
 	return TRUE;
 }
 
diff --git a/providers/reuseable/postgres/gda-postgres-reuseable.c b/providers/reuseable/postgres/gda-postgres-reuseable.c
index b7bfc9f..50ca46c 100644
--- a/providers/reuseable/postgres/gda-postgres-reuseable.c
+++ b/providers/reuseable/postgres/gda-postgres-reuseable.c
@@ -142,6 +142,7 @@ _gda_postgres_reuseable_reset_data (GdaProviderReuseable *rdata)
 	GdaPostgresReuseable *reuseable;
 	reuseable = (GdaPostgresReuseable*) rdata;
 
+	g_free (rdata->server_version);
 	if (reuseable->types_dbtype_hash)
 		g_hash_table_destroy (reuseable->types_dbtype_hash);
 	if (reuseable->types_oid_hash)
@@ -202,6 +203,7 @@ _gda_postgres_compute_version (GdaConnection *cnc, GdaPostgresReuseable *rdata,
 
 	const gchar *str;
 	str = g_value_get_string (cvalue);
+	((GdaProviderReuseable*)rdata)->server_version = g_strdup (str);
 
 	/* analyse string */
 	const gchar *ptr;
diff --git a/providers/web/gda-web-provider.c b/providers/web/gda-web-provider.c
index b2b493f..4e41ae0 100644
--- a/providers/web/gda-web-provider.c
+++ b/providers/web/gda-web-provider.c
@@ -62,7 +62,6 @@ static gboolean            gda_web_provider_open_connection (GdaServerProvider *
 							     guint *task_id, GdaServerProviderAsyncCallback async_cb, gpointer cb_data);
 static gboolean            gda_web_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc);
 static const gchar        *gda_web_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc);
-static const gchar        *gda_web_provider_get_database (GdaServerProvider *provider, GdaConnection *cnc);
 
 /* DDL operations */
 static gboolean            gda_web_provider_supports_operation (GdaServerProvider *provider, GdaConnection *cnc,
@@ -118,22 +117,10 @@ static GObject             *gda_web_provider_statement_execute (GdaServerProvide
 								guint *task_id, GdaServerProviderExecCallback async_cb, 
 								gpointer cb_data, GError **error);
 
-/* distributed transactions */
-static gboolean gda_web_provider_xa_start    (GdaServerProvider *provider, GdaConnection *cnc, 
-					      const GdaXaTransactionId *xid, GError **error);
-
-static gboolean gda_web_provider_xa_end      (GdaServerProvider *provider, GdaConnection *cnc, 
-					      const GdaXaTransactionId *xid, GError **error);
-static gboolean gda_web_provider_xa_prepare  (GdaServerProvider *provider, GdaConnection *cnc, 
-					      const GdaXaTransactionId *xid, GError **error);
-
-static gboolean gda_web_provider_xa_commit   (GdaServerProvider *provider, GdaConnection *cnc, 
-					      const GdaXaTransactionId *xid, GError **error);
-static gboolean gda_web_provider_xa_rollback (GdaServerProvider *provider, GdaConnection *cnc, 
-					      const GdaXaTransactionId *xid, GError **error);
-
-static GList   *gda_web_provider_xa_recover  (GdaServerProvider *provider, GdaConnection *cnc, 
-					      GError **error);
+/* Quoting */
+static gchar               *gda_web_identifier_quote    (GdaServerProvider *provider, GdaConnection *cnc,
+							 const gchar *id,
+							 gboolean meta_store_convention, gboolean force_quotes);
 
 
 /*
@@ -156,7 +143,7 @@ gda_web_provider_class_init (GdaWebProviderClass *klass)
 
 	provider_class->open_connection = gda_web_provider_open_connection;
 	provider_class->close_connection = gda_web_provider_close_connection;
-	provider_class->get_database = gda_web_provider_get_database;
+	provider_class->get_database = NULL;
 
 	provider_class->supports_operation = gda_web_provider_supports_operation;
         provider_class->create_operation = gda_web_provider_create_operation;
@@ -179,6 +166,8 @@ gda_web_provider_class_init (GdaWebProviderClass *klass)
 	provider_class->cancel = NULL;
 	provider_class->create_connection = NULL;
 
+	provider_class->identifier_quote = gda_web_identifier_quote;
+
 	memset (&(provider_class->meta_funcs), 0, sizeof (GdaServerProviderMeta));
 	provider_class->meta_funcs._info = _gda_web_meta__info;
 	provider_class->meta_funcs._btypes = _gda_web_meta__btypes;
@@ -224,13 +213,7 @@ gda_web_provider_class_init (GdaWebProviderClass *klass)
 	provider_class->meta_funcs.routine_par = _gda_web_meta_routine_par;
 
 	/* distributed transactions: if not supported, then provider_class->xa_funcs should be set to NULL */
-	provider_class->xa_funcs = g_new0 (GdaServerProviderXa, 1);
-	provider_class->xa_funcs->xa_start = gda_web_provider_xa_start;
-	provider_class->xa_funcs->xa_end = gda_web_provider_xa_end;
-	provider_class->xa_funcs->xa_prepare = gda_web_provider_xa_prepare;
-	provider_class->xa_funcs->xa_commit = gda_web_provider_xa_commit;
-	provider_class->xa_funcs->xa_rollback = gda_web_provider_xa_rollback;
-	provider_class->xa_funcs->xa_recover = gda_web_provider_xa_recover;
+	provider_class->xa_funcs = NULL;
 
 	/* provider is thread safe */
 	provider_class->limiting_thread = NULL;
@@ -571,28 +554,7 @@ gda_web_provider_get_server_version (GdaServerProvider *provider, GdaConnection
 	cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
 	if (!cdata) 
 		return FALSE;
-	TO_IMPLEMENT;
-	return NULL;
-}
-
-/*
- * Get database request
- *
- * Returns the database name as a string, which should be stored in @cnc's associated WebConnectionData structure
- */
-static const gchar *
-gda_web_provider_get_database (GdaServerProvider *provider, GdaConnection *cnc)
-{
-	WebConnectionData *cdata;
-
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
-
-	cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
-	if (!cdata) 
-		return NULL;
-	TO_IMPLEMENT;
-	return NULL;
+	return cdata->server_version;
 }
 
 /*
@@ -604,7 +566,7 @@ gda_web_provider_get_database (GdaServerProvider *provider, GdaConnection *cnc)
  *   - make this method return TRUE for the operation type
  *   - implement the gda_web_provider_render_operation() and gda_web_provider_perform_operation() methods
  *
- * In this example, the GDA_SERVER_OPERATION_CREATE_TABLE is implemented
+ * For now no server operation is supported, it can be added if cdata->reuseable is not %NULL
  */
 static gboolean
 gda_web_provider_supports_operation (GdaServerProvider *provider, GdaConnection *cnc,
@@ -618,10 +580,7 @@ gda_web_provider_supports_operation (GdaServerProvider *provider, GdaConnection
         switch (type) {
         case GDA_SERVER_OPERATION_CREATE_DB:
         case GDA_SERVER_OPERATION_DROP_DB:
-		return FALSE;
-
         case GDA_SERVER_OPERATION_CREATE_TABLE:
-		return TRUE;
         case GDA_SERVER_OPERATION_DROP_TABLE:
         case GDA_SERVER_OPERATION_RENAME_TABLE:
 
@@ -633,6 +592,7 @@ gda_web_provider_supports_operation (GdaServerProvider *provider, GdaConnection
         case GDA_SERVER_OPERATION_CREATE_VIEW:
         case GDA_SERVER_OPERATION_DROP_VIEW:
         default:
+		TO_IMPLEMENT;
                 return FALSE;
         }
 }
@@ -647,35 +607,22 @@ static GdaServerOperation *
 gda_web_provider_create_operation (GdaServerProvider *provider, GdaConnection *cnc,
 				   GdaServerOperationType type, GdaSet *options, GError **error)
 {
-        gchar *file;
-        GdaServerOperation *op;
-        gchar *str;
-	gchar *dir;
+	WebConnectionData *cdata = NULL;
 
 	if (cnc) {
 		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
 		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
-	}
 
-        file = g_utf8_strdown (gda_server_operation_op_type_to_string (type), -1);
-        str = g_strdup_printf ("web_specs_%s.xml", file);
-        g_free (file);
-
-	dir = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, NULL);
-        file = gda_server_provider_find_file (provider, dir, str);
-	g_free (dir);
-
-        if (! file) {
-                g_set_error (error, 0, 0, _("Missing spec. file '%s'"), str);
-		g_free (str);
-                return NULL;
-        }
-        g_free (str);
-
-        op = gda_server_operation_new (type, file);
-        g_free (file);
+		cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	}
+	if (!cdata) {
+		g_set_error (error, 0, 0, _("Not supported"));
+		return NULL;
+	}
 
-        return op;
+	TO_IMPLEMENT;
+	g_set_error (error, 0, 0, _("Server operations not yet implemented"));
+	return NULL;
 }
 
 /*
@@ -685,59 +632,22 @@ static gchar *
 gda_web_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc,
 				   GdaServerOperation *op, GError **error)
 {
-        gchar *sql = NULL;
-        gchar *file;
-        gchar *str;
-	gchar *dir;
+	WebConnectionData *cdata = NULL;
 
 	if (cnc) {
 		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
 		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
-	}
-
-	/* test @op's validity */
-        file = g_utf8_strdown (gda_server_operation_op_type_to_string (gda_server_operation_get_op_type (op)), -1);
-        str = g_strdup_printf ("web_specs_%s.xml", file);
-        g_free (file);
-
-	dir = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, NULL);
-        file = gda_server_provider_find_file (provider, dir, str);
-	g_free (dir);
 
-        if (! file) {
-                g_set_error (error, 0, 0, _("Missing spec. file '%s'"), str);
-		g_free (str);
-                return NULL;
-        }
-        g_free (str);
-        if (!gda_server_operation_is_valid (op, file, error)) {
-                g_free (file);
-                return NULL;
-        }
-        g_free (file);
+		cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	}
+	if (!cdata) {
+		g_set_error (error, 0, 0, _("Not supported"));
+		return NULL;
+	}
 
-	/* actual rendering */
-        switch (gda_server_operation_get_op_type (op)) {
-        case GDA_SERVER_OPERATION_CREATE_DB:
-        case GDA_SERVER_OPERATION_DROP_DB:
-		sql = NULL;
-                break;
-        case GDA_SERVER_OPERATION_CREATE_TABLE:
-                sql = gda_web_render_CREATE_TABLE (provider, cnc, op, error);
-                break;
-        case GDA_SERVER_OPERATION_DROP_TABLE:
-        case GDA_SERVER_OPERATION_RENAME_TABLE:
-        case GDA_SERVER_OPERATION_ADD_COLUMN:
-        case GDA_SERVER_OPERATION_CREATE_INDEX:
-        case GDA_SERVER_OPERATION_DROP_INDEX:
-        case GDA_SERVER_OPERATION_CREATE_VIEW:
-        case GDA_SERVER_OPERATION_DROP_VIEW:
-                sql = NULL;
-                break;
-        default:
-                g_assert_not_reached ();
-        }
-        return sql;
+	TO_IMPLEMENT;
+	g_set_error (error, 0, 0, _("Server operations not yet implemented"));
+	return NULL;
 }
 
 /*
@@ -784,13 +694,57 @@ gda_web_provider_begin_transaction (GdaServerProvider *provider, GdaConnection *
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
 
+	if (name && *name) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_NON_SUPPORTED_ERROR,
+			     "%s", _("Named transaction is not supported"));
+		return FALSE;
+	}
+	if (level != GDA_TRANSACTION_ISOLATION_UNKNOWN) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_NON_SUPPORTED_ERROR,
+			     "%s", _("Transaction level is not supported"));
+		return FALSE;
+	}
 	cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
 	if (!cdata) 
 		return FALSE;
 
-	TO_IMPLEMENT;
+	/* prepare XML command */
+	xmlDocPtr doc;
+	xmlNodePtr root, cmdnode;
+	gchar *token;
+	doc = xmlNewDoc (BAD_CAST "1.0");
+	root = xmlNewNode (NULL, BAD_CAST "request");
+	xmlDocSetRootElement (doc, root);
+	token = _gda_web_compute_token (cdata);
+	xmlNewChild (root, NULL, BAD_CAST "token", BAD_CAST token);
+	g_free (token);
+	cmdnode = xmlNewChild (root, NULL, BAD_CAST "cmd", BAD_CAST "BEGIN");
 
-	return FALSE;
+	/* send command */
+	xmlChar *cmde;
+	xmlDocPtr replydoc;
+	int size;
+	gchar status;
+	
+	xmlDocDumpMemory (doc, &cmde, &size);
+	xmlFreeDoc (doc);
+	replydoc = _gda_web_send_message_to_frontend (cnc, cdata, MESSAGE_PREPARE, (gchar*) cmde, cdata->key, &status);
+	xmlFree (cmde);
+
+	if (!replydoc) {
+		_gda_web_change_connection_to_closed (cnc, cdata);
+		return FALSE;
+	}
+	if (status != 'O') {
+		_gda_web_set_connection_error_from_xmldoc (cnc, replydoc, error);
+		xmlFreeDoc (replydoc);
+
+		if (status == 'C')
+			_gda_web_change_connection_to_closed (cnc, cdata);
+		return FALSE;
+	}
+
+	return TRUE;
 }
 
 /*
@@ -805,13 +759,52 @@ gda_web_provider_commit_transaction (GdaServerProvider *provider, GdaConnection
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
 
+	if (name && *name) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_NON_SUPPORTED_ERROR,
+			     "%s", _("Named transaction is not supported"));
+		return FALSE;
+	}
 	cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
 	if (!cdata) 
 		return FALSE;
 
-	TO_IMPLEMENT;
+	/* prepare XML command */
+	xmlDocPtr doc;
+	xmlNodePtr root, cmdnode;
+	gchar *token;
+	doc = xmlNewDoc (BAD_CAST "1.0");
+	root = xmlNewNode (NULL, BAD_CAST "request");
+	xmlDocSetRootElement (doc, root);
+	token = _gda_web_compute_token (cdata);
+	xmlNewChild (root, NULL, BAD_CAST "token", BAD_CAST token);
+	g_free (token);
+	cmdnode = xmlNewChild (root, NULL, BAD_CAST "cmd", BAD_CAST "COMMIT");
 
-	return FALSE;
+	/* send command */
+	xmlChar *cmde;
+	xmlDocPtr replydoc;
+	int size;
+	gchar status;
+	
+	xmlDocDumpMemory (doc, &cmde, &size);
+	xmlFreeDoc (doc);
+	replydoc = _gda_web_send_message_to_frontend (cnc, cdata, MESSAGE_PREPARE, (gchar*) cmde, cdata->key, &status);
+	xmlFree (cmde);
+
+	if (!replydoc) {
+		_gda_web_change_connection_to_closed (cnc, cdata);
+		return FALSE;
+	}
+	if (status != 'O') {
+		_gda_web_set_connection_error_from_xmldoc (cnc, replydoc, error);
+		xmlFreeDoc (replydoc);
+
+		if (status == 'C')
+			_gda_web_change_connection_to_closed (cnc, cdata);
+		return FALSE;
+	}
+
+	return TRUE;
 }
 
 /*
@@ -826,13 +819,52 @@ gda_web_provider_rollback_transaction (GdaServerProvider *provider, GdaConnectio
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
 
+	if (name && *name) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_NON_SUPPORTED_ERROR,
+			     "%s", _("Named transaction is not supported"));
+		return FALSE;
+	}
 	cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
 	if (!cdata) 
 		return FALSE;
 
-	TO_IMPLEMENT;
+	/* prepare XML command */
+	xmlDocPtr doc;
+	xmlNodePtr root, cmdnode;
+	gchar *token;
+	doc = xmlNewDoc (BAD_CAST "1.0");
+	root = xmlNewNode (NULL, BAD_CAST "request");
+	xmlDocSetRootElement (doc, root);
+	token = _gda_web_compute_token (cdata);
+	xmlNewChild (root, NULL, BAD_CAST "token", BAD_CAST token);
+	g_free (token);
+	cmdnode = xmlNewChild (root, NULL, BAD_CAST "cmd", BAD_CAST "ROLLBACK");
 
-	return FALSE;
+	/* send command */
+	xmlChar *cmde;
+	xmlDocPtr replydoc;
+	int size;
+	gchar status;
+	
+	xmlDocDumpMemory (doc, &cmde, &size);
+	xmlFreeDoc (doc);
+	replydoc = _gda_web_send_message_to_frontend (cnc, cdata, MESSAGE_PREPARE, (gchar*) cmde, cdata->key, &status);
+	xmlFree (cmde);
+
+	if (!replydoc) {
+		_gda_web_change_connection_to_closed (cnc, cdata);
+		return FALSE;
+	}
+	if (status != 'O') {
+		_gda_web_set_connection_error_from_xmldoc (cnc, replydoc, error);
+		xmlFreeDoc (replydoc);
+
+		if (status == 'C')
+			_gda_web_change_connection_to_closed (cnc, cdata);
+		return FALSE;
+	}
+
+	return TRUE;
 }
 
 /*
@@ -847,13 +879,53 @@ gda_web_provider_add_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
 
+	if (!name || !(*name)) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_NON_SUPPORTED_ERROR,
+			     "%s", _("Unnamed savepoint is not supported"));
+		return FALSE;
+	}
 	cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
 	if (!cdata) 
 		return FALSE;
 
-	TO_IMPLEMENT;
+	/* prepare XML command */
+	xmlDocPtr doc;
+	xmlNodePtr root, cmdnode;
+	gchar *token;
+	doc = xmlNewDoc (BAD_CAST "1.0");
+	root = xmlNewNode (NULL, BAD_CAST "request");
+	xmlDocSetRootElement (doc, root);
+	token = _gda_web_compute_token (cdata);
+	xmlNewChild (root, NULL, BAD_CAST "token", BAD_CAST token);
+	g_free (token);
+	cmdnode = xmlNewChild (root, NULL, BAD_CAST "cmd", BAD_CAST "BEGIN");
+	xmlSetProp (cmdnode, BAD_CAST "svpname", BAD_CAST name);
 
-	return FALSE;
+	/* send command */
+	xmlChar *cmde;
+	xmlDocPtr replydoc;
+	int size;
+	gchar status;
+	
+	xmlDocDumpMemory (doc, &cmde, &size);
+	xmlFreeDoc (doc);
+	replydoc = _gda_web_send_message_to_frontend (cnc, cdata, MESSAGE_PREPARE, (gchar*) cmde, cdata->key, &status);
+	xmlFree (cmde);
+
+	if (!replydoc) {
+		_gda_web_change_connection_to_closed (cnc, cdata);
+		return FALSE;
+	}
+	if (status != 'O') {
+		_gda_web_set_connection_error_from_xmldoc (cnc, replydoc, error);
+		xmlFreeDoc (replydoc);
+
+		if (status == 'C')
+			_gda_web_change_connection_to_closed (cnc, cdata);
+		return FALSE;
+	}
+
+	return TRUE;
 }
 
 /*
@@ -868,13 +940,53 @@ gda_web_provider_rollback_savepoint (GdaServerProvider *provider, GdaConnection
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
 
+	if (!name || !(*name)) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_NON_SUPPORTED_ERROR,
+			     "%s", _("Unnamed savepoint is not supported"));
+		return FALSE;
+	}
 	cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
 	if (!cdata) 
 		return FALSE;
 
-	TO_IMPLEMENT;
+	/* prepare XML command */
+	xmlDocPtr doc;
+	xmlNodePtr root, cmdnode;
+	gchar *token;
+	doc = xmlNewDoc (BAD_CAST "1.0");
+	root = xmlNewNode (NULL, BAD_CAST "request");
+	xmlDocSetRootElement (doc, root);
+	token = _gda_web_compute_token (cdata);
+	xmlNewChild (root, NULL, BAD_CAST "token", BAD_CAST token);
+	g_free (token);
+	cmdnode = xmlNewChild (root, NULL, BAD_CAST "cmd", BAD_CAST "ROLLBACK");
+	xmlSetProp (cmdnode, BAD_CAST "svpname", BAD_CAST name);
 
-	return FALSE;
+	/* send command */
+	xmlChar *cmde;
+	xmlDocPtr replydoc;
+	int size;
+	gchar status;
+	
+	xmlDocDumpMemory (doc, &cmde, &size);
+	xmlFreeDoc (doc);
+	replydoc = _gda_web_send_message_to_frontend (cnc, cdata, MESSAGE_PREPARE, (gchar*) cmde, cdata->key, &status);
+	xmlFree (cmde);
+
+	if (!replydoc) {
+		_gda_web_change_connection_to_closed (cnc, cdata);
+		return FALSE;
+	}
+	if (status != 'O') {
+		_gda_web_set_connection_error_from_xmldoc (cnc, replydoc, error);
+		xmlFreeDoc (replydoc);
+
+		if (status == 'C')
+			_gda_web_change_connection_to_closed (cnc, cdata);
+		return FALSE;
+	}
+
+	return TRUE;
 }
 
 /*
@@ -936,31 +1048,19 @@ static GdaDataHandler *
 gda_web_provider_get_data_handler (GdaServerProvider *provider, GdaConnection *cnc,
 				   GType type, const gchar *dbms_type)
 {
-	GdaDataHandler *dh;
+	WebConnectionData *cdata = NULL;
+
 	if (cnc) {
 		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
 		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
-	}
 
-	if (type == G_TYPE_INVALID) {
-		TO_IMPLEMENT; /* use @dbms_type */
-		dh = NULL;
-	}
-	else if ((type == GDA_TYPE_BINARY) ||
-		 (type == GDA_TYPE_BLOB)) {
-		TO_IMPLEMENT; /* define data handlers for these types */
-		dh = NULL;
-	}
-	else if ((type == GDA_TYPE_TIME) ||
-		 (type == GDA_TYPE_TIMESTAMP) ||
-		 (type == G_TYPE_DATE)) {
-		TO_IMPLEMENT; /* define data handlers for these types */
-		dh = NULL;
+		cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
 	}
-	else
-		dh = gda_server_provider_get_data_handler_default (provider, cnc, type, dbms_type);
+	if (!cdata)
+		return NULL;
 
-	return dh;
+	TO_IMPLEMENT;
+	return NULL;
 }
 
 /*
@@ -971,55 +1071,19 @@ gda_web_provider_get_data_handler (GdaServerProvider *provider, GdaConnection *c
 static const gchar*
 gda_web_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConnection *cnc, GType type)
 {
+	WebConnectionData *cdata = NULL;
+
 	if (cnc) {
 		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
 		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+
+		cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
 	}
+	if (!cdata)
+		return NULL;
 
 	TO_IMPLEMENT;
-
-	if ((type == G_TYPE_INT64) ||
-	    (type == G_TYPE_INT) ||
-	    (type == GDA_TYPE_SHORT) ||
-	    (type == GDA_TYPE_USHORT) ||
-	    (type == G_TYPE_CHAR) ||
-	    (type == G_TYPE_UCHAR) ||
-	    (type == G_TYPE_ULONG) ||
-	    (type == G_TYPE_UINT) ||
-	    (type == G_TYPE_UINT64))
-		return "integer";
-
-	if ((type == GDA_TYPE_BINARY) ||
-	    (type == GDA_TYPE_BLOB))
-		return "blob";
-
-	if (type == G_TYPE_BOOLEAN)
-		return "boolean";
-	
-	if ((type == G_TYPE_DATE) || 
-	    (type == GDA_TYPE_GEOMETRIC_POINT) ||
-	    (type == G_TYPE_OBJECT) ||
-	    (type == GDA_TYPE_LIST) ||
-	    (type == G_TYPE_STRING) ||
-	    (type == GDA_TYPE_TIME) ||
-	    (type == GDA_TYPE_TIMESTAMP) ||
-	    (type == G_TYPE_INVALID) ||
-	    (type == G_TYPE_GTYPE))
-		return "string";
-
-	if ((type == G_TYPE_DOUBLE) ||
-	    (type == GDA_TYPE_NUMERIC) ||
-	    (type == G_TYPE_FLOAT))
-		return "real";
-	
-	if (type == GDA_TYPE_TIME)
-		return "time";
-	if (type == GDA_TYPE_TIMESTAMP)
-		return "timestamp";
-	if (type == G_TYPE_DATE)
-		return "date";
-
-	return "text";
+	return NULL;
 }
 
 /*
@@ -1057,12 +1121,19 @@ gda_web_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection *c
 				   GdaStatement *stmt, GdaSet *params, GdaStatementSqlFlag flags,
 				   GSList **params_used, GError **error)
 {
+	WebConnectionData *cdata = NULL;
 	g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
+
 	if (cnc) {
-		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+
+		cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
 	}
+	if (!cdata)
+		return gda_statement_to_sql_extended (stmt, cnc, params, flags, params_used, error);
 
+	/*TO_IMPLEMENT;*/
 	return gda_statement_to_sql_extended (stmt, cnc, params, flags, params_used, error);
 }
 
@@ -1364,6 +1435,7 @@ gda_web_provider_statement_execute (GdaServerProvider *provider, GdaConnection *
 	else if (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_UNKNOWN) {
 		if (! g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "select", 6) ||
 		    ! g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "pragma", 6) ||
+		    ! g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "show", 4) ||
 		    ! g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "describe", 8))
 			xmlSetProp (node, BAD_CAST "type", BAD_CAST "SELECT");
 	}
@@ -1557,131 +1629,22 @@ gda_web_provider_statement_execute (GdaServerProvider *provider, GdaConnection *
 	return retval;
 }
 
-/*
- * starts a distributed transaction: put the XA transaction in the ACTIVE state
- */
-static gboolean
-gda_web_provider_xa_start (GdaServerProvider *provider, GdaConnection *cnc, 
-			   const GdaXaTransactionId *xid, GError **error)
-{
-	WebConnectionData *cdata;
-
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
-	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
-	g_return_val_if_fail (xid, FALSE);
-
-	cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
-	if (!cdata) 
-		return FALSE;
-
-	TO_IMPLEMENT;
-	return FALSE;
-}
-
-/*
- * put the XA transaction in the IDLE state: the connection won't accept any more modifications.
- * This state is required by some database providers before actually going to the PREPARED state
- */
-static gboolean
-gda_web_provider_xa_end (GdaServerProvider *provider, GdaConnection *cnc, 
-			 const GdaXaTransactionId *xid, GError **error)
-{
-	WebConnectionData *cdata;
-
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
-	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
-	g_return_val_if_fail (xid, FALSE);
-
-	cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
-	if (!cdata) 
-		return FALSE;
-
-	TO_IMPLEMENT;
-	return FALSE;
-}
-
-/*
- * prepares the distributed transaction: put the XA transaction in the PREPARED state
- */
-static gboolean
-gda_web_provider_xa_prepare (GdaServerProvider *provider, GdaConnection *cnc, 
-			     const GdaXaTransactionId *xid, GError **error)
-{
-	WebConnectionData *cdata;
-
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
-	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
-	g_return_val_if_fail (xid, FALSE);
-
-	cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
-	if (!cdata) 
-		return FALSE;
-
-	TO_IMPLEMENT;
-	return FALSE;
-}
-
-/*
- * commits the distributed transaction: actually write the prepared data to the database and
- * terminates the XA transaction
- */
-static gboolean
-gda_web_provider_xa_commit (GdaServerProvider *provider, GdaConnection *cnc, 
-			    const GdaXaTransactionId *xid, GError **error)
-{
-	WebConnectionData *cdata;
-
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
-	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
-	g_return_val_if_fail (xid, FALSE);
-
-	cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
-	if (!cdata) 
-		return FALSE;
-
-	TO_IMPLEMENT;
-	return FALSE;
-}
-
-/*
- * Rolls back an XA transaction, possible only if in the ACTIVE, IDLE or PREPARED state
- */
-static gboolean
-gda_web_provider_xa_rollback (GdaServerProvider *provider, GdaConnection *cnc, 
-			      const GdaXaTransactionId *xid, GError **error)
-{
-	WebConnectionData *cdata;
-
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
-	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
-	g_return_val_if_fail (xid, FALSE);
-
-	cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
-	if (!cdata) 
-		return FALSE;
-
-	TO_IMPLEMENT;
-	return FALSE;
-}
-
-/*
- * Lists all XA transactions that are in the PREPARED state
- *
- * Returns: a list of GdaXaTransactionId structures, which will be freed by the caller
- */
-static GList *
-gda_web_provider_xa_recover (GdaServerProvider *provider, GdaConnection *cnc,
-			     GError **error)
+static gchar *
+gda_web_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
+			  const gchar *id,
+			  gboolean for_meta_store, gboolean force_quotes)
 {
-	WebConnectionData *cdata;
+	WebConnectionData *cdata = NULL;
 
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+	if (cnc) {
+		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
 
-	cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
-	if (!cdata) 
-		return NULL;
+		cdata = (WebConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	}
+	if (!cdata)
+		return gda_sql_identifier_quote (id, NULL, NULL, for_meta_store, force_quotes);
 
-	TO_IMPLEMENT;
-	return NULL;
+	/*TO_IMPLEMENT;*/
+	return gda_sql_identifier_quote (id, NULL, NULL, for_meta_store, force_quotes);
 }
diff --git a/providers/web/gda-web-util.c b/providers/web/gda-web-util.c
index 273abdb..9ee50e1 100644
--- a/providers/web/gda-web-util.c
+++ b/providers/web/gda-web-util.c
@@ -210,6 +210,15 @@ decode_buffer_response (GdaConnection *cnc, WebConnectionData *cdata, SoupBuffer
 				g_print ("REUSEABLE [%s]: %p\n", cdata->server_id, cdata->reuseable);
 #endif
 			}
+			else if (!cdata->server_version && !strcmp ((gchar*) node->name, "serverversion")) {
+				xmlChar *contents;
+				contents = xmlNodeGetContent (node);
+				cdata->server_version = g_strdup ((gchar*) contents);
+				xmlFree (contents);
+#ifdef DEBUG_WEB_PROV
+				g_print ("SERVER version [%s]\n", cdata->server_version);
+#endif
+			}
 		}
 	}
 
@@ -638,6 +647,7 @@ _gda_web_free_cnc_data (WebConnectionData *cdata)
 		g_free (cdata->reuseable);
 	}
 	g_free (cdata->server_id);
+	g_free (cdata->server_version);
 	g_free (cdata->server_base_url);
 	g_free (cdata->front_url);
 	g_free (cdata->worker_url);
diff --git a/providers/web/gda-web.h b/providers/web/gda-web.h
index 5aa3140..a1f9dc6 100644
--- a/providers/web/gda-web.h
+++ b/providers/web/gda-web.h
@@ -41,6 +41,7 @@ typedef struct {
 	GdaMutex *mutex; /* protected access */
 
 	gchar *server_id; /* PostgreSQL, MySQL, ... */
+	gchar *server_version; /* native representation */
 
 	gboolean forced_closing;
 	gchar *server_base_url;
diff --git a/providers/web/php/gda-tester.php b/providers/web/php/gda-tester.php
index 07781ca..7303087 100644
--- a/providers/web/php/gda-tester.php
+++ b/providers/web/php/gda-tester.php
@@ -20,7 +20,7 @@ if (! extension_loaded ("SimpleXML")) {
 	exit (1);
 }
 
-function handle_pear_error ($res, $reply)
+function handle_pear_error ($res)
 {
 	if (PEAR::isError($res)) {
 		$cause = "\tStandard Message [".$res->getMessage()."]\n". 
@@ -36,7 +36,7 @@ if ($test_connections) {
 		echo "Connection ".$dbname;
 		try {
 			$mdb2 = MDB2::connect($dsn[$dbname]);
-			handle_pear_error ($mdb2, $reply);
+			handle_pear_error ($mdb2);
 			echo " ==> OK\n";
 		}
 		catch (GdaException $e) {
diff --git a/providers/web/php/gda-worker.php b/providers/web/php/gda-worker.php
index f4de601..4e96dd7 100644
--- a/providers/web/php/gda-worker.php
+++ b/providers/web/php/gda-worker.php
@@ -320,6 +320,7 @@ function gda_handle_xml ($xml, &$doquit)
 				$dbtype = determine_db_type ($mdb2);
 				if ($dbtype)
 					$reply->addChild ('servertype', $dbtype);
+				$reply->addChild ('serverversion', $mdb2->getServerVersion (true));
 				$status = "OK";
 				break;
 
@@ -420,6 +421,66 @@ function gda_handle_xml ($xml, &$doquit)
 				do_exec ($reply, $mdb2, $pstmt_hash, $sql, $type_is_result, $argsnode);
 				$status = "OK";
 				break;
+			case "BEGIN":
+				if (!isset ($_SESSION['key']))
+					throw new GdaException('Protocol error', true);
+				if ($token == "-")
+					throw new GdaException('Not authenticated', true);
+					
+				/* actually execute SQL in $sql */
+				if (!isset ($mdb2))
+					$mdb2 = real_connect ($_SESSION['dsn'], $reply);
+
+				foreach ($child->attributes() as $a => $b) {
+					if ($a == "svpname") {
+						$svpname = $b;
+						break;
+					}
+				}
+				if (isset ($svpname))
+					$res = $mdb2->beginTransaction ($svpname);
+				else
+					$res = $mdb2->beginTransaction ();
+				handle_pear_error ($res, $reply);
+				$status = "OK";
+				break;
+			case "COMMIT":
+				if (!isset ($_SESSION['key']))
+					throw new GdaException('Protocol error', true);
+				if ($token == "-")
+					throw new GdaException('Not authenticated', true);
+					
+				/* actually execute SQL in $sql */
+				if (!isset ($mdb2))
+					$mdb2 = real_connect ($_SESSION['dsn'], $reply);
+
+				$res = $mdb2->commit ();
+				handle_pear_error ($res, $reply);
+				$status = "OK";
+				break;
+			case "ROLLBACK":
+				if (!isset ($_SESSION['key']))
+					throw new GdaException('Protocol error', true);
+				if ($token == "-")
+					throw new GdaException('Not authenticated', true);
+					
+				/* actually execute SQL in $sql */
+				if (!isset ($mdb2))
+					$mdb2 = real_connect ($_SESSION['dsn'], $reply);
+
+				foreach ($child->attributes() as $a => $b) {
+					if ($a == "svpname") {
+						$svpname = $b;
+						break;
+					}
+				}
+				if (isset ($svpname))
+					$res = $mdb2->rollback ($svpname);
+				else
+					$res = $mdb2->rollback ();
+				handle_pear_error ($res, $reply);
+				$status = "OK";
+				break;
 			case 'META':
 				if (!isset ($_SESSION['key']))
 					throw new GdaException('Protocol error', true);
@@ -557,7 +618,7 @@ function do_exec ($reply, &$mdb2, $pstmt_hash, $sql, $type_is_result, $argsnode)
 		$ncols = $res->numCols();
 
 		/* compute field type */
-		$tableinfo = $mdb2->tableInfo ($res, NULL);
+		$tableinfo = $mdb2->reverse->tableInfo ($res, NULL);
 		if (! PEAR::isError ($tableinfo)) {
 			//var_dump($tableinfo);
 			$gtypes = array();



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