libgda r3159 - in trunk: . doc/C doc/C/tmpl libgda libgda/sql-parser po providers/mysql providers/postgres testing



Author: vivien
Date: Wed Jun  4 20:35:49 2008
New Revision: 3159
URL: http://svn.gnome.org/viewvc/libgda?rev=3159&view=rev

Log:
2008-06-04  Vivien Malerba <malerba gnome-db org>

	* po/POTFILES.in:
	* po/POTFILES.skip: updated lists of files
	* libgda/gda-connection.h: added GDA_CONNECTION_FEATURE_XA_TRANSACTIONS
	* testing/html.[ch]:
	* testing/Makefile.am:
	* testing/gda-provider-status.c: new program to report about the
	implementation of database providers (generates an HTML report)
	this program is not installed by 'make install'
	* providers/mysql: more work on the MySQL provider (thanks to Carlos
	 Savoretti)

2008-06-04  Johannes Schmid <jhs gnome org>

	* libgda/sql-parser/Makefile.am:
	Added rules to generate gda-sql-parser-enum-types.[ch]


Added:
   trunk/testing/gda-provider-status.c
   trunk/testing/html.c
   trunk/testing/html.h
Modified:
   trunk/ChangeLog
   trunk/doc/C/   (props changed)
   trunk/doc/C/tmpl/   (props changed)
   trunk/doc/C/tmpl/gda-connection.sgml
   trunk/libgda/gda-config.c
   trunk/libgda/gda-connection.h
   trunk/libgda/sql-parser/   (props changed)
   trunk/libgda/sql-parser/Makefile.am
   trunk/po/POTFILES.in
   trunk/po/POTFILES.skip
   trunk/providers/mysql/gda-mysql-meta.c
   trunk/providers/mysql/gda-mysql-provider.c
   trunk/providers/mysql/gda-mysql-pstmt.c
   trunk/providers/mysql/gda-mysql-pstmt.h
   trunk/providers/mysql/gda-mysql-recordset.c
   trunk/providers/mysql/gda-mysql-recordset.h
   trunk/providers/mysql/gda-mysql-util.c
   trunk/providers/mysql/gda-mysql-util.h
   trunk/providers/mysql/libmain.c
   trunk/providers/postgres/gda-postgres-provider.c
   trunk/testing/   (props changed)
   trunk/testing/Makefile.am

Modified: trunk/doc/C/tmpl/gda-connection.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-connection.sgml	(original)
+++ trunk/doc/C/tmpl/gda-connection.sgml	Wed Jun  4 20:35:49 2008
@@ -492,6 +492,7 @@
 @GDA_CONNECTION_FEATURE_UPDATABLE_CURSOR: 
 @GDA_CONNECTION_FEATURE_USERS: 
 @GDA_CONNECTION_FEATURE_VIEWS: 
+ GDA_CONNECTION_FEATURE_XA_TRANSACTIONS: 
 @GDA_CONNECTION_FEATURE_LAST: 
 
 <!-- ##### FUNCTION gda_connection_supports_feature ##### -->

Modified: trunk/libgda/gda-config.c
==============================================================================
--- trunk/libgda/gda-config.c	(original)
+++ trunk/libgda/gda-config.c	Wed Jun  4 20:35:49 2008
@@ -1063,7 +1063,8 @@
  * @error: a place to store errors, or %NULL
  *
  * Get a pointer to the session-wide #GdaServerProvider for the
- * provider named @provider_name
+ * provider named @provider_name. The caller must not call g_object_unref() on the
+ * returned object.
  *
  * Returns: a pointer to the #GdaServerProvider, or %NULL if an error occurred
  */

Modified: trunk/libgda/gda-connection.h
==============================================================================
--- trunk/libgda/gda-connection.h	(original)
+++ trunk/libgda/gda-connection.h	Wed Jun  4 20:35:49 2008
@@ -98,6 +98,7 @@
 	GDA_CONNECTION_FEATURE_UPDATABLE_CURSOR,
 	GDA_CONNECTION_FEATURE_USERS,
 	GDA_CONNECTION_FEATURE_VIEWS,
+	GDA_CONNECTION_FEATURE_XA_TRANSACTIONS,
 
 	GDA_CONNECTION_FEATURE_LAST
 } GdaConnectionFeature;

Modified: trunk/libgda/sql-parser/Makefile.am
==============================================================================
--- trunk/libgda/sql-parser/Makefile.am	(original)
+++ trunk/libgda/sql-parser/Makefile.am	Wed Jun  4 20:35:49 2008
@@ -37,13 +37,50 @@
 	gda-statement-struct-unknown.h \
 	gda-statement-struct-util.h
 
+gda-sql-parser-enum-types.h: s-enum-types-h
+	@true
+
+s-enum-types-h: @REBUILD@ $(libgda_sql_parser_headers) Makefile
+	( cd $(srcdir) && glib-mkenums \
+	                --fhead "#ifndef __LIBGDA_SQL_PARSER_ENUM_TYPES_H__\n#define __LIBGDA_SQL_PARSER_ENUM_TYPES_H__\n\n#include <glib-object.h>\n\nG_BEGIN_DECLS\n" \
+			--fprod "/* enumerations from \"@filename \" */\n" \
+			--vhead "GType @enum_name _get_type (void);\n#define GDA_SQL_PARSER_TYPE_ ENUMSHORT@ (@enum_name _get_type())\n" 	\
+			--ftail "G_END_DECLS\n\n#endif /* __LIBGDA_ENUM_TYPES_H__ */" \
+		$(libgda_sql_parser_headers)) > tmp-gda-enum-types.h \
+	&& (cmp -s tmp-gda-enum-types.h gda-sql-parser-enum-types.h || cp tmp-gda-enum-types.h gda-sql-parser-enum-types.h ) \
+	&& rm -f tmp-gda-enum-types.h	\
+	&& echo timestamp > $(@F)
+
+gda-sql-parser-enum-types.c: s-enum-types-c
+	@true
+
+s-enum-types-c: @REBUILD@ $(libgda_sql_parser_headers) Makefile
+	( cd $(srcdir) && glib-mkenums \
+	                --fhead "#include <sql-parser/gda-sql-parser.h>\n" \
+	                --fhead "#include <sql-parser/gda-sql-statement.h>\n" \
+	                --fhead "#include <glib-object.h>" \
+                        --fprod "\n/* enumerations from \"@filename \" */" \
+			--vhead "GType\n enum_name@_get_type (void)\n{\n  static GType etype = 0;\n  if (etype == 0) {\n    static const G Type@Value values[] = {" 	\
+			--vprod "      { @VALUENAME@, \"@VALUENAME \", \"@valuenick \" }," \
+			--vtail "      { 0, NULL, NULL }\n    };\n    etype = g_ type@_register_static (\"@EnumName \", values);\n  }\n  return etype;\n}\n" \
+		$(libgda_sql_parser_headers)) > tmp-gda-enum-types.c \
+	&& (cmp -s tmp-gda-enum-types.c gda-sql-parser-enum-types.c || cp tmp-gda-enum-types.c gda-sql-parser-enum-types.c ) \
+	&& rm -f tmp-gda-enum-types.c \
+	&& echo timestamp > $(@F)
+
+# Generate the enums source code, with glib-mkenums:
+# This is based on the same Makefile.am stuff in pango:
+libgda_sql_parser_built_headers = gda-sql-parser-enum-types.h
+libgda_sql_parser_built_cfiles = gda-sql-parser-enum-types.c
 
 $(OBJECTS) $(libgda_sql_parser_4_0_la_OBJECTS): token_types.h
 libgda_sql_parserincludedir=$(includedir)/libgda-$(GDA_ABI_MAJOR_VERSION).$(GDA_ABI_MINOR_VERSION)/sql-parser
-libgda_sql_parserinclude_HEADERS=$(libgda_sql_parser_headers)
+libgda_sql_parserinclude_HEADERS=$(libgda_sql_parser_headers) $(libgda_sql_parser_built_headers)
 
 libgda_sql_parser_4_0_la_SOURCES = \
 	$(libgda_sql_parser_headers) \
+	$(libgda_sql_parser_built_headers) \
+	$(libgda_sql_parser_built_cfiles) \
 	gda-sql-parser-private.h \
 	parser.c \
         parser.h \
@@ -66,4 +103,9 @@
 EXTRA_DIST= parser.y delimiter.y lemon.c lempar.c gen_def.c parser_tokens.h
 
 CLEANFILES = parser.h parser.c parser.out delimiter.h delimiter.c delimiter.out token_types.h \
-	lemon$(EXEEXT_FOR_BUILD) gen_def$(EXEEXT_FOR_BUILD)
+	lemon$(EXEEXT_FOR_BUILD) gen_def$(EXEEXT_FOR_BUILD) \
+	$(libgda_sql_parser_built_headers) $(libgda_sql_parser_built_cfiles) \
+	gda-enum-types.h \
+	s-enum-types-h \
+	gda-enum-types.c \
+	s-enum-types-c

Modified: trunk/po/POTFILES.in
==============================================================================
--- trunk/po/POTFILES.in	(original)
+++ trunk/po/POTFILES.in	Wed Jun  4 20:35:49 2008
@@ -26,6 +26,7 @@
 libgda/gda-statement.c
 libgda/gda-util.c
 libgda/gda-value.c
+libgda/gda-xa-transaction.c
 libgda/handlers/gda-handler-bin.c
 libgda/handlers/gda-handler-boolean.c
 libgda/handlers/gda-handler-numerical.c

Modified: trunk/po/POTFILES.skip
==============================================================================
--- trunk/po/POTFILES.skip	(original)
+++ trunk/po/POTFILES.skip	Wed Jun  4 20:35:49 2008
@@ -2,6 +2,39 @@
 libgda/sqlite/sql-parser.c/lemon.c
 libgda/sqlite/sql-parser.c/lempar.c
 libgda/sqlite/sqlite-src/sqlite3.c
+providers/firebird/firebird_specs_dsn.xml.in
+providers/firebird/gda-firebird-blob-op.c
+providers/firebird/gda-firebird-provider.c
+providers/firebird/gda-firebird-recordset.c
+providers/firebird/libmain.c
+providers/freetds/freetds_specs_dsn.xml.in
+providers/freetds/gda-freetds-provider.c
+providers/freetds/gda-freetds-recordset.c
+providers/freetds/libmain.c
+providers/freetds/utils.c
+providers/ibmdb2/gda-ibmdb2-provider.c
+providers/ibmdb2/gda-ibmdb2-types.c
+providers/ibmdb2/ibmdb2_specs_dsn.xml.in
+providers/ibmdb2/libmain.c
+providers/ldap/gda-ldap-provider.c
+providers/ldap/gda-ldap-recordset.c
+providers/ldap/ldap_specs_dsn.xml.in
+providers/ldap/libmain.c
+providers/msql/gda-msql-provider.c
+providers/msql/gda-msql-recordset.c
+providers/msql/libmain.c
+providers/msql/msql_specs_dsn.xml.in
+providers/odbc/gda-odbc-provider.c
+providers/odbc/libmain.c
+providers/odbc/odbc_specs_dsn.xml.in
+providers/oracle/gda-oracle-blob-op.c
+providers/oracle/gda-oracle-provider.c
+providers/oracle/gda-oracle-recordset.c
+providers/oracle/libmain.c
+providers/oracle/oracle_specs_drop_index.xml.in
+providers/oracle/oracle_specs_drop_table.xml.in
+providers/oracle/oracle_specs_dsn.xml.in
+providers/oracle/utils.c 
 providers/skel-implementation/capi/capi_specs_create_table.xml.in
 providers/skel-implementation/capi/capi_specs_dsn.xml.in
 providers/skel-implementation/capi/gda-capi-blob-op.c
@@ -14,4 +47,13 @@
 providers/skel-implementation/models/gda-models-provider.c
 providers/skel-implementation/models/libmain.c
 providers/skel-implementation/models/models_specs_dsn.xml.in
+providers/sybase/gda-sybase-provider.c
+providers/sybase/gda-sybase-recordset.c
+providers/sybase/gda-sybase-types.c
+providers/sybase/libmain.c
 providers/sybase/main.c
+providers/sybase/sybase_specs_dsn.xml.in
+providers/sybase/utils.c
+providers/xbase/gda-xbase-provider.c
+providers/xbase/libmain.c
+providers/xbase/xbase_specs_dsn.xml.in 

Modified: trunk/providers/mysql/gda-mysql-meta.c
==============================================================================
--- trunk/providers/mysql/gda-mysql-meta.c	(original)
+++ trunk/providers/mysql/gda-mysql-meta.c	Wed Jun  4 20:35:49 2008
@@ -44,6 +44,7 @@
 typedef enum {
 	I_STMT_CATALOG,
         I_STMT_BTYPES,
+        I_STMT_SCHEMAS_ALL,
 } InternalStatementItem;
 
 
@@ -60,6 +61,7 @@
         /* I_STMT_SCHEMAS */
 
         /* I_STMT_SCHEMAS_ALL */
+	"SELECT catalog_name, schema_name, 'mysql', CASE schema_name WHEN 'information_schema' THEN TRUE WHEN 'mysql' THEN TRUE ELSE FALSE END   FROM information_schema.schemata",
 
         /* I_STMT_SCHEMA_NAMED */
 
@@ -170,15 +172,16 @@
 		       GdaMetaContext     *context,
 		       GError            **error)
 {
+	g_print ("*** %s\n", __func__);
 	GdaDataModel *model;
         gboolean retval;
-
         model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_CATALOG], NULL, error);
-        if (!model)
-                return FALSE;
-
-        retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
-        g_object_unref (model);
+        if (model == NULL)
+                retval = FALSE;
+	else {
+		retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
+		g_object_unref (G_OBJECT(model));
+	}
 
         return retval;
 }
@@ -191,20 +194,20 @@
 			 GError            **error)
 {
 	g_print ("*** %s\n", __func__);
-        GdaDataModel *model;
-        gboolean retval = TRUE;
 	GType col_types[] = {
                 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
                 G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_NONE
         };
+        GdaDataModel *model;
+        gboolean retval;
 	model = gda_connection_statement_execute_select_full (cnc, internal_stmt[I_STMT_BTYPES], NULL,
                                                               GDA_STATEMENT_MODEL_RANDOM_ACCESS, col_types, error);
-        if (!model)
-                return FALSE;
-
-        if (retval)
+        if (model == NULL)
+                retval = FALSE;
+	else {
                 retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
-        g_object_unref (G_OBJECT(model));
+		g_object_unref (G_OBJECT(model));
+	}
 
         return retval;
 }
@@ -229,23 +232,26 @@
 		     const GValue       *udt_catalog,
 		     const GValue       *udt_schema)
 {
-	GdaDataModel *model;
-	gboolean retval = TRUE;
-
-	/* set internal holder's values from the arguments */
-	gda_holder_set_value (gda_set_get_holder (i_set, "cat"), udt_catalog);
-	gda_holder_set_value (gda_set_get_holder (i_set, "schema"), udt_schema);
 
 	TO_IMPLEMENT;
-	/* fill in @model, with something like:
-	 * model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_UDT], i_set, error);
-	 */
-	if (!model)
-		return FALSE;
-	retval = gda_meta_store_modify_with_context (store, context, model, error);
-	g_object_unref (model);
 
-	return retval;
+	/* /\* set internal holder's values from the arguments *\/ */
+	/* gda_holder_set_value (gda_set_get_holder (i_set, "cat"), udt_catalog); */
+	/* gda_holder_set_value (gda_set_get_holder (i_set, "schema"), udt_schema); */
+	/* GdaDataModel *model; */
+	/* gboolean retval; */
+	/* /\* fill in @model, with something like: */
+	/*  * model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_UDT], i_set, error); */
+	/*  *\/ */
+	/* if (model == NULL) */
+	/* 	retval = FALSE; */
+	/* else { */
+	/* 	retval = gda_meta_store_modify_with_context (store, context, model, error); */
+	/* 	g_object_unref (G_OBJECT(model)); */
+	/* } */
+
+	/* return retval; */
+	return TRUE;
 }
 
 
@@ -361,16 +367,6 @@
 }
 
 gboolean
-_gda_mysql_meta_el_types (GdaServerProvider *prov, GdaConnection *cnc, 
-			  GdaMetaStore *store, GdaMetaContext *context, GError **error,
-			  const GValue *specific_name)
-{
-	TO_IMPLEMENT;
-	return TRUE;
-}
-
-
-gboolean
 _gda_mysql_meta__collations (GdaServerProvider  *prov,
 			     GdaConnection      *cnc, 
 			     GdaMetaStore       *store,
@@ -427,8 +423,20 @@
 			   GdaMetaContext     *context,
 			   GError            **error)
 {
-	TO_IMPLEMENT;
-	return TRUE;
+	g_print ("*** %s\n", __func__);
+	// TO_IMPLEMENT;
+
+	GdaDataModel *model;
+	gboolean retval;
+	model = gda_connection_statement_execute_select	(cnc, internal_stmt[I_STMT_SCHEMAS_ALL], i_set, error);
+	if (model == NULL)
+		retval = FALSE;
+	else {
+		retval = gda_meta_store_modify_with_context (store, context, model, error);
+		g_object_unref (G_OBJECT(model));
+	}
+
+	return retval;
 }
 
 gboolean

Modified: trunk/providers/mysql/gda-mysql-provider.c
==============================================================================
--- trunk/providers/mysql/gda-mysql-provider.c	(original)
+++ trunk/providers/mysql/gda-mysql-provider.c	Wed Jun  4 20:35:49 2008
@@ -158,6 +158,36 @@
 								  GdaServerProviderAsyncCallback   async_cb, 
 								  gpointer                         cb_data,
 								  GError                         **error);
+//
+
+/* distributed transactions */
+static gboolean gda_mysql_provider_xa_start    (GdaServerProvider         *provider,
+						GdaConnection             *cnc, 
+						const GdaXaTransactionId  *xid,
+						GError                   **error);
+
+static gboolean gda_mysql_provider_xa_end      (GdaServerProvider         *provider,
+						GdaConnection             *cnc, 
+						const GdaXaTransactionId  *xid,
+						GError                   **error);
+static gboolean gda_mysql_provider_xa_prepare  (GdaServerProvider         *provider,
+						GdaConnection             *cnc, 
+						const GdaXaTransactionId  *xid,
+						GError                   **error);
+
+static gboolean gda_mysql_provider_xa_commit   (GdaServerProvider        *provider,
+						GdaConnection            *cnc, 
+						const GdaXaTransactionId  *xid,
+						GError                   **error);
+static gboolean gda_mysql_provider_xa_rollback (GdaServerProvider         *provider,
+						GdaConnection             *cnc, 
+						const GdaXaTransactionId  *xid,
+						GError                   **error);
+
+static GList   *gda_mysql_provider_xa_recover  (GdaServerProvider  *provider,
+						GdaConnection      *cnc, 
+						GError            **error);
+//
 
 /* 
  * private connection data destroy 
@@ -238,7 +268,6 @@
         provider_class->meta_funcs._constraints_dom = _gda_mysql_meta__constraints_dom;
         provider_class->meta_funcs.constraints_dom = _gda_mysql_meta_constraints_dom;
         provider_class->meta_funcs._el_types = _gda_mysql_meta__el_types;
-        provider_class->meta_funcs.el_types = _gda_mysql_meta_el_types;
         provider_class->meta_funcs._collations = _gda_mysql_meta__collations;
         provider_class->meta_funcs.collations = _gda_mysql_meta_collations;
         provider_class->meta_funcs._character_sets = _gda_mysql_meta__character_sets;
@@ -267,6 +296,17 @@
         provider_class->meta_funcs.routine_col = _gda_mysql_meta_routine_col;
         provider_class->meta_funcs._routine_par = _gda_mysql_meta__routine_par;
         provider_class->meta_funcs.routine_par = _gda_mysql_meta_routine_par;
+	//
+
+	/* distributed transactions: if not supported, then provider_class->xa_funcs should be set to NULL */
+	provider_class->xa_funcs = g_new0 (GdaServerProviderXa, 1);
+	provider_class->xa_funcs->xa_start = gda_mysql_provider_xa_start;
+	provider_class->xa_funcs->xa_end = gda_mysql_provider_xa_end;
+	provider_class->xa_funcs->xa_prepare = gda_mysql_provider_xa_prepare;
+	provider_class->xa_funcs->xa_commit = gda_mysql_provider_xa_commit;
+	provider_class->xa_funcs->xa_rollback = gda_mysql_provider_xa_rollback;
+	provider_class->xa_funcs->xa_recover = gda_mysql_provider_xa_recover;
+	//
 }
 
 static void
@@ -489,19 +529,19 @@
 					     (use_ssl != NULL) ? TRUE : FALSE,
 					     &error);
 	if (!mysql) {
-		_gda_mysql_make_error (cnc, mysql, NULL);
+		_gda_mysql_make_error (cnc, mysql, NULL, NULL);
 		return FALSE;
 	}
 
 	MYSQL_STMT *mysql_stmt = mysql_stmt_init (mysql);
 	if (!mysql_stmt) {
-		_gda_mysql_make_error (cnc, mysql, NULL);
+		_gda_mysql_make_error (cnc, NULL, mysql_stmt, NULL);
 		return FALSE;
 	}
 
 	my_bool update_max_length = 1;
 	if (mysql_stmt_attr_set (mysql_stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (const void *) &update_max_length)) {
-		_gda_mysql_make_error (cnc, mysql, NULL);
+		_gda_mysql_make_error (cnc, NULL, mysql_stmt, NULL);
 		return FALSE;
 	}
 	
@@ -1155,7 +1195,7 @@
 	GSList *used_set = NULL;
 	gchar *sql = gda_mysql_provider_statement_to_sql
 		(provider, cnc, stmt, set,
-		 GDA_STATEMENT_SQL_PARAMS_AS_QMARK, &used_set, error);
+		 GDA_STATEMENT_SQL_PARAMS_AS_UQMARK, &used_set, error);
 
 	
 	if (!sql)
@@ -1163,7 +1203,7 @@
 
 	if (mysql_stmt_prepare (cdata->mysql_stmt, sql, strlen (sql))) {
 		GdaConnectionEvent *event = _gda_mysql_make_error
-			(cdata->cnc, cdata->mysql, NULL);
+			(cdata->cnc, NULL, cdata->mysql_stmt, NULL);
 		goto cleanup;
 	}
 
@@ -1224,7 +1264,7 @@
 	
 	if (mysql_stmt_prepare (cdata->mysql_stmt, sql, strlen (sql))) {
 		GdaConnectionEvent *event = _gda_mysql_make_error
-			(cdata->cnc, cdata->mysql, NULL);
+			(cdata->cnc, NULL, cdata->mysql_stmt, NULL);
 		ps = NULL;
 	} else {
 		ps = gda_mysql_pstmt_new (cdata->cnc, cdata->mysql, cdata->mysql_stmt);
@@ -1310,6 +1350,9 @@
 	/* optionnally reset the prepared statement if required by the API */
 	// TO_IMPLEMENT;
 	
+	//
+	g_print ("   %s: SQL=%s\n", __func__, _GDA_PSTMT(ps)->sql);
+	//
 	/* bind statement's parameters */
 	GSList *list;
 	GdaConnectionEvent *event = NULL;
@@ -1319,15 +1362,13 @@
 	char **param_values = g_new0 (char *, nb_params + 1);
         int *param_lengths = g_new0 (int, nb_params + 1);
         int *param_formats = g_new0 (int, nb_params + 1);
-	g_print ("NB=%d\n", nb_params);
+	g_print ("NB=%d, SQL=%s\n", nb_params, _GDA_PSTMT(ps)->sql);
+
+	MYSQL_BIND *mysql_bind_param = g_new0 (MYSQL_BIND, nb_params);
 	
-	for (i = 1, list = _GDA_PSTMT (ps)->param_ids; list; list = list->next, i++) {
+	for (i = 0, list = _GDA_PSTMT (ps)->param_ids; list; list = list->next, i++) {
 		const gchar *pname = (gchar *) list->data;
-		GdaHolder *h;
 
-		
-		g_print ("PNAME=%s\n", pname);
-		//		
 		/* find requested parameter */
 		if (!params) {
 			event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
@@ -1338,7 +1379,7 @@
 			break;
 		}
 
-		h = gda_set_get_holder (params, pname);
+		GdaHolder *h = gda_set_get_holder (params, pname);
 		if (!h) {
 			gchar *tmp = gda_alphanum_to_text (g_strdup (pname + 1));
 			if (tmp) {
@@ -1359,11 +1400,58 @@
 
 		/* actual binding using the C API, for parameter at position @i */
 		const GValue *value = gda_holder_get_value (h);
-		TO_IMPLEMENT;
+		// TO_IMPLEMENT;
+
+		if (value == NULL || gda_value_is_null (value)) {
+			param_values[i] = NULL;
+		} else if ((G_VALUE_TYPE(value) == G_TYPE_DATE) ||
+			   (G_VALUE_TYPE(value) == GDA_TYPE_TIME) ||
+			   (G_VALUE_TYPE(value) == GDA_TYPE_TIMESTAMP)) {
+			//
+			GdaHandlerTime *handler_time = (GdaHandlerTime *) gda_server_provider_get_data_handler_gtype
+				(provider, cnc, G_VALUE_TYPE(value));
+			g_assert (handler_time);
+			param_values[i] = gda_handler_time_get_no_locale_str_from_value (handler_time,
+											 value);
+			//
+			g_print ("--- TIME=%s\n", param_values[i]);
+		} else {
+			GdaDataHandler *data_handler = gda_server_provider_get_data_handler_gtype
+				(provider, cnc, G_VALUE_TYPE(value));
+			if (data_handler == NULL)
+				param_values[i] = NULL;
+			else
+				param_values[i] = gda_data_handler_get_str_from_value (data_handler,
+										       value);
+			g_print ("--- PV=%s\n", param_values[i]);
+
+			mysql_bind_param[i].buffer_type = MYSQL_TYPE_STRING;
+			mysql_bind_param[i].buffer = g_strdup (param_values[i]);
+			mysql_bind_param[i].buffer_length = strlen (param_values[i]);
+			mysql_bind_param[i].length = g_malloc0 (sizeof(unsigned long));
+
+		}
+		//
+		gchar *str = gda_value_stringify (value);
+		g_print ("   %s: %s=%s\n", __func__, pname, str);
+		g_free (str);
+		//
+
 	}
 		
+	if (mysql_stmt_bind_param (cdata->mysql_stmt, mysql_bind_param)) {
+		g_warning ("mysql_stmt_bind_param failed: %s\n", mysql_stmt_error (cdata->mysql_stmt));
+	}
+
+	ps->mysql_bind_param = mysql_bind_param;
+
 	if (event) {
 		gda_connection_add_event (cnc, event);
+
+		g_strfreev (param_values);
+		g_free (param_lengths);
+		g_free (param_formats);
+
 		return NULL;
 	}
 	
@@ -1375,7 +1463,7 @@
 	
 	GObject *return_value = NULL;
 	if (mysql_stmt_execute (cdata->mysql_stmt)) {
-		event = _gda_mysql_make_error (cnc, cdata->mysql, error);
+		event = _gda_mysql_make_error (cnc, NULL, cdata->mysql_stmt, error);
 	} else {
 		//	
 		/* execute prepared statement using C API depending on its kind */
@@ -1385,7 +1473,7 @@
 		    !g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "EXPLAIN", 7)) {
 			
 			if (mysql_stmt_store_result (cdata->mysql_stmt)) {
-				_gda_mysql_make_error (cnc, cdata->mysql, error);
+				_gda_mysql_make_error (cnc, NULL, cdata->mysql_stmt, error);
 			} else {
 				GdaDataModelAccessFlags flags;
 
@@ -1431,6 +1519,152 @@
 }
 
 /*
+ * starts a distributed transaction: put the XA transaction in the ACTIVE state
+ */
+static gboolean
+gda_mysql_provider_xa_start (GdaServerProvider         *provider,
+			     GdaConnection             *cnc, 
+			     const GdaXaTransactionId  *xid,
+			     GError                   **error)
+{
+	g_print ("*** %s\n", __func__);
+	MysqlConnectionData *cdata;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
+	g_return_val_if_fail (xid, FALSE);
+
+	cdata = (MysqlConnectionData*) 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_mysql_provider_xa_end (GdaServerProvider         *provider,
+			   GdaConnection             *cnc, 
+			   const GdaXaTransactionId  *xid,
+			   GError                   **error)
+{
+	g_print ("*** %s\n", __func__);
+	MysqlConnectionData *cdata;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
+	g_return_val_if_fail (xid, FALSE);
+
+	cdata = (MysqlConnectionData*) 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_mysql_provider_xa_prepare (GdaServerProvider         *provider,
+			       GdaConnection             *cnc, 
+			       const GdaXaTransactionId  *xid,
+			       GError                   **error)
+{
+	g_print ("*** %s\n", __func__);
+	MysqlConnectionData *cdata;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
+	g_return_val_if_fail (xid, FALSE);
+
+	cdata = (MysqlConnectionData*) 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_mysql_provider_xa_commit (GdaServerProvider         *provider,
+			      GdaConnection             *cnc, 
+			      const GdaXaTransactionId  *xid,
+			      GError                   **error)
+{
+	g_print ("*** %s\n", __func__);
+	MysqlConnectionData *cdata;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
+	g_return_val_if_fail (xid, FALSE);
+
+	cdata = (MysqlConnectionData*) 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_mysql_provider_xa_rollback (GdaServerProvider         *provider,
+				GdaConnection             *cnc, 
+				const GdaXaTransactionId  *xid,
+				GError                   **error)
+{
+	g_print ("*** %s\n", __func__);
+	MysqlConnectionData *cdata;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
+	g_return_val_if_fail (xid, FALSE);
+
+	cdata = (MysqlConnectionData*) 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_mysql_provider_xa_recover (GdaServerProvider  *provider,
+			       GdaConnection      *cnc,
+			       GError            **error)
+{
+	g_print ("*** %s\n", __func__);
+	MysqlConnectionData *cdata;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+	g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, NULL);
+
+	cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return NULL;
+
+	TO_IMPLEMENT;
+	return NULL;
+}
+
+/*
  * Free connection's specific data
  */
 static void

Modified: trunk/providers/mysql/gda-mysql-pstmt.c
==============================================================================
--- trunk/providers/mysql/gda-mysql-pstmt.c	(original)
+++ trunk/providers/mysql/gda-mysql-pstmt.c	Wed Jun  4 20:35:49 2008
@@ -2,7 +2,7 @@
  * Copyright (C) 2008 The GNOME Foundation.
  *
  * AUTHORS:
- *      TO_ADD: your name and email
+ *      Carlos Savoretti <csavoretti gmail com>
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -82,6 +82,10 @@
 	
 	/* initialize specific parts of @pstmt */
 	// TO_IMPLEMENT;
+	//
+	pstmt->mysql_bind_param = NULL;
+	pstmt->mysql_bind_result = NULL;
+	//
 }
 
 static void
@@ -94,6 +98,23 @@
 
 	/* free memory */
 	// TO_IMPLEMENT; /* free some specific parts of @pstmt */
+	//
+	gint i;
+	for (i = 0; i < g_slist_length (((GdaPStmt *) pstmt)->param_ids); ++i) {
+		g_free (pstmt->mysql_bind_param[i].buffer);
+		g_free (pstmt->mysql_bind_param[i].length);
+	}
+	g_free (pstmt->mysql_bind_param);
+	pstmt->mysql_bind_param = NULL;
+
+	for (i = 0; i < ((GdaPStmt *) pstmt)->ncols; ++i) {
+		g_free (pstmt->mysql_bind_result[i].buffer);
+		g_free (pstmt->mysql_bind_result[i].is_null);
+		g_free (pstmt->mysql_bind_result[i].length);
+	}
+	g_free (pstmt->mysql_bind_result);
+	pstmt->mysql_bind_result = NULL;
+	//
 
 	/* chain to parent class */
 	parent_class->finalize (object);

Modified: trunk/providers/mysql/gda-mysql-pstmt.h
==============================================================================
--- trunk/providers/mysql/gda-mysql-pstmt.h	(original)
+++ trunk/providers/mysql/gda-mysql-pstmt.h	Wed Jun  4 20:35:49 2008
@@ -43,6 +43,8 @@
 	GdaConnection  *cnc;
 	MYSQL          *mysql;
 	MYSQL_STMT     *mysql_stmt;
+	MYSQL_BIND     *mysql_bind_param;
+	MYSQL_BIND     *mysql_bind_result;
 	
 };
 

Modified: trunk/providers/mysql/gda-mysql-recordset.c
==============================================================================
--- trunk/providers/mysql/gda-mysql-recordset.c	(original)
+++ trunk/providers/mysql/gda-mysql-recordset.c	Wed Jun  4 20:35:49 2008
@@ -83,7 +83,6 @@
 	/* TO_ADD: specific information */
 	
 	MYSQL_STMT  *mysql_stmt;
-	MYSQL_BIND  *mysql_bind;    /* Array to bind columns in the result set. */
 
 	gint  chunk_size;    /* Number of rows to fetch at a time when iterating forward/backward. */
 	gint  chunks_read;   /* Number of times that we've iterated forward/backward. */
@@ -218,16 +217,6 @@
 		/* free specific information */
 		// TO_IMPLEMENT;
 		
-                gint i;
-                for (i = 0; i < (((GdaPModel *)recset)->prep_stmt)->ncols; ++i) {
-                        g_free (recset->priv->mysql_bind[i].buffer);
-                        g_free (recset->priv->mysql_bind[i].is_null);
-                        g_free (recset->priv->mysql_bind[i].length);
-                }
-                g_free (recset->priv->mysql_bind);
-                recset->priv->mysql_bind = NULL;
-
-		
 		g_free (recset->priv);
 		recset->priv = NULL;
 	}
@@ -277,9 +266,6 @@
         MysqlConnectionData *cdata;
         gint i;
 	GdaDataModelAccessFlags rflags;
-	
-	MYSQL_BIND *mysql_bind = NULL;
-	
 
         g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
         g_return_val_if_fail (ps != NULL, NULL);
@@ -326,7 +312,7 @@
 		MYSQL_RES *mysql_res = mysql_stmt_result_metadata (cdata->mysql_stmt);
 		MYSQL_FIELD *mysql_fields = mysql_fetch_fields (mysql_res);
 		
-		mysql_bind = g_new0 (MYSQL_BIND, GDA_PSTMT (ps)->ncols);
+		MYSQL_BIND *mysql_bind_result = g_new0 (MYSQL_BIND, GDA_PSTMT (ps)->ncols);
 		//		
 		/* fill GdaColumn's data */
 		for (i=0, list = _GDA_PSTMT (ps)->tmpl_columns; 
@@ -365,19 +351,19 @@
 			*/
 
 			
-			mysql_bind[i].buffer_type = field->type;
-			switch (mysql_bind[i].buffer_type) {
+			mysql_bind_result[i].buffer_type = field->type;
+			switch (mysql_bind_result[i].buffer_type) {
 			case MYSQL_TYPE_TINY:
 			case MYSQL_TYPE_SHORT:
 			case MYSQL_TYPE_INT24:
 			case MYSQL_TYPE_LONG:
 			case MYSQL_TYPE_YEAR:
-				mysql_bind[i].buffer = g_malloc0 (sizeof(int));
-				mysql_bind[i].is_null = g_malloc0 (sizeof(my_bool));
+				mysql_bind_result[i].buffer = g_malloc0 (sizeof(int));
+				mysql_bind_result[i].is_null = g_malloc0 (sizeof(my_bool));
 				break;
 			case MYSQL_TYPE_LONGLONG:
-				mysql_bind[i].buffer = g_malloc0 (sizeof(long long));
-				mysql_bind[i].is_null = g_malloc0 (sizeof(my_bool));
+				mysql_bind_result[i].buffer = g_malloc0 (sizeof(long long));
+				mysql_bind_result[i].is_null = g_malloc0 (sizeof(my_bool));
 				break;
 			case MYSQL_TYPE_NULL:
 				break;
@@ -385,13 +371,13 @@
 			case MYSQL_TYPE_DATE:
 			case MYSQL_TYPE_DATETIME:
 			case MYSQL_TYPE_TIMESTAMP:
-				mysql_bind[i].buffer = g_malloc0 (sizeof(MYSQL_TIME));
-				mysql_bind[i].is_null = g_malloc0 (sizeof(my_bool));
+				mysql_bind_result[i].buffer = g_malloc0 (sizeof(MYSQL_TIME));
+				mysql_bind_result[i].is_null = g_malloc0 (sizeof(my_bool));
 				break;
 			case MYSQL_TYPE_FLOAT:
 			case MYSQL_TYPE_DOUBLE:
-				mysql_bind[i].buffer = g_malloc0 (sizeof(double));
-				mysql_bind[i].is_null = g_malloc0 (sizeof(my_bool));
+				mysql_bind_result[i].buffer = g_malloc0 (sizeof(double));
+				mysql_bind_result[i].is_null = g_malloc0 (sizeof(my_bool));
 				break;
 			case MYSQL_TYPE_STRING:
 			case MYSQL_TYPE_VAR_STRING:
@@ -401,23 +387,25 @@
 			case MYSQL_TYPE_LONG_BLOB:
 			case MYSQL_TYPE_NEWDECIMAL:
 			case MYSQL_TYPE_BIT:
-				mysql_bind[i].buffer = g_malloc0 (field->max_length + 1);
-				mysql_bind[i].buffer_length = field->max_length + 1;
-				mysql_bind[i].length = g_malloc0 (sizeof(unsigned long));
+				mysql_bind_result[i].buffer = g_malloc0 (field->max_length + 1);
+				mysql_bind_result[i].buffer_length = field->max_length + 1;
+				mysql_bind_result[i].length = g_malloc0 (sizeof(unsigned long));
 				break;
 			default:
-				g_warning (_("Invalid column bind data type.\n"),
-					   mysql_bind[i].buffer_type);
+				g_warning (_("Invalid column bind data type. %d\n"),
+					   mysql_bind_result[i].buffer_type);
 			}
 			
 		}
 		
-                if (mysql_stmt_bind_result (cdata->mysql_stmt, mysql_bind)) {
+                if (mysql_stmt_bind_result (cdata->mysql_stmt, mysql_bind_result)) {
                         g_warning ("mysql_stmt_bind_result failed: %s\n", mysql_stmt_error (cdata->mysql_stmt));
                 }
 		
 		mysql_free_result (mysql_res);
-		
+
+		ps->mysql_bind_result = mysql_bind_result;
+
         }
 
 	/* determine access mode: RANDOM or CURSOR FORWARD are the only supported */
@@ -437,9 +425,6 @@
 	/* post init specific code */
 	// TO_IMPLEMENT;
 	
-	if (mysql_bind != NULL)
-		model->priv->mysql_bind = mysql_bind;
-	
 	model->priv->mysql_stmt = cdata->mysql_stmt;
 
 	((GdaPModel *) model)->advertized_nrows = mysql_stmt_affected_rows (cdata->mysql_stmt);
@@ -479,19 +464,19 @@
 	g_print ("*** %s -- %d -- %d\n", __func__,
 		 ((GdaPModel *) imodel)->prep_stmt->ncols, rownum);
 	
-	MYSQL_BIND *mysql_bind = imodel->priv->mysql_bind;
-	g_assert (mysql_bind);
+	MYSQL_BIND *mysql_bind_result = ((GdaMysqlPStmt *) ((GdaPModel *) imodel)->prep_stmt)->mysql_bind_result;
+	g_assert (mysql_bind_result);
 	
 	GdaPRow *prow = gda_prow_new (((GdaPModel *) imodel)->prep_stmt->ncols);
 	gint col;
 	for (col = 0; col < ((GdaPModel *) imodel)->prep_stmt->ncols; ++col) {
 		
-		GValue *value = gda_prow_get_value (prow, col);
-		GType type = ((GdaPModel *) imodel)->prep_stmt->types[col];
-		gda_value_reset_with_type (value, type);
-		
 		gint i = col;
 		
+		GValue *value = gda_prow_get_value (prow, i);
+		GType type = ((GdaPModel *) imodel)->prep_stmt->types[i];
+		gda_value_reset_with_type (value, type);
+		
 		int intvalue = 0;
 		long long longlongvalue = 0;
 		double doublevalue = 0.0;
@@ -500,14 +485,14 @@
 		my_bool is_null;
 		unsigned long length;
 		
-		switch (mysql_bind[i].buffer_type) {
+		switch (mysql_bind_result[i].buffer_type) {
 		case MYSQL_TYPE_TINY:
 		case MYSQL_TYPE_SHORT:
 		case MYSQL_TYPE_INT24:
 		case MYSQL_TYPE_LONG:
 		case MYSQL_TYPE_YEAR:
-			g_memmove (&intvalue, mysql_bind[i].buffer, sizeof(int));
-			g_memmove (&is_null, mysql_bind[i].is_null, sizeof(my_bool));
+			g_memmove (&intvalue, mysql_bind_result[i].buffer, sizeof(int));
+			g_memmove (&is_null, mysql_bind_result[i].is_null, sizeof(my_bool));
 			
 			if (type == G_TYPE_INT)
 				g_value_set_int (value, intvalue);
@@ -521,8 +506,8 @@
 			}
 			break;
 		case MYSQL_TYPE_LONGLONG:
-			g_memmove (&longlongvalue, mysql_bind[i].buffer, sizeof(long long));
-			g_memmove (&is_null, mysql_bind[i].is_null, sizeof(my_bool));
+			g_memmove (&longlongvalue, mysql_bind_result[i].buffer, sizeof(long long));
+			g_memmove (&is_null, mysql_bind_result[i].is_null, sizeof(my_bool));
 			break;
 		case MYSQL_TYPE_NULL:
 			g_value_unset (value);
@@ -531,8 +516,8 @@
 		case MYSQL_TYPE_DATE:
 		case MYSQL_TYPE_DATETIME:
 		case MYSQL_TYPE_TIMESTAMP:
-			g_memmove (&timevalue, mysql_bind[i].buffer, sizeof(MYSQL_TIME));
-			g_memmove (&is_null, mysql_bind[i].is_null, sizeof(my_bool));
+			g_memmove (&timevalue, mysql_bind_result[i].buffer, sizeof(MYSQL_TIME));
+			g_memmove (&is_null, mysql_bind_result[i].is_null, sizeof(my_bool));
 
 			if (type == GDA_TYPE_TIME) {
 				GdaTime time = {
@@ -566,8 +551,8 @@
 			break;
 		case MYSQL_TYPE_FLOAT:
 		case MYSQL_TYPE_DOUBLE:
-			g_memmove (&doublevalue, mysql_bind[i].buffer, sizeof(double));
-			g_memmove (&is_null, mysql_bind[i].is_null, sizeof(my_bool));
+			g_memmove (&doublevalue, mysql_bind_result[i].buffer, sizeof(double));
+			g_memmove (&is_null, mysql_bind_result[i].is_null, sizeof(my_bool));
 			
 			setlocale (LC_NUMERIC, "C");
 			if (type == G_TYPE_FLOAT)
@@ -589,8 +574,8 @@
 		case MYSQL_TYPE_LONG_BLOB:
 		case MYSQL_TYPE_NEWDECIMAL:
 		case MYSQL_TYPE_BIT:
-			g_memmove (&length, mysql_bind[i].length, sizeof(unsigned long));
-			strvalue = g_memdup (mysql_bind[i].buffer, length + 1);
+			g_memmove (&length, mysql_bind_result[i].length, sizeof(unsigned long));
+			strvalue = g_memdup (mysql_bind_result[i].buffer, length + 1);
 			
 			if (type == G_TYPE_STRING)
 				g_value_set_string (value, strvalue);
@@ -604,7 +589,7 @@
 				GdaBlob *blob = (GdaBlob *) gda_value_new_blob
 					((const guchar *) strvalue, (gulong) length);
 				gda_value_take_blob (value, blob);
-				gda_value_free (blob);
+				gda_value_free ((GValue *) blob);
 			} else if (type == G_TYPE_DOUBLE) {
 				setlocale (LC_NUMERIC, "C");
 				g_value_set_double (value, atof (strvalue));
@@ -617,9 +602,13 @@
 			break;
 		default:
 			g_warning (_("Invalid column bind data type. %d\n"),
-				   mysql_bind[i].buffer_type);
+				   mysql_bind_result[i].buffer_type);
 		}
-		
+		//
+		gchar *str = gda_value_stringify (value);
+		g_print ("   V=%s, %d\n", str, is_null);
+		g_free (str);
+		//		
 	}
 	return prow;
 }
@@ -670,7 +659,7 @@
 	gda_pmodel_take_row (model, *prow, rownum);
 	
 	/* if (model->nb_stored_rows == model->advertized_nrows) { */
-	/* 	g_print ("*** All the row have been converted..."); */
+	/* 	g_print ("  All the row have been converted..."); */
 	/* } */
 	
 

Modified: trunk/providers/mysql/gda-mysql-recordset.h
==============================================================================
--- trunk/providers/mysql/gda-mysql-recordset.h	(original)
+++ trunk/providers/mysql/gda-mysql-recordset.h	Wed Jun  4 20:35:49 2008
@@ -48,9 +48,13 @@
 	GdaPModelClass             parent_class;
 };
 
-GType         gda_mysql_recordset_get_type  (void) G_GNUC_CONST;
-GdaDataModel *gda_mysql_recordset_new       (GdaConnection *cnc, GdaMysqlPStmt *ps, GdaDataModelAccessFlags flags, 
-					    GType *col_types);
+GType
+gda_mysql_recordset_get_type  (void) G_GNUC_CONST;
+GdaDataModel *
+gda_mysql_recordset_new       (GdaConnection            *cnc,
+			       GdaMysqlPStmt            *ps,
+			       GdaDataModelAccessFlags   flags, 
+			       GType                    *col_types);
 
 G_END_DECLS
 

Modified: trunk/providers/mysql/gda-mysql-util.c
==============================================================================
--- trunk/providers/mysql/gda-mysql-util.c	(original)
+++ trunk/providers/mysql/gda-mysql-util.c	Wed Jun  4 20:35:49 2008
@@ -49,7 +49,8 @@
  */
 GdaConnectionEvent *
 _gda_mysql_make_error (GdaConnection  *cnc,
-		       MYSQL          *mysql, /* PGresult *pg_res, */
+		       MYSQL          *mysql,
+		       MYSQL_STMT     *mysql_stmt,
 		       GError        **error)
 {
 	/* GdaConnectionEvent *error_ev; */
@@ -114,6 +115,19 @@
 			(event_error, mysql_errno (mysql));
 		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_STATEMENT_EXEC_ERROR,
 			     mysql_sqlstate (mysql));
+		//
+		g_print ("%s: %s\n", __func__, mysql_error (mysql));
+		//
+	} else if (mysql_stmt) {
+		gda_connection_event_set_description
+			(event_error, mysql_stmt_error (mysql_stmt));
+		gda_connection_event_set_code
+			(event_error, mysql_stmt_errno (mysql_stmt));
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_STATEMENT_EXEC_ERROR,
+			     mysql_stmt_sqlstate (mysql_stmt));
+		//
+		g_print ("%s: %s\n", __func__, mysql_stmt_error (mysql_stmt));
+		//
 	} else {
 		gda_connection_event_set_description
 			(event_error, _("No description"));

Modified: trunk/providers/mysql/gda-mysql-util.h
==============================================================================
--- trunk/providers/mysql/gda-mysql-util.h	(original)
+++ trunk/providers/mysql/gda-mysql-util.h	Wed Jun  4 20:35:49 2008
@@ -31,6 +31,7 @@
 GdaConnectionEvent *
 _gda_mysql_make_error               (GdaConnection  *cnc,
 				     MYSQL          *mysql,
+				     MYSQL_STMT     *mysql_stmt,
 				     GError        **error);
 /* int */
 /* _gda_mysql_real_query_wrap          (GdaConnection  *cnc, */

Modified: trunk/providers/mysql/libmain.c
==============================================================================
--- trunk/providers/mysql/libmain.c	(original)
+++ trunk/providers/mysql/libmain.c	Wed Jun  4 20:35:49 2008
@@ -47,7 +47,7 @@
 const gchar *
 plugin_get_description (void)
 {
-	return _("Example provider for C API databases");
+	return _("Provider for MySQL databases");
 }
 
 gchar *

Modified: trunk/providers/postgres/gda-postgres-provider.c
==============================================================================
--- trunk/providers/postgres/gda-postgres-provider.c	(original)
+++ trunk/providers/postgres/gda-postgres-provider.c	Wed Jun  4 20:35:49 2008
@@ -1416,6 +1416,7 @@
         case GDA_CONNECTION_FEATURE_USERS:
         case GDA_CONNECTION_FEATURE_VIEWS:
         case GDA_CONNECTION_FEATURE_BLOBS:
+        case GDA_CONNECTION_FEATURE_XA_TRANSACTIONS:
                 return TRUE;
         case GDA_CONNECTION_FEATURE_NAMESPACES:
                 if (cnc) {

Modified: trunk/testing/Makefile.am
==============================================================================
--- trunk/testing/Makefile.am	(original)
+++ trunk/testing/Makefile.am	Wed Jun  4 20:35:49 2008
@@ -5,7 +5,7 @@
 	$(LIBGDA_CFLAGS)
 
 bin_PROGRAMS = gda-test-connection-4.0
-noinst_PROGRAMS = gda-test-blob
+noinst_PROGRAMS = gda-test-blob gda-provider-status
 
 gda_test_connection_4_0_SOURCES = \
         gda-test-connection.c
@@ -22,4 +22,13 @@
         $(LIBGDA_LIBS)
 
 
+gda_provider_status_SOURCES = \
+	html.h \
+	html.c \
+        gda-provider-status.c
+
+gda_provider_status_LDADD = \
+        $(top_builddir)/libgda/libgda-4.0.la \
+        $(LIBGDA_LIBS)
+
 EXTRA_DIST = 

Added: trunk/testing/gda-provider-status.c
==============================================================================
--- (empty file)
+++ trunk/testing/gda-provider-status.c	Wed Jun  4 20:35:49 2008
@@ -0,0 +1,475 @@
+/* GDA - provider status report
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ * 	Vivien Malerba <malerba gnome-db org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <libgda/libgda.h>
+#include <sql-parser/gda-sql-parser.h>
+#include "html.h"
+#include <libgda/gda-enum-types.h>
+
+/* options */
+gboolean ask_pass = FALSE;
+gchar *outfile = NULL;
+gchar *raw_prov = NULL;
+
+static GOptionEntry entries[] = {
+        { "no-password-ask", 'p', 0, G_OPTION_ARG_NONE, &ask_pass, "Don't ast for a password when it is empty", NULL },
+        { "prov", 'P', 0, G_OPTION_ARG_STRING, &raw_prov, "Provider to be used", NULL },
+        { "output-file", 'o', 0, G_OPTION_ARG_STRING, &outfile, "Output file", "output file"},
+        { NULL }
+};
+
+HtmlConfig *config;
+
+static GdaConnection *open_connection (const gchar *cnc_string, GError **error);
+static gboolean report_provider_status (GdaServerProvider *prov, GdaConnection *cnc);
+
+int
+main (int argc, char *argv[])
+{
+	GOptionContext *context;
+	GError *error = NULL;
+	int exit_status = EXIT_SUCCESS;
+	GSList *list, *cnc_list = NULL;
+	GdaServerProvider *prov = NULL;
+
+	context = g_option_context_new ("[DSN|connection string]...");
+	g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
+        if (!g_option_context_parse (context, &argc, &argv, &error)) {
+                g_print ("Can't parse arguments: %s\n", error->message);
+		exit_status = EXIT_FAILURE;
+		goto cleanup;
+        }
+        g_option_context_free (context);
+        gda_init ();
+	ask_pass = !ask_pass;
+
+	config = g_new0 (HtmlConfig, 1);
+	html_init_config (HTML_CONFIG (config));
+	config->index = html_file_new (HTML_CONFIG (config), 
+				       "index.html", "Providers status");
+	config->dir = g_strdup (".");
+
+	if (raw_prov) {
+		prov = gda_config_get_provider_object (raw_prov, &error);
+		if (!prov) {
+			g_print ("Can't load the '%s' provider: %s\n", raw_prov,
+				 error && error->message ? error->message : "No detail");
+			return EXIT_FAILURE;
+		}
+		if (!report_provider_status (prov, NULL)) {
+			exit_status = EXIT_FAILURE;
+			goto cleanup;
+
+		}
+	}
+
+	/* use connections if specified */
+	gint i;
+	for (i = 1; i < argc; i++) {
+		/* open connection */
+		GdaConnection *cnc;
+		cnc = open_connection (argv[i], &error);
+		if (!cnc) {
+			g_print ("Can't open connection to '%s': %s\n", argv[i],
+				 error && error->message ? error->message : "No detail");
+			exit_status = EXIT_FAILURE;
+			goto cleanup;
+		}
+		cnc_list = g_slist_append (cnc_list, cnc);
+	}
+	if (getenv ("GDA_SQL_CNC")) {
+		GdaConnection *cnc;
+		cnc = open_connection (getenv ("GDA_SQL_CNC"), &error);
+		if (!cnc) {
+			g_print ("Can't open connection defined by GDA_SQL_CNC: %s\n",
+				 error && error->message ? error->message : "No detail");
+			exit_status = EXIT_FAILURE;
+			goto cleanup;
+		}
+		cnc_list = g_slist_append (cnc_list, cnc);
+	}
+
+	
+	/* report provider's status for all the connections */
+	for (list = cnc_list; list; list = list->next) {
+		if (!report_provider_status (prov, GDA_CONNECTION (list->data))) {
+			exit_status = EXIT_FAILURE;
+			goto cleanup;
+
+		}
+	}
+
+	g_slist_foreach (HTML_CONFIG (config)->all_files, (GFunc) html_file_write, config);
+	
+	/* cleanups */
+ cleanup:
+	g_slist_foreach (cnc_list, (GFunc) g_object_unref, NULL);
+	g_slist_free (cnc_list);
+
+	return exit_status;
+}
+
+
+/*
+ * Open a connection
+ */
+static GdaConnection*
+open_connection (const gchar *cnc_string, GError **error)
+{
+	GdaConnection *cnc = NULL;
+
+	GdaDataSourceInfo *info;
+	gchar *user, *pass, *real_cnc, *real_provider, *real_auth_string = NULL;
+	gda_connection_string_split (cnc_string, &real_cnc, &real_provider, &user, &pass);
+	if (!real_cnc) {
+		g_free (user);
+		g_free (pass);
+		g_free (real_provider);
+		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR, 
+			     "Malformed connection string '%s'", cnc_string);
+		return NULL;
+	}
+
+	if (ask_pass) {
+		if (user && !*user) {
+			gchar buf[80];
+			g_print ("\tUsername for '%s': ", cnc_string);
+			if (scanf ("%80s", buf) == -1) {
+				g_free (real_cnc);
+				g_free (user);
+				g_free (pass);
+				g_free (real_provider);
+				g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR, 
+					     "No username for '%s'", cnc_string);
+				return NULL;
+			}
+			g_free (user);
+			user = g_strdup (buf);
+		}
+		if (pass && !*pass) {
+			gchar buf[80];
+			g_print ("\tPassword for '%s': ", cnc_string);
+			if (scanf ("%80s", buf) == -1) {
+				g_free (real_cnc);
+				g_free (user);
+				g_free (pass);
+				g_free (real_provider);
+				g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR, 
+					     "No password for '%s'", cnc_string);
+				return NULL;
+			}
+			g_free (pass);
+			pass = g_strdup (buf);
+		}
+		if (user || pass) {
+			gchar *s1;
+			s1 = gda_rfc1738_encode (user);
+			if (pass) {
+				gchar *s2;
+				s2 = gda_rfc1738_encode (pass);
+				real_auth_string = g_strdup_printf ("USERNAME=%s;PASSWORD=%s", s1, s2);
+				g_free (s2);
+			}
+			else
+				real_auth_string = g_strdup_printf ("USERNAME=%s", s1);
+			g_free (s1);
+		}
+	}
+	
+	info = gda_config_get_dsn (real_cnc);
+	if (info && !real_provider)
+		cnc = gda_connection_open_from_dsn (cnc_string, real_auth_string, 0, error);
+	else 
+		cnc = gda_connection_open_from_string (NULL, cnc_string, real_auth_string, 0, error);
+	
+	g_free (real_cnc);
+	g_free (user);
+	g_free (pass);
+	g_free (real_provider);
+	g_free (real_auth_string);
+
+	return cnc;
+}
+
+static gboolean
+report_provider_status (GdaServerProvider *prov, GdaConnection *cnc)
+{
+	gchar *str;
+	HtmlFile *file = config->index;
+
+	if (prov && cnc && (prov != gda_connection_get_provider_obj (cnc)))
+		/* ignoring connection as it has a different provider */
+		return TRUE;
+	g_assert (prov || cnc);
+
+	/* section */
+	if (cnc)
+		str = g_strdup_printf ("Report for connection '%s'", gda_connection_get_cnc_string (cnc));
+	else
+		str = g_strdup_printf ("Report for '%s' provider", gda_server_provider_get_name (prov));
+	html_add_header (HTML_CONFIG (config), file, str);
+	g_free (str);
+
+	/* provider info */
+	if (!prov)
+		prov = gda_connection_get_provider_obj (cnc);
+	xmlNodePtr table, tr, td, hnode;
+	GdaSqlParser *parser;
+
+	hnode = xmlNewChild (file->body, NULL, "h3", "General information");	
+	table = xmlNewChild (file->body, NULL, "table", NULL);
+	//xmlSetProp(table, "width", (xmlChar*)"100%");
+	tr = xmlNewChild (table, NULL, "tr", NULL);
+	xmlNewChild (tr, NULL, "th", "Property");
+	xmlNewChild (tr, NULL, "th", "Value");
+
+	tr = xmlNewChild (table, NULL, "tr", NULL);
+	xmlNewChild (tr, NULL, "td", "Provider's name");
+	xmlNewChild (tr, NULL, "td", gda_server_provider_get_name (prov));
+
+	tr = xmlNewChild (table, NULL, "tr", NULL);
+	xmlNewChild (tr, NULL, "td", "Provider's version");
+	xmlNewChild (tr, NULL, "td", gda_server_provider_get_version (prov));
+
+	tr = xmlNewChild (table, NULL, "tr", NULL);
+	xmlNewChild (tr, NULL, "td", "Provider's server version");
+	xmlNewChild (tr, NULL, "td", cnc ? gda_server_provider_get_server_version (prov, cnc) : "---");
+
+	parser = gda_server_provider_create_parser (prov, cnc);
+	tr = xmlNewChild (table, NULL, "tr", NULL);
+	xmlNewChild (tr, NULL, "td", "Creates its own SQL parser");
+	xmlNewChild (tr, NULL, "td", parser ? "Yes" : "No");
+	if (parser)
+		g_object_unref (parser);
+
+	/* supported features */
+	GdaConnectionFeature f;
+	hnode = xmlNewChild (file->body, NULL, "h3", "Supported features");
+	table = xmlNewChild (file->body, NULL, "table", NULL);
+
+	tr = xmlNewChild (table, NULL, "tr", NULL);
+	xmlNewChild (tr, NULL, "th", "Feature");
+	xmlNewChild (tr, NULL, "th", "Supported ?");
+	for (f = 0; f < GDA_CONNECTION_FEATURE_LAST; f++) {
+		GEnumValue *ev;
+
+		ev = g_enum_get_value ((GEnumClass *) g_type_class_ref (GDA_TYPE_CONNECTION_FEATURE), f);
+
+		tr = xmlNewChild (table, NULL, "tr", NULL);
+		xmlNewChild (tr, NULL, "td", ev->value_name);
+		xmlNewChild (tr, NULL, "td", gda_server_provider_supports_feature (prov, cnc, f) ? "Yes" : "No");
+	}
+	
+	/* supported operations */
+	GdaServerOperationType op;
+	hnode = xmlNewChild (file->body, NULL, "h3", "Supported server operations");
+	table = xmlNewChild (file->body, NULL, "table", NULL);
+
+	tr = xmlNewChild (table, NULL, "tr", NULL);
+	xmlNewChild (tr, NULL, "th", "Server operation");
+	xmlNewChild (tr, NULL, "th", "Supported ?");
+	for (op = 0; op < GDA_SERVER_OPERATION_NB; op++) {
+		GEnumValue *ev;
+
+		ev = g_enum_get_value ((GEnumClass *) g_type_class_ref (GDA_TYPE_SERVER_OPERATION_TYPE), op);
+
+		tr = xmlNewChild (table, NULL, "tr", NULL);
+		xmlNewChild (tr, NULL, "td", ev->value_name);
+		xmlNewChild (tr, NULL, "td", gda_server_provider_supports_operation (prov, cnc, op, NULL) ? "Yes" : "No");
+	}
+
+	/* virtual methods implementation */
+	gint i;
+	typedef void (*AFunc) (void);
+	typedef struct {
+		const gchar *name;
+		gboolean     should_be;
+		void       (*func) (void);
+	} ProvFunc;
+	GdaServerProviderClass *pclass = (GdaServerProviderClass*) 
+		G_OBJECT_GET_CLASS (prov);
+	ProvFunc fa[] = {
+		{"get_name", TRUE, (AFunc) pclass->get_name},
+		{"get_version", TRUE, (AFunc) pclass->get_version},
+		{"get_server_version", TRUE, (AFunc) pclass->get_server_version},
+		{"supports_feature", TRUE, (AFunc) pclass->supports_feature},
+		{"get_data_handler", TRUE, (AFunc) pclass->get_data_handler},
+		{"get_def_dbms_type", TRUE, (AFunc) pclass->get_def_dbms_type},
+		{"escape_string", TRUE, (AFunc) pclass->escape_string},
+		{"unescape_string", TRUE, (AFunc) pclass->unescape_string},
+		{"open_connection", TRUE, (AFunc) pclass->open_connection},
+		{"close_connection", TRUE, (AFunc) pclass->close_connection},
+		{"get_database", TRUE, (AFunc) pclass->get_database},
+		{"supports_operation", TRUE, (AFunc) pclass->supports_operation},
+		{"create_operation", FALSE, (AFunc) pclass->create_operation},
+		{"render_operation", FALSE, (AFunc) pclass->render_operation},
+		{"perform_operation", FALSE, (AFunc) pclass->perform_operation},
+		{"begin_transaction", FALSE, (AFunc) pclass->begin_transaction},
+		{"commit_transaction", FALSE, (AFunc) pclass->commit_transaction},
+		{"rollback_transaction", FALSE, (AFunc) pclass->rollback_transaction},
+		{"add_savepoint", FALSE, (AFunc) pclass->add_savepoint},
+		{"rollback_savepoint", FALSE, (AFunc) pclass->rollback_savepoint},
+		{"delete_savepoint", FALSE, (AFunc) pclass->delete_savepoint},
+		{"create_parser", FALSE, (AFunc) pclass->create_parser},
+		{"statement_to_sql", TRUE, (AFunc) pclass->statement_to_sql},
+		{"statement_prepare", TRUE, (AFunc) pclass->statement_prepare},
+		{"statement_execute", TRUE, (AFunc) pclass->statement_execute},
+	};
+	hnode = xmlNewChild (file->body, NULL, "h3", "Main virtual methods implementation");
+	table = xmlNewChild (file->body, NULL, "table", NULL);
+
+	tr = xmlNewChild (table, NULL, "tr", NULL);
+	xmlNewChild (tr, NULL, "th", "Server's virtual method");
+	xmlNewChild (tr, NULL, "th", "Implemented ?");
+
+	for (i = 0; i < sizeof (fa) / sizeof (ProvFunc); i++) {
+		gchar *str;
+		ProvFunc *pf = &(fa[i]);
+		tr = xmlNewChild (table, NULL, "tr", NULL);
+		str = g_strdup_printf ("%s ()", pf->name);
+		xmlNewChild (tr, NULL, "td", str);
+		g_free (str);
+		td = xmlNewChild (tr, NULL, "td", pf->func ? "Yes" : "No");
+		if (pf->should_be && !pf->func)
+			xmlSetProp(td, "class", (xmlChar*)"error");
+	}
+	
+	/* meta data implementation */
+	ProvFunc md[] = {
+		{"_info", TRUE, (AFunc) pclass->meta_funcs._info},
+ 		{"_btypes", TRUE, (AFunc) pclass->meta_funcs._btypes},
+		{"_udt", TRUE, (AFunc) pclass->meta_funcs._udt},
+		{"udt", TRUE, (AFunc) pclass->meta_funcs.udt},
+		{"_udt_cols", TRUE, (AFunc) pclass->meta_funcs._udt_cols},
+		{"udt_cols", TRUE, (AFunc) pclass->meta_funcs.udt_cols},
+		{"_enums", TRUE, (AFunc) pclass->meta_funcs._enums},
+		{"enums", TRUE, (AFunc) pclass->meta_funcs.enums},
+		{"_domains", TRUE, (AFunc) pclass->meta_funcs._domains},
+		{"domains", TRUE, (AFunc) pclass->meta_funcs.domains},
+		{"_constraints_dom", TRUE, (AFunc) pclass->meta_funcs._constraints_dom},
+		{"constraints_dom", TRUE, (AFunc) pclass->meta_funcs.constraints_dom},
+		{"_el_types", TRUE, (AFunc) pclass->meta_funcs._el_types},
+		{"el_types", TRUE, (AFunc) pclass->meta_funcs.el_types},
+		{"_collations", TRUE, (AFunc) pclass->meta_funcs._collations},
+		{"collations", TRUE, (AFunc) pclass->meta_funcs.collations},
+		{"_character_sets", TRUE, (AFunc) pclass->meta_funcs._character_sets},
+		{"character_sets", TRUE, (AFunc) pclass->meta_funcs.character_sets},
+		{"_schemata", TRUE, (AFunc) pclass->meta_funcs._schemata},
+		{"schemata", TRUE, (AFunc) pclass->meta_funcs.schemata},
+		{"_tables_views", TRUE, (AFunc) pclass->meta_funcs._tables_views},
+		{"tables_views", TRUE, (AFunc) pclass->meta_funcs.tables_views},
+		{"_columns", TRUE, (AFunc) pclass->meta_funcs._columns},
+		{"columns", TRUE, (AFunc) pclass->meta_funcs.columns},
+		{"_view_cols", TRUE, (AFunc) pclass->meta_funcs._view_cols},
+		{"view_cols", TRUE, (AFunc) pclass->meta_funcs.view_cols},
+		{"_constraints_tab", TRUE, (AFunc) pclass->meta_funcs._constraints_tab},
+		{"constraints_tab", TRUE, (AFunc) pclass->meta_funcs.constraints_tab},
+		{"_constraints_ref", TRUE, (AFunc) pclass->meta_funcs._constraints_ref},
+		{"constraints_ref", TRUE, (AFunc) pclass->meta_funcs.constraints_ref},
+		{"_key_columns", TRUE, (AFunc) pclass->meta_funcs._key_columns},
+		{"key_columns", TRUE, (AFunc) pclass->meta_funcs.key_columns},
+		{"_check_columns", TRUE, (AFunc) pclass->meta_funcs._check_columns},
+		{"check_columns", TRUE, (AFunc) pclass->meta_funcs.check_columns},
+		{"_triggers", TRUE, (AFunc) pclass->meta_funcs._triggers},
+		{"triggers", TRUE, (AFunc) pclass->meta_funcs.triggers},
+		{"_routines", TRUE, (AFunc) pclass->meta_funcs._routines},
+		{"routines", TRUE, (AFunc) pclass->meta_funcs.routines},
+		{"_routine_col", TRUE, (AFunc) pclass->meta_funcs._routine_col},
+		{"routine_col", TRUE, (AFunc) pclass->meta_funcs.routine_col},
+		{"_routine_par", TRUE, (AFunc) pclass->meta_funcs._routine_par},
+		{"routine_par", TRUE, (AFunc) pclass->meta_funcs.routine_par},
+	};
+	hnode = xmlNewChild (file->body, NULL, "h3", "Meta data methods implementation");
+	table = xmlNewChild (file->body, NULL, "table", NULL);
+
+	tr = xmlNewChild (table, NULL, "tr", NULL);
+	xmlNewChild (tr, NULL, "th", "Meta data's method");
+	xmlNewChild (tr, NULL, "th", "Implemented ?");
+
+	for (i = 0; i < sizeof (md) / sizeof (ProvFunc); i++) {
+		gchar *str;
+		ProvFunc *pf = &(md[i]);
+		tr = xmlNewChild (table, NULL, "tr", NULL);
+		str = g_strdup_printf ("%s ()", pf->name);
+		xmlNewChild (tr, NULL, "td", str);
+		g_free (str);
+		td = xmlNewChild (tr, NULL, "td", pf->func ? "Yes" : "No");
+		if (pf->should_be && !pf->func)
+			xmlSetProp(td, "class", (xmlChar*)"error");
+	}
+
+	/* distributed transaction implementation */
+	gboolean has_xa = gda_server_provider_supports_feature (prov, cnc, 
+			  GDA_CONNECTION_FEATURE_XA_TRANSACTIONS);
+	hnode = xmlNewChild (file->body, NULL, "h3", "Distributed transaction implementation");
+	if (pclass->xa_funcs) {
+		if (!has_xa) {
+			xmlNodePtr para;
+			para = xmlNewChild (file->body, NULL, "para", 
+					    "The provider has the 'xa_funcs' part but "
+					    "reports that distributed transactions are "
+					    "not supported.");
+			xmlSetProp(para, "class", (xmlChar*)"warning");
+		}
+			
+		ProvFunc dt[] = {
+			{"xa_start", TRUE, (AFunc) pclass->xa_funcs->xa_start},
+			{"xa_end", FALSE, (AFunc) pclass->xa_funcs->xa_end},
+			{"xa_prepare", TRUE, (AFunc) pclass->xa_funcs->xa_prepare},
+			{"xa_commit", TRUE, (AFunc) pclass->xa_funcs->xa_commit},
+			{"xa_rollback", TRUE, (AFunc) pclass->xa_funcs->xa_rollback},
+			{"xa_recover", TRUE, (AFunc) pclass->xa_funcs->xa_recover},
+		};
+		
+		table = xmlNewChild (file->body, NULL, "table", NULL);
+		
+		tr = xmlNewChild (table, NULL, "tr", NULL);
+		xmlNewChild (tr, NULL, "th", "Meta data's method");
+		xmlNewChild (tr, NULL, "th", "Implemented ?");
+		
+		for (i = 0; i < sizeof (dt) / sizeof (ProvFunc); i++) {
+			gchar *str;
+			ProvFunc *pf = &(dt[i]);
+			tr = xmlNewChild (table, NULL, "tr", NULL);
+			str = g_strdup_printf ("%s ()", pf->name);
+			xmlNewChild (tr, NULL, "td", str);
+			g_free (str);
+			td = xmlNewChild (tr, NULL, "td", pf->func ? "Yes" : "No");
+			if (pf->should_be && !pf->func)
+				xmlSetProp(td, "class", (xmlChar*)"error");
+		}
+	}
+	else {
+		if (has_xa) {
+			xmlNodePtr para;
+			para = xmlNewChild (file->body, NULL, "para", 
+					    "The provider does not have the 'xa_funcs' part but "
+					    "reports that distributed transactions are "
+					    "supported.");
+			xmlSetProp(para, "class", (xmlChar*)"warning");
+		}
+		xmlNewChild (tr, NULL, "para", "Not implemented");
+	}
+	
+
+	return TRUE;
+}

Added: trunk/testing/html.c
==============================================================================
--- (empty file)
+++ trunk/testing/html.c	Wed Jun  4 20:35:49 2008
@@ -0,0 +1,357 @@
+#include "html.h"
+#include <glib/gi18n-lib.h>
+
+static gint counter = 0;
+
+void
+html_init_config (HtmlConfig *config)
+{
+	g_assert (config);
+
+	config->nodes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+}
+
+HtmlFile *
+html_file_new (HtmlConfig *config, const gchar *name, const gchar *title)
+{
+	HtmlFile *file;
+	xmlNodePtr topnode, head, node;
+
+	file = g_new0 (HtmlFile, 1);
+	file->name = g_strdup (name);
+	file->doc = xmlNewDoc ("1.0");
+	topnode = xmlNewDocNode (file->doc, NULL, "html", NULL);
+	xmlDocSetRootElement (file->doc, topnode);
+
+	/* head */
+	head = xmlNewChild (topnode, NULL, "head", NULL);
+
+	node = xmlNewChild (head, NULL, "meta", NULL);
+	xmlSetProp(node, "content", (xmlChar*)"charset=ISO-8859-1");
+	xmlSetProp(node, "http-equiv", (xmlChar*)"content-type");
+
+	node = xmlNewChild (head, NULL, "title", title);
+	node = xmlNewChild (head, NULL, "style", 
+"body { "
+"       margin: 0px; padding: 0px;  border:0px; "
+"	font: 8pt/16pt georgia; "
+"	color: #555753; "
+"	margin: 5px; "
+"	}"
+""
+"a:visited, a:link { "
+"        text-decoration: none ; color: #4085cd; "
+"}"
+""
+"a:hover { "
+"        text-decoration: none; color: #FF0000;  "
+"}"
+""
+"p { "
+"	font: 8pt/16pt georgia; "
+"	margin-top: 0px; "
+"	text-align: justify;"
+"	}"
+"h2 { "
+"	font: italic normal 14pt georgia; "
+"	letter-spacing: 1px; "
+"	margin-bottom: 0px; "
+"	color: #7D775C;"
+"	}"
+""
+"table {"
+"	font-size: 8pt;"
+"	/*border: 1pt solid #A8E775;*/"
+"	padding: 3px;"
+"}"
+""
+"tr {"
+"	background:  #EFEEEF;"
+"}"
+""
+".none {"
+"        list-style : none;"
+"	padding-left: 0px;"
+"}"
+""
+".error {"
+"        color: #FF0000;"
+"        font: bold;"
+"        font-size: large;"
+"}"
+""
+".warning {"
+"        color: #ff9900;"
+"        font: bold;"
+"        font-size: medium;"
+"}"
+""
+".notice {"
+"        color: #22bb00;"
+"        font: bold;"
+"        /*font-size: medium;*/"
+"}"
+""
+"#inactive {"
+"        background-color: #CCCCFF;"
+"}"
+""
+".null {"
+"       color: lightblue;"
+"}"
+);
+
+	/* body */
+	node = xmlNewChild (topnode, NULL, "body", NULL);
+	file->body = node;
+
+	/* title */
+	node = xmlNewChild (file->body, NULL, "h1", title);
+	xmlSetProp(node, "class", (xmlChar*)"title");
+
+	/* toc */
+	file->toc = xmlNewChild (file->body, NULL, "ul", _("Table of contents"));
+	xmlSetProp(file->toc, "class", (xmlChar*)"none");
+
+	/* add to @config's list of files */
+	config->all_files = g_slist_append (config->all_files, file);
+
+	return file;
+}
+
+gboolean
+html_file_write (HtmlFile *file, HtmlConfig *config)
+{
+	gchar *str;
+
+	str = g_strdup_printf ("%s/%s", config->dir, file->name);
+	gint i;
+	i = xmlSaveFormatFile (str, file->doc, TRUE);
+	if (i == -1) 
+		g_warning (_("Error writing XML file %s"), str);
+	g_free (str);
+
+	return i!=-1;
+}
+
+void
+html_file_free  (HtmlFile *file)
+{
+	xmlFreeDoc (file->doc);
+	g_free (file->name);
+	g_free (file);
+}
+
+void
+html_declare_node (HtmlConfig *config, const gchar *path, xmlNodePtr node)
+{
+	html_declare_node_own (config, g_strdup (path), node);
+}
+
+void
+html_declare_node_own (HtmlConfig *config, gchar *path, xmlNodePtr node)
+{
+	xmlNodePtr enode;
+
+	enode = g_hash_table_lookup (config->nodes, path);
+	if (enode) {
+		g_warning ("Node path %s is already attributed", path);
+		g_free (path);
+		return;
+	}
+	
+	g_hash_table_insert (config->nodes, path, node);
+	/*g_print ("--- Added node @ %s\n", path);*/
+}
+
+/*
+ * if @link_to starts with a '/' then a # is prepended (internal link)
+ */
+void
+real_html_add_link_to_node (xmlNodePtr node, const gchar *text, const gchar *link_to)
+{
+	xmlNodePtr href;
+	gchar *tmp;
+
+	href = xmlNewNode (NULL, (xmlChar*)"a");
+	tmp = g_strdup_printf (" [%s] ", text);
+	xmlNodeSetContent (href, tmp);
+	g_free (tmp);
+	if (node->children) {
+		xmlNodePtr sibl;
+
+		sibl = node->children;
+		while (sibl && xmlNodeIsText (sibl))
+			sibl = sibl->next;
+		if (sibl)
+			xmlAddPrevSibling (sibl, href);
+		else
+			xmlAddChild (node, href);	
+	}
+	else
+		xmlAddChild (node, href);
+	if (*link_to == '/') {
+		tmp = g_strdup_printf ("#%s", link_to);
+		xmlSetProp(href, (xmlChar*)"href", tmp);
+		g_free (tmp);
+	}
+	else
+		xmlSetProp(href, (xmlChar*)"href", link_to);
+}
+
+void
+html_add_link_to_node (HtmlConfig *config, const gchar *nodepath, const gchar *text, const gchar *link_to)
+{
+	xmlNodePtr node;
+
+	node = g_hash_table_lookup (config->nodes, nodepath);
+	if (!node) {
+		g_warning ("Can't link non existant node '%s'", nodepath);
+		return;
+	}
+
+	real_html_add_link_to_node (node, text, link_to);
+}
+
+void
+html_add_to_toc (HtmlConfig *config, HtmlFile *file, const gchar *text, const gchar *link_to)
+{
+	xmlNodePtr li;
+
+	li = xmlNewChild (file->toc, NULL, "li", NULL);
+	real_html_add_link_to_node (li, text, link_to);
+}
+
+xmlNodePtr
+html_add_header (HtmlConfig *config, HtmlFile *file, const gchar *text)
+{
+	xmlNodePtr hnode, ntmp;
+	gchar *tmp;
+	
+	hnode = xmlNewChild (file->body, NULL, "h2", text);
+	tmp = g_strdup_printf ("/a/%d", counter++);
+	html_add_to_toc (config, file, text, tmp);
+	ntmp = xmlNewChild (hnode, NULL, "a", "");
+	xmlSetProp(ntmp, (xmlChar*)"name", tmp);
+	g_free (tmp);
+	
+	return hnode;
+}
+
+void
+html_mark_path_error (HtmlConfig *config, const gchar *nodepath)
+{
+	xmlNodePtr node;
+
+	node = g_hash_table_lookup (config->nodes, nodepath);
+	if (!node) {
+		g_warning ("Can't link non existant node '%s'", nodepath);
+		return;
+	}
+	html_mark_node_error (config, node);
+}
+
+void
+html_mark_node_error (HtmlConfig *config, xmlNodePtr node)
+{
+	xmlSetProp(node, "class", (xmlChar*)"error");
+}
+
+void
+html_mark_node_warning (HtmlConfig *config, xmlNodePtr node)
+{
+	xmlSetProp(node, "class", (xmlChar*)"warning");
+}
+
+void
+html_mark_node_notice (HtmlConfig *config, xmlNodePtr node)
+{
+	xmlSetProp(node, "class", (xmlChar*)"notice");
+}
+
+xmlNodePtr
+html_render_attribute_str (xmlNodePtr parent, const gchar *node_type, 
+		      const gchar *att_name, const gchar *att_val)
+{
+	xmlNodePtr node;
+	gchar *tmp;
+
+	tmp = g_strdup_printf ("%s = %s", att_name, att_val);
+	node = xmlNewChild (parent, NULL, node_type, tmp);
+	g_free (tmp);
+
+	return node;
+}
+
+xmlNodePtr
+html_render_attribute_bool (xmlNodePtr parent, const gchar *node_type, 
+			    const gchar *att_name, gboolean att_val)
+{
+	xmlNodePtr node;
+	gchar *tmp;
+
+	tmp = g_strdup_printf ("%s = %s", att_name, att_val ? _("Yes") : _("No"));
+	node = xmlNewChild (parent, NULL, node_type, tmp);
+	g_free (tmp);
+
+	return node;
+}
+
+xmlNodePtr
+html_render_data_model (xmlNodePtr parent, GdaDataModel *model)
+{
+	xmlNodePtr node, tr, td;
+        gint rows, cols, i;
+
+        g_return_val_if_fail (GDA_IS_DATA_MODEL (model), NULL);
+
+        node = xmlNewChild (parent, NULL, "table", "");
+
+	cols = gda_data_model_get_n_columns (model);
+	rows = gda_data_model_get_n_rows (model);
+
+        /* set the table structure */
+	tr = xmlNewChild (node, NULL, "tr", NULL);
+        for (i = 0; i < cols; i++) {
+                GdaColumn *column;
+
+                column = gda_data_model_describe_column (model, i);
+                if (!column) {
+                        xmlFreeNode (node);
+                        return NULL;
+                }
+
+                td = xmlNewChild (tr, NULL, "th", gda_column_get_name (column));
+        }
+	
+	/* add the model data to the XML output */
+        if (rows > 0) {
+                gint r, c;
+
+                for (r = 0; r < rows; r++) {
+			tr = xmlNewChild (node, NULL, "tr", "");
+                        for (c = 0 ; c < cols; c++) {
+                                GValue *value;
+                                gchar *str;
+
+                                value = (GValue *) gda_data_model_get_value_at (model, c, r);
+				if (!value || gda_value_is_null (value)) {
+					xmlNodePtr p;
+					td = xmlNewChild (tr, NULL, "td", NULL);
+					p = xmlNewChild (td, NULL, "p", "NULL");
+					xmlSetProp(p, "class", (xmlChar*)"null");
+				}
+				else {
+					if (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN)
+						str = g_strdup (g_value_get_boolean (value) ? "TRUE" : "FALSE");
+					else
+						str = gda_value_stringify (value);
+					td = xmlNewChild (tr, NULL, "td", str);
+					g_free (str);
+				}
+                        }
+                }
+        }
+
+        return node;
+}

Added: trunk/testing/html.h
==============================================================================
--- (empty file)
+++ trunk/testing/html.h	Wed Jun  4 20:35:49 2008
@@ -0,0 +1,46 @@
+#include <glib.h>
+#include <libxml/tree.h>
+#include <libgda/libgda.h>
+
+typedef struct {
+	gchar      *name;
+	xmlDocPtr   doc;
+	xmlNodePtr  body;
+	xmlNodePtr  toc;
+} HtmlFile;
+
+typedef struct {
+	HtmlFile          *index;
+	
+	GHashTable        *nodes; /* key=node name, value=xmlNodePtr */
+	gchar             *dir;
+	GSList            *all_files;
+} HtmlConfig;
+#define HTML_CONFIG(x) ((HtmlConfig*)(x))
+
+
+/*
+ * HTML output files manipulation
+ * Files are built as XML files and then printed at the end
+ */
+void       html_init_config           (HtmlConfig *config);
+HtmlFile  *html_file_new              (HtmlConfig *config, 
+				       const gchar *name, const gchar *title);
+gboolean   html_file_write            (HtmlFile *file, HtmlConfig *config);
+void       html_file_free             (HtmlFile *file);
+void       html_declare_node          (HtmlConfig *config, const gchar *path, xmlNodePtr node);
+void       html_declare_node_own      (HtmlConfig *config, gchar *path, xmlNodePtr node);
+void       html_add_link_to_node      (HtmlConfig *config, const gchar *nodepath,
+				       const gchar *text, const gchar *link_to);
+void       html_add_to_toc            (HtmlConfig *config, HtmlFile *file, const gchar *text, const gchar *link_to);
+xmlNodePtr html_add_header            (HtmlConfig *config, HtmlFile *file, const gchar *text);
+void       html_mark_path_error       (HtmlConfig *config, const gchar *nodepath);
+void       html_mark_node_error       (HtmlConfig *config, xmlNodePtr node);
+void       html_mark_node_warning     (HtmlConfig *config, xmlNodePtr node);
+void       html_mark_node_notice      (HtmlConfig *config, xmlNodePtr node);
+
+xmlNodePtr html_render_attribute_str  (xmlNodePtr parent, const gchar *node_type, 
+				       const gchar *att_name, const gchar *att_val);
+xmlNodePtr html_render_attribute_bool (xmlNodePtr parent, const gchar *node_type, 
+				       const gchar *att_name, gboolean att_val);
+xmlNodePtr html_render_data_model     (xmlNodePtr parent, GdaDataModel *model);



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