libgda r3180 - in trunk: . doc/C doc/C/tmpl libgda libgda-xslt libgda/sql-parser libgda/sqlite po providers/mysql providers/postgres tests tests/data-models tests/multi-threading tests/providers tools



Author: vivien
Date: Thu Jul 17 20:25:20 2008
New Revision: 3180
URL: http://svn.gnome.org/viewvc/libgda?rev=3180&view=rev

Log:
2008-07-17  Vivien Malerba <malerba gnome-db org>

	* libgda-xslt/Makefile.am:
	* configure.in:
	* libgda/gda-config.c: applied patches for bug #541991 (thanks to Cygwin Ports maintainer)
	* providers/mysql/libmain.c:
	* providers/mysql/gda-mysql-meta.c:
	* providers/mysql/gda-mysql-provider.c:
	* providers/mysql/gda-mysql-meta.h:
	* providers/mysql/gda-mysql-parser.c: another set of improvements to the MySQL provider
	(thanks to Carlos Savoretti)
	* tests/Makefile.am:
	* tests/multi-threading/*:
	* configure.in:
	* libgda/gda-mutex.[ch]:
	* libgda/Makefile.am:
	* libgda/libgda.h.in: created the GdaMutex mutex which is dynamically
	allocated and recursive
	* libgda/Makefile.am:
	* libgda/libgda.h.in:
	* libgda/gda-lockable.[ch]: new GdaLockable interface to be used to lock objects
	* sql-parser/gda-sql-parser-private.h:
	* libgda/sql-parser/gda-sql-parser.c:
	* libgda/gda-connection.c: implement the GdaLockable interface (GdaSqlParser no
	uses a GdaMutex per GdaSqlParser instance instead of a global recursive mutex)
	* tests/Makefile.am
	* tests/multi-threading/: new multi threaded environment tests
	* tests/data-models/check_data_proxy.c: correctly specify the GType type
	in functions using an ellipse for 64 bits OS
	* tests/data-models/Makefile.am:
	* tests/data-models/data1.xml:
	* tests/data-models/check_model_copy.c: test data model copy
	* tests/data-models/check_model_import.c: also test data models in current
	directory
	* libgda/gda-set.c: make gda_set_real_add_holder() show a warning if the data
	holder to add does not have any ID instead of crash
	* libgda/gda-data-model-iter.c: use ID attribute of data model column
	* libgda/gda-data-comparator.c: corrected the "diff_computed" signal accumulator
	* libgda/gda-data-model.c: better determmine column and data model names when exporting
	to XML, and corrected a bug in the data model import function
	* doc/C: doc. updates
	* tools/gda-sql.ico:
	* tools/gda-sql-res.rc:
	* tools/Makefile.am: added an icon in the gda-sql executable when compiling for a
	Windows platform


Added:
   trunk/doc/C/tmpl/gda-lockable.sgml
   trunk/doc/C/tmpl/gda-mutex.sgml
   trunk/libgda/gda-lockable.c
   trunk/libgda/gda-lockable.h
   trunk/libgda/gda-meta-struct-io.c
   trunk/libgda/gda-meta-struct-private.h
   trunk/libgda/gda-mutex.c
   trunk/libgda/gda-mutex.h
   trunk/tests/data-models/check_model_copy.c
   trunk/tests/data-models/data1.xml
   trunk/tests/dbstruct.xml
   trunk/tests/gda-ddl-creator.c
   trunk/tests/gda-ddl-creator.h
   trunk/tests/multi-threading/   (props changed)
   trunk/tests/multi-threading/Makefile.am
   trunk/tests/multi-threading/check_cnc_lock.c
   trunk/tests/multi-threading/check_mutex.c
   trunk/tests/multi-threading/check_parser.c
   trunk/tests/multi-threading/common.c
   trunk/tests/multi-threading/common.h
   trunk/tests/multi-threading/testdb.sql
   trunk/tests/test-ddl-creator.c
   trunk/tools/gda-sql-res.rc
   trunk/tools/gda-sql.ico   (contents, props changed)
Modified:
   trunk/ChangeLog
   trunk/configure.in
   trunk/doc/C/libgda-4.0-docs.sgml
   trunk/doc/C/libgda-4.0-sections.txt
   trunk/doc/C/limitations.xml
   trunk/doc/C/prov-writing.xml
   trunk/doc/C/tmpl/gda-connection.sgml
   trunk/doc/C/tmpl/gda-meta-store.sgml
   trunk/doc/C/tmpl/gda-meta-struct.sgml
   trunk/doc/C/tmpl/gda-server-provider.sgml
   trunk/libgda-xslt/Makefile.am
   trunk/libgda/Makefile.am
   trunk/libgda/gda-config.c
   trunk/libgda/gda-connection-private.h
   trunk/libgda/gda-connection.c
   trunk/libgda/gda-connection.h
   trunk/libgda/gda-data-comparator.c
   trunk/libgda/gda-data-model-iter.c
   trunk/libgda/gda-data-model.c
   trunk/libgda/gda-meta-store.c
   trunk/libgda/gda-meta-store.h
   trunk/libgda/gda-meta-struct.c
   trunk/libgda/gda-meta-struct.h
   trunk/libgda/gda-server-provider.c
   trunk/libgda/gda-server-provider.h
   trunk/libgda/gda-set.c
   trunk/libgda/libgda.h.in
   trunk/libgda/sql-parser/gda-sql-parser-private.h
   trunk/libgda/sql-parser/gda-sql-parser.c
   trunk/libgda/sql-parser/gda-sql-parser.h
   trunk/libgda/sqlite/gda-sqlite-provider.c
   trunk/po/POTFILES.in
   trunk/po/POTFILES.skip
   trunk/providers/mysql/gda-mysql-meta.c
   trunk/providers/mysql/gda-mysql-meta.h
   trunk/providers/mysql/gda-mysql-parser.c
   trunk/providers/mysql/gda-mysql-provider.c
   trunk/providers/mysql/libmain.c
   trunk/providers/postgres/gda-postgres-provider.c
   trunk/tests/   (props changed)
   trunk/tests/Makefile.am
   trunk/tests/data-models/   (props changed)
   trunk/tests/data-models/Makefile.am
   trunk/tests/data-models/check_data_proxy.c
   trunk/tests/data-models/check_model_import.c
   trunk/tests/providers/Makefile.am
   trunk/tests/providers/TYPES_SCHEMA_SQLite.xml
   trunk/tools/Makefile.am

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Thu Jul 17 20:25:20 2008
@@ -143,10 +143,9 @@
 case "$host" in
 *-cygwin*)
     AC_MSG_RESULT([Win32 - cygwin])
-    platform_win32=yes
     NO_UNDEFINED='-no-undefined'
     SOPREFIX='cyg'
-    LIBTOOL_EXPORT_OPTIONS=
+    LIBTOOL_EXPORT_OPTIONS='-export-symbols-regex "^[[^_]].*"'
     linklibext=".dll.a"
     AC_MSG_RESULT([Win32])
     ;;
@@ -158,6 +157,7 @@
     SOPREFIX='lib'
     LIBTOOL_EXPORT_OPTIONS=
     linklibext=".dll.a"
+    AC_SUBST(WINDRES)
     ;;
 *-*-darwin*)
     dnl Darwin based distributions (including Mac OS X)
@@ -1262,6 +1262,7 @@
 tests/providers/Makefile
 tests/value-holders/Makefile
 tests/meta-store/Makefile
+tests/multi-threading/Makefile
 doc/Makefile
 doc/C/Makefile
 doc/C/libgda-4.0.types

Modified: trunk/doc/C/libgda-4.0-docs.sgml
==============================================================================
--- trunk/doc/C/libgda-4.0-docs.sgml	(original)
+++ trunk/doc/C/libgda-4.0-docs.sgml	Thu Jul 17 20:25:20 2008
@@ -42,6 +42,8 @@
 <!ENTITY libgda-GdaCommand SYSTEM "xml/gda-command.xml">
 <!ENTITY libgda-config SYSTEM "xml/gda-config.xml">
 <!ENTITY libgda-GdaConnection SYSTEM "xml/gda-connection.xml">
+<!ENTITY libgda-GdaMutex SYSTEM "xml/gda-mutex.xml">
+<!ENTITY libgda-GdaLockable SYSTEM "xml/gda-lockable.xml">
 <!ENTITY libgda-GdaThreader SYSTEM "xml/gda-threader.xml">
 <!ENTITY libgda-GdaDataModelArray SYSTEM "xml/gda-data-model-array.xml">
 <!ENTITY libgda-GdaDataModelBdb SYSTEM "xml/gda-data-model-bdb.xml">
@@ -903,6 +905,8 @@
       &libgda-log;
       &libgda-quark-list;
       &libgda-GdaDataModelRow;
+      &libgda-GdaMutex;
+      &libgda-GdaLockable;
       &libgda-GdaThreader;
     </chapter>
   </part>

Modified: trunk/doc/C/libgda-4.0-sections.txt
==============================================================================
--- trunk/doc/C/libgda-4.0-sections.txt	(original)
+++ trunk/doc/C/libgda-4.0-sections.txt	Thu Jul 17 20:25:20 2008
@@ -158,6 +158,10 @@
 GdaConnectionMetaType
 gda_connection_get_meta_store_data
 gda_connection_value_to_sql_string
+<SUBSECTION>
+gda_connection_lock
+gda_connection_trylock
+gda_connection_unlock
 <SUBSECTION Standard>
 GDA_CONNECTION
 GDA_CONNECTION_CLASS
@@ -522,6 +526,7 @@
 GdaServerProviderError
 GdaServerProviderMeta
 GdaServerProviderAsyncCallback
+GdaServerProviderExecCallback
 gda_server_provider_get_name
 gda_server_provider_get_version
 gda_server_provider_get_server_version
@@ -648,6 +653,17 @@
 </SECTION>
 
 <SECTION>
+<FILE>gda-mutex</FILE>
+<TITLE>GdaMutex</TITLE>
+GdaMutex
+gda_mutex_new
+gda_mutex_lock
+gda_mutex_trylock
+gda_mutex_unlock
+gda_mutex_free
+</SECTION>
+
+<SECTION>
 <FILE>gda-threader</FILE>
 <TITLE>GdaThreader</TITLE>
 GdaThreader
@@ -1150,6 +1166,10 @@
 gda_sql_parser_parse_string
 gda_sql_parser_parse_string_as_batch
 gda_sql_parser_parse_file_as_batch
+<SUBSECTION>
+gda_sql_parser_lock
+gda_sql_parser_trylock
+gda_sql_parser_unlock
 <SUBSECTION Standard>
 GDA_IS_SQL_PARSER
 GDA_SQL_PARSER
@@ -1479,3 +1499,18 @@
 GDA_TYPE_DATA_COMPARATOR
 gda_data_comparator_get_type
 </SECTION>
+
+<SECTION>
+<FILE>gda-lockable</FILE>
+<TITLE>GdaLockable</TITLE>
+GdaLockable
+gda_lockable_lock
+gda_lockable_trylock
+gda_lockable_unlock
+<SUBSECTION Standard>
+GDA_LOCKABLE
+GDA_LOCKABLE_GET_CLASS
+GDA_IS_LOCKABLE
+GDA_TYPE_LOCKABLE
+gda_lockable_get_type
+</SECTION>

Modified: trunk/doc/C/limitations.xml
==============================================================================
--- trunk/doc/C/limitations.xml	(original)
+++ trunk/doc/C/limitations.xml	Thu Jul 17 20:25:20 2008
@@ -4,21 +4,39 @@
   <sect1 id="limitations_global"><title>Global limitations</title>
     <para>
       &LIBGDA;'s global limitations are:
-      <sect2 id="threads"><title>Multi threading</title>
-	<para>&LIBGDA; is not thread safe. However it supports working with threads as long as
-	  any object created by the API is used by one single thread (that is there is no
-	  situation when two threads try to acces the same object at the same time).
+      <sect2 id="threads"><title>Multi threaded environment</title>
+	<para>&LIBGDA; is not thread safe. However it supports working with threads as long as any object 
+	  (except otherwise stated) created by the API is used by one single thread (that is there is no
+	  situation when two threads try to acces the same object at the same time). Exceptions are:
+	  <itemizedlist>
+	    <listitem><para>&LIBGDA;'s <link linkend="init_config">configuration</link> can be accessed from any thread</para></listitem>
+	    <listitem><para>Any object which implements the <link linkend="GdaLockable">GdaLockable</link> interface 
+		can be accessed from any thread. However 
+		one can use the <link linkend="gda-lockable-lock">gda_lockable_lock()</link> method to specifically 
+		lock an object's usage (especially when getting and
+		setting properties before or after calling methods).</para></listitem>
+	    <listitem><para>Any <link linkend="GdaConnection">GdaConnection</link> object can be accessed from any thread 
+		(that object implements the <link linkend="GdaLockable">GdaLockable</link> interface). Also
+		some database providers may impose other limitations (inherited from the database's specific client APIs)
+		such as only one thread can use the connection object, or even that only one thread can use the database
+		provider.</para></listitem>
+	  </itemizedlist>
 	</para>
-	<para>For example it is safe to start a thread and in that thread create a connection
-	  which is only used in that thread.</para>
+	
+	<para>Note that multi threading support is still at an early stage and may contain bugs</para>
       </sect2>
     </para>
   </sect1>
 
   <sect1 id="limitations_mysql"><title>For MySQL</title>
-    <para>
-      The following limitations apply to MySQL databases accessed via Libgda: none.
-    </para>
+    <sect2><title>Multi threaded environment</title>
+      <para>
+	If MySQL client was not compiled with the <option>--enable-thread-safe-client</option> flag, 
+	then the database provider will only allow
+	connections to be opened from the thread which initializes &LIBGDA;. Otherwise there is no limitation.
+      </para>
+    </sect2>
+
   </sect1>
 
   <sect1 id="limitations_oracle"><title>For Oracle</title>
@@ -58,6 +76,14 @@
 	The <link linkend="gda-connection-statement-execute-non-select">gda_connection_statement_execute_non_select()</link>'s last_insert_row attribute will return a <link linkend="GdaSet">GdaSet</link> object only if the table has OIDs.
       </para>
     </sect2>
+
+    <sect2><title>Multi threaded environment</title>
+      <para>
+	If PostgreSQL was not compiled with the <option>--enable-thread-safety</option> flag, 
+	then the database provider will only allow
+	connections to be opened from the thread which initializes &LIBGDA;. Otherwise there is no limitation.
+      </para>
+    </sect2>
   </sect1>
 
   <sect1 id="limitations_sqlite"><title>For SQLite</title>
@@ -69,6 +95,14 @@
 	The <link linkend="gda-connection-statement-execute-non-select">gda_connection_statement_execute_non_select()</link>'s last_insert_row attribute uses the hidden "_ROWID_" column for each table, but it may fail if the table has a column with the same name.
       </para>
     </sect2>
+
+    <sect2><title>Multi threaded environment</title>
+      <para>
+	While waiting for the SQLite 3.6 (and the <option>SQLITE_CONFIG_SERIALIZED</option> flag), 
+	a connection object can only be used from the thread which created it (see
+	SQLite's <ulink url="http://www.sqlite.org/cvstrac/wiki?p=MultiThreading";>documentation about threads</ulink>).
+      </para>
+    </sect2>
   </sect1>
   
 </chapter>

Modified: trunk/doc/C/prov-writing.xml
==============================================================================
--- trunk/doc/C/prov-writing.xml	(original)
+++ trunk/doc/C/prov-writing.xml	Thu Jul 17 20:25:20 2008
@@ -49,6 +49,31 @@
   </sect1>
 
   <sect1>
+    <title>Multi threaded environment</title>
+    <para>
+      Each database provider should be useable in a multi threaded environment, even if they impose some restrictions
+      as to how they can be used in such an environment. The &LIBGDA;'s framework provides some locking mechanism which
+      is:
+      <itemizedlist>
+	<listitem><para>if multi threading cannot be supported at all (for example if the client library internally
+	    used by the provider does not support it), then the provider should make sure it refuses to work
+	    if used from any thread different than the thread which created it, the provider's class implementation
+	    should set the class's <structfield>limiting_thread</structfield> attribute to the thread which created it
+	    using <link linkend="g-thread-self">g_thread_self()</link></para>
+	</listitem>
+	<listitem><para>if multi threading is supported but any connection (or related object) can only be 
+	    used by the thread in which it was created, then for each opened connection, the 
+	    &quot;<link linkend="GdaConnection--thread-owner">thread-owner</link>&quot; connection's property
+	    must be set to the current thread (and other related objects must be locked in a similar way)</para>
+	</listitem>
+	<listitem><para>if no locking is done, then the provider is assumed to support full multi threading access,
+	  in this case make sure to set class's <structfield>limiting_thread</structfield> attribute to NULL.</para>
+	</listitem>
+      </itemizedlist>
+    </para>
+  </sect1>
+
+  <sect1>
     <title>Methods - provider's information</title>
     <sect2 id="prov-get-name">
       <title>get_name() - mandatory</title>

Modified: trunk/doc/C/tmpl/gda-connection.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-connection.sgml	(original)
+++ trunk/doc/C/tmpl/gda-connection.sgml	Thu Jul 17 20:25:20 2008
@@ -103,6 +103,11 @@
 
 </para>
 
+<!-- ##### ARG GdaConnection:thread-owner ##### -->
+<para>
+
+</para>
+
 <!-- ##### ENUM GdaConnectionOptions ##### -->
 <para>
 

Added: trunk/doc/C/tmpl/gda-lockable.sgml
==============================================================================
--- (empty file)
+++ trunk/doc/C/tmpl/gda-lockable.sgml	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,50 @@
+<!-- ##### SECTION Title ##### -->
+GdaLockable
+
+<!-- ##### SECTION Short_Description ##### -->
+Interface for locking objects in a multi threaded environment
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### STRUCT GdaLockable ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### FUNCTION gda_lockable_lock ##### -->
+<para>
+
+</para>
+
+ lockable: 
+
+
+<!-- ##### FUNCTION gda_lockable_trylock ##### -->
+<para>
+
+</para>
+
+ lockable: 
+ Returns: 
+
+
+<!-- ##### FUNCTION gda_lockable_unlock ##### -->
+<para>
+
+</para>
+
+ lockable: 
+
+

Modified: trunk/doc/C/tmpl/gda-meta-store.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-meta-store.sgml	(original)
+++ trunk/doc/C/tmpl/gda-meta-store.sgml	Thu Jul 17 20:25:20 2008
@@ -82,8 +82,8 @@
 
 </para>
 
- GDA_META_STORE_INCORRECT_SCHEMA: 
- GDA_META_STORE_UNSUPPORTED_PROVIDER: 
+ GDA_META_STORE_INCORRECT_SCHEMA_ERROR: 
+ GDA_META_STORE_UNSUPPORTED_PROVIDER_ERROR: 
 @GDA_META_STORE_INTERNAL_ERROR: 
 @GDA_META_STORE_META_CONTEXT_ERROR: 
 @GDA_META_STORE_MODIFY_CONTENTS_ERROR: 

Modified: trunk/doc/C/tmpl/gda-meta-struct.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-meta-struct.sgml	(original)
+++ trunk/doc/C/tmpl/gda-meta-struct.sgml	Thu Jul 17 20:25:20 2008
@@ -135,7 +135,12 @@
 
 <!-- ##### STRUCT GdaMetaDbObject ##### -->
 <para>
-
+  Struture to hold information about each database object (tables, views, triggers, ...)
+</para>
+<para>
+  Note: @obj_catalog, @obj_schema, @obj_name, @obj_short_name and @obj_full_name are case sensitive:
+  one must call _identifier_needs_quotes() to know if is it is necessary to surround by double quotes
+  before using in an SQL statement
 </para>
 
 @obj_type: 

Added: trunk/doc/C/tmpl/gda-mutex.sgml
==============================================================================
--- (empty file)
+++ trunk/doc/C/tmpl/gda-mutex.sgml	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,73 @@
+<!-- ##### SECTION Title ##### -->
+GdaMutex
+
+<!-- ##### SECTION Short_Description ##### -->
+Recursive mutex implementation
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+  #GdaMutex implements a recursive mutex (unlike the #GMutex implementation which offers no
+  guarantee about recursiveness). A recursive mutex is a mutex which can be locked several
+  times by the same thread (and needs to be unlocked the same number of times before
+  another thread can lock it).
+</para>
+<para>
+  A #GdaMutex can safely be used even in a non multi-threaded environment in which case
+  it does nothing.
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### STRUCT GdaMutex ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### FUNCTION gda_mutex_new ##### -->
+<para>
+
+</para>
+
+ Returns: 
+
+
+<!-- ##### FUNCTION gda_mutex_lock ##### -->
+<para>
+
+</para>
+
+ mutex: 
+
+
+<!-- ##### FUNCTION gda_mutex_trylock ##### -->
+<para>
+
+</para>
+
+ mutex: 
+ Returns: 
+
+
+<!-- ##### FUNCTION gda_mutex_unlock ##### -->
+<para>
+
+</para>
+
+ mutex: 
+
+
+<!-- ##### FUNCTION gda_mutex_free ##### -->
+<para>
+
+</para>
+
+ mutex: 
+
+

Modified: trunk/doc/C/tmpl/gda-server-provider.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-server-provider.sgml	(original)
+++ trunk/doc/C/tmpl/gda-server-provider.sgml	Thu Jul 17 20:25:20 2008
@@ -34,6 +34,7 @@
 </para>
 
 @parent_class: 
+ limiting_thread: 
 @get_name: 
 @get_version: 
 @get_server_version: 
@@ -139,13 +140,27 @@
 
 <!-- ##### USER_FUNCTION GdaServerProviderAsyncCallback ##### -->
 <para>
-
+  Function to be called by Libgda when the associated asynchronous method invoked finishes.
 </para>
 
 @provider: 
 @cnc: 
 @task_id: 
 @result_status: 
+ error: 
+ data: 
+
+
+<!-- ##### USER_FUNCTION GdaServerProviderExecCallback ##### -->
+<para>
+  Function to be called by Libgda when the associated asynchronous method invoked finishes.
+</para>
+
+ provider: 
+ cnc: 
+ task_id: 
+ result_obj: 
+ error: 
 @data: 
 
 

Modified: trunk/libgda-xslt/Makefile.am
==============================================================================
--- trunk/libgda-xslt/Makefile.am	(original)
+++ trunk/libgda-xslt/Makefile.am	Thu Jul 17 20:25:20 2008
@@ -19,6 +19,7 @@
 	sql_exslt_internal.c \
 	sql_backend.c
 
+libgda_xslt_4_0_la_LDFLAGS = -version-info $(GDA_CURRENT):$(GDA_REVISION):$(GDA_AGE) $(NO_UNDEFINED)
 libgda_xslt_4_0_la_LIBADD = $(LIBGDA_LIBS) $(LIBXSLT_LIBS)\
         $(top_builddir)/libgda/libgda-4.0.la
 

Modified: trunk/libgda/Makefile.am
==============================================================================
--- trunk/libgda/Makefile.am	(original)
+++ trunk/libgda/Makefile.am	Thu Jul 17 20:25:20 2008
@@ -51,10 +51,12 @@
 	gda-easy.h \
 	gda-enums.h \
 	gda-holder.h \
+	gda-lockable.h \
 	gda-log.h \
 	gda-marshal.h \
 	gda-meta-store.h \
 	gda-meta-struct.h \
+	gda-mutex.h \
 	gda-quark-list.h \
 	gda-set.h \
 	gda-row.h \
@@ -101,11 +103,15 @@
 	gda-easy.c \
 	gda-holder.c \
 	gda-init.c \
+	gda-lockable.c \
 	gda-log.c \
 	gda-marshal.c \
 	gda-meta-store.c \
 	gda-meta-store-extra.h \
+	gda-meta-struct-private.h \
 	gda-meta-struct.c \
+	gda-meta-struct-io.c \
+	gda-mutex.c \
 	gda-quark-list.c \
 	gda-set.c \
 	gda-row.c \

Modified: trunk/libgda/gda-config.c
==============================================================================
--- trunk/libgda/gda-config.c	(original)
+++ trunk/libgda/gda-config.c	Thu Jul 17 20:25:20 2008
@@ -1272,12 +1272,13 @@
 			g_free (cname);
 		}
 
-		ext = g_strrstr (name, ".");
-		if (!ext)
-			continue;
-		if (strcmp (ext + 1, G_MODULE_SUFFIX))
+		if (!g_str_has_suffix (name, "." G_MODULE_SUFFIX))
 			continue;
+#ifdef G_WITH_CYGWIN
+		if (!g_str_has_prefix (name, "cyggda"))
+#else
 		if (!g_str_has_prefix (name, "libgda"))
+#endif
 			continue;
 
 		path = g_build_path (G_DIR_SEPARATOR_S, dirname,

Modified: trunk/libgda/gda-connection-private.h
==============================================================================
--- trunk/libgda/gda-connection-private.h	(original)
+++ trunk/libgda/gda-connection-private.h	Thu Jul 17 20:25:20 2008
@@ -56,11 +56,6 @@
 void     gda_connection_del_prepared_statement (GdaConnection *cnc, GdaStatement *gda_stmt); 
 gpointer gda_connection_get_prepared_statement (GdaConnection *cnc, GdaStatement *gda_stmt);
 
-/*
- * GdaMetaStore handling
- */
-GdaMetaStore *gda_connection_get_meta_store    (GdaConnection *cnc);
-
 G_END_DECLS
 
 #endif

Modified: trunk/libgda/gda-connection.c
==============================================================================
--- trunk/libgda/gda-connection.c	(original)
+++ trunk/libgda/gda-connection.c	Thu Jul 17 20:25:20 2008
@@ -42,6 +42,8 @@
 #include <sql-parser/gda-statement-struct-trans.h>
 #include <libgda/gda-meta-store-extra.h>
 #include <libgda/gda-util.h>
+#include <libgda/gda-mutex.h>
+#include <libgda/gda-lockable.h>
 
 #define PROV_CLASS(provider) (GDA_SERVER_PROVIDER_CLASS (G_OBJECT_GET_CLASS (provider)))
 
@@ -61,6 +63,12 @@
 
 	gpointer              provider_data;
 	GDestroyNotify        provider_data_destroy_func;
+
+	/* multi threading locking */
+	GThread              *unique_possible_thread; /* non NULL => only that thread can use this connection */
+	GCond                *unique_possible_cond;
+	GMutex               *unique_possible_mutex;
+	GdaMutex             *mutex;
 };
 
 static void gda_connection_class_init (GdaConnectionClass *klass);
@@ -76,6 +84,13 @@
 					 GValue *value,
 					 GParamSpec *pspec);
 
+/* GdaLockable interface */
+static void                 gda_connection_lockable_init (GdaLockableClass *iface);
+static void                 gda_connection_lock      (GdaLockable *lockable);
+static gboolean             gda_connection_trylock   (GdaLockable *lockable);
+static void                 gda_connection_unlock    (GdaLockable *lockable);
+
+
 enum {
 	ERROR,
 	CONN_OPENED,
@@ -97,7 +112,8 @@
         PROP_PROVIDER_OBJ,
         PROP_AUTH_STRING,
         PROP_OPTIONS,
-	PROP_META_STORE
+	PROP_META_STORE,
+	PROP_THREAD_OWNER
 };
 
 static GObjectClass *parent_class = NULL;
@@ -167,41 +183,59 @@
         object_class->get_property = gda_connection_get_property;
 
 	g_object_class_install_property (object_class, PROP_DSN,
-                                         g_param_spec_string ("dsn", _("DSN to use"), NULL, NULL,
+                                         g_param_spec_string ("dsn", NULL, _("DSN to use"), NULL,
 							      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
 	g_object_class_install_property (object_class, PROP_CNC_STRING,
-                                         g_param_spec_string ("cnc_string", _("Connection string to use"), NULL, NULL,
+                                         g_param_spec_string ("cnc_string", NULL, _("Connection string to use"), NULL,
 							      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
 	g_object_class_install_property (object_class, PROP_PROVIDER_OBJ,
-                                         g_param_spec_object ("provider_obj", _("Provider to use"), NULL,
+                                         g_param_spec_object ("provider_obj", NULL, _("Provider to use"),
                                                                GDA_TYPE_SERVER_PROVIDER,
 							       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
 
         g_object_class_install_property (object_class, PROP_AUTH_STRING,
-                                         g_param_spec_string ("auth_string", _("Authentication string to use"),
-                                                              NULL, NULL,
+                                         g_param_spec_string ("auth_string", NULL,_("Authentication string to use"),
+                                                              NULL,
                                                               (G_PARAM_READABLE | G_PARAM_WRITABLE)));
         g_object_class_install_property (object_class, PROP_OPTIONS,
-                                         g_param_spec_flags ("options", _("Options (connection sharing)"),
-							    NULL, GDA_TYPE_CONNECTION_OPTIONS, GDA_CONNECTION_OPTIONS_NONE,
+                                         g_param_spec_flags ("options", NULL, _("Options (connection sharing)"),
+							    GDA_TYPE_CONNECTION_OPTIONS, GDA_CONNECTION_OPTIONS_NONE,
 							    (G_PARAM_READABLE | G_PARAM_WRITABLE)));
         g_object_class_install_property (object_class, PROP_META_STORE,
 					 /* To translators: Don't translate "GdaMetaStore", it's a class name */
-					 g_param_spec_object ("meta-store", _ ("GdaMetaStore used by the connection"),
-							      NULL, GDA_TYPE_META_STORE,
+					 g_param_spec_object ("meta-store", NULL, _ ("GdaMetaStore used by the connection"),
+							      GDA_TYPE_META_STORE,
 							      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
 
+	g_object_class_install_property (object_class, PROP_THREAD_OWNER,
+					 g_param_spec_pointer ("thread-owner", NULL,
+							       _("Unique GThread from which the connection will be available."
+								 "This should only be modified by the database providers' implementation"),
+							       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
 	
 	object_class->dispose = gda_connection_dispose;
 	object_class->finalize = gda_connection_finalize;
 }
 
 static void
+gda_connection_lockable_init (GdaLockableClass *iface)
+{
+	iface->i_lock = gda_connection_lock;
+	iface->i_trylock = gda_connection_trylock;
+	iface->i_unlock = gda_connection_unlock;
+}
+
+static void
 gda_connection_init (GdaConnection *cnc, GdaConnectionClass *klass)
 {
 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
 
 	cnc->priv = g_new0 (GdaConnectionPrivate, 1);
+	cnc->priv->unique_possible_thread = NULL;
+	cnc->priv->unique_possible_cond = NULL;
+	cnc->priv->unique_possible_mutex = NULL;
+	cnc->priv->mutex = gda_mutex_new ();
 	cnc->priv->provider_obj = NULL;
 	cnc->priv->dsn = NULL;
 	cnc->priv->cnc_string = NULL;
@@ -220,6 +254,7 @@
 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
 
 	/* free memory */
+	cnc->priv->unique_possible_thread = NULL;
 	gda_connection_close_no_warning (cnc);
 
 	if (cnc->priv->provider_obj) {
@@ -258,6 +293,12 @@
 	g_free (cnc->priv->cnc_string);
 	g_free (cnc->priv->auth_string);
 
+	if (cnc->priv->unique_possible_cond)
+		g_cond_free (cnc->priv->unique_possible_cond);
+	if (cnc->priv->unique_possible_mutex)
+		g_mutex_free (cnc->priv->unique_possible_mutex);
+	gda_mutex_free (cnc->priv->mutex);
+
 	g_free (cnc->priv);
 	cnc->priv = NULL;
 
@@ -298,9 +339,18 @@
 			0,
 			(GInstanceInitFunc) gda_connection_init
 		};
+
+		static GInterfaceInfo lockable_info = {
+                        (GInterfaceInitFunc) gda_connection_lockable_init,
+			NULL,
+                        NULL
+                };
+
 		g_static_mutex_lock (&registering);
-		if (type == 0)
+		if (type == 0) {
 			type = g_type_register_static (G_TYPE_OBJECT, "GdaConnection", &info, 0);
+			g_type_add_interface_static (type, GDA_TYPE_LOCKABLE, &lockable_info);
+		}
 		g_static_mutex_unlock (&registering);
 	}
 
@@ -318,23 +368,37 @@
         cnc = GDA_CONNECTION (object);
         if (cnc->priv) {
                 switch (param_id) {
+		case PROP_THREAD_OWNER:
+			gda_mutex_lock (cnc->priv->mutex);
+			cnc->priv->unique_possible_thread = g_value_get_pointer (value);
+			if (cnc->priv->unique_possible_cond) 
+				g_cond_signal (cnc->priv->unique_possible_cond);
+			gda_mutex_unlock (cnc->priv->mutex);
+			break;
                 case PROP_DSN:
+			gda_connection_lock ((GdaLockable*) cnc);
 			gda_connection_set_dsn (cnc, g_value_get_string (value));
+			gda_connection_unlock ((GdaLockable*) cnc);
                         break;
                 case PROP_CNC_STRING:
+			gda_connection_lock ((GdaLockable*) cnc);
 			g_free (cnc->priv->cnc_string);
 			cnc->priv->cnc_string = NULL;
 			if (g_value_get_string (value)) 
 				cnc->priv->cnc_string = g_strdup (g_value_get_string (value));
+			gda_connection_unlock ((GdaLockable*) cnc);
                         break;
                 case PROP_PROVIDER_OBJ:
+			gda_connection_lock ((GdaLockable*) cnc);
                         if (cnc->priv->provider_obj)
 				g_object_unref(cnc->priv->provider_obj);
 
 			cnc->priv->provider_obj = g_value_get_object (value);
 			g_object_ref (G_OBJECT (cnc->priv->provider_obj));
+			gda_connection_unlock ((GdaLockable*) cnc);
                         break;
                 case PROP_AUTH_STRING:
+			gda_connection_lock ((GdaLockable*) cnc);
 			if (! cnc->priv->is_open) {
 				const gchar *str = g_value_get_string (value);
 				g_free (cnc->priv->auth_string);
@@ -342,11 +406,15 @@
 				if (str)
 					cnc->priv->auth_string = g_strdup (str);
 			}
+			gda_connection_unlock ((GdaLockable*) cnc);
                         break;
                 case PROP_OPTIONS:
+			gda_mutex_lock (cnc->priv->mutex);
 			cnc->priv->options = g_value_get_flags (value);
+			gda_mutex_unlock (cnc->priv->mutex);
 			break;
 		case PROP_META_STORE:
+			gda_mutex_lock (cnc->priv->mutex);
 			if (cnc->priv->meta_store) {
 				g_object_unref (cnc->priv->meta_store);
 				cnc->priv->meta_store = NULL;
@@ -354,6 +422,7 @@
 			cnc->priv->meta_store = g_value_get_object (value);
 			if (cnc->priv->meta_store)
 				g_object_ref (cnc->priv->meta_store);
+			gda_mutex_unlock (cnc->priv->mutex);
 			break;
                 }
         }	
@@ -369,6 +438,7 @@
 
         cnc = GDA_CONNECTION (object);
         if (cnc->priv) {
+		gda_mutex_lock (cnc->priv->mutex);
                 switch (param_id) {
                 case PROP_DSN:
 			g_value_set_string (value, cnc->priv->dsn);
@@ -389,6 +459,7 @@
 			g_value_set_object (value, cnc->priv->meta_store);
 			break;
                 }
+		gda_mutex_unlock (cnc->priv->mutex);
         }	
 }
 
@@ -645,13 +716,15 @@
 	GdaQuarkList *params, *auth;
 	char *real_auth_string = NULL;
 
-	g_return_val_if_fail (cnc && GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
 	g_return_val_if_fail (cnc->priv, FALSE);
 
 	/* don't do anything if connection is already opened */
 	if (cnc->priv->is_open)
 		return TRUE;
 
+	gda_connection_lock ((GdaLockable*) cnc);
+
 	/* connection string */
 	if (cnc->priv->dsn) {
 		/* get the data source info */
@@ -660,6 +733,7 @@
 			gda_log_error (_("Data source %s not found in configuration"), cnc->priv->dsn);
 			g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_NONEXIST_DSN_ERROR,
 				     _("Data source %s not found in configuration"), cnc->priv->dsn);
+			gda_connection_unlock ((GdaLockable*) cnc);
 			return FALSE;
 		}
 
@@ -671,6 +745,7 @@
 			gda_log_error (_("No DSN or connection string specified"));
 			g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_NO_CNC_SPEC_ERROR,
 				     _("No DSN or connection string specified"));
+			gda_connection_unlock ((GdaLockable*) cnc);
 			return FALSE;
 		}
 		/* try to see if connection string has the <provider>://<rest of the string> format */
@@ -680,11 +755,22 @@
 	if (!cnc->priv->provider_obj) {
 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_NO_PROVIDER_SPEC_ERROR,
 			     _("No provider specified"));
+		gda_connection_unlock ((GdaLockable*) cnc);
 		return FALSE;
 	}
+
+	if (PROV_CLASS (cnc->priv->provider_obj)->limiting_thread &&
+	    (PROV_CLASS (cnc->priv->provider_obj)->limiting_thread != g_thread_self ())) {
+		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_PROVIDER_ERROR,
+			     _("Provider does not allow usage from this thread"));
+		gda_connection_unlock ((GdaLockable*) cnc);
+		return FALSE;
+	}
+
 	if (!PROV_CLASS (cnc->priv->provider_obj)->open_connection) {
 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_PROVIDER_ERROR,
 			     _("Internal error: provider does not implement the open_connection() virtual method"));
+		gda_connection_unlock ((GdaLockable*) cnc);
 		return FALSE;
 	}
 
@@ -744,6 +830,13 @@
 #endif
 	}
 
+	/* limit connection's useable thread */
+	if (PROV_CLASS (cnc->priv->provider_obj)->limiting_thread)
+		g_object_set (G_OBJECT (cnc), "thread-owner", 
+			      PROV_CLASS (cnc->priv->provider_obj)->limiting_thread, NULL);
+
+
+	gda_connection_unlock ((GdaLockable*) cnc);
 	return cnc->priv->is_open;
 }
 
@@ -764,6 +857,7 @@
 	if (! cnc->priv->is_open)
 		return;
 
+	gda_connection_lock ((GdaLockable*) cnc);
 #ifdef GDA_DEBUG_signal
         g_print (">> 'CONN_TO_CLOSE' from %s\n", __FUNCTION__);
 #endif
@@ -773,6 +867,7 @@
 #endif
 
         gda_connection_close_no_warning (cnc);
+	gda_connection_unlock ((GdaLockable*) cnc);
 }
 
 /**
@@ -790,6 +885,8 @@
 	if (! cnc->priv->is_open)
 		return;
 
+	gda_connection_lock ((GdaLockable*) cnc);
+
 	/* get rid of prepared statements to avoid problems */
 	if (cnc->priv->prepared_stmts) {
 		g_hash_table_foreach (cnc->priv->prepared_stmts, 
@@ -819,6 +916,8 @@
 #ifdef GDA_DEBUG_signal
         g_print ("<< 'CONN_CLOSED' from %s\n", __FUNCTION__);
 #endif
+
+	gda_connection_unlock ((GdaLockable*) cnc);
 }
 
 
@@ -910,7 +1009,7 @@
 {
 	GdaDataSourceInfo *dsn;
 
-        g_return_val_if_fail (cnc && GDA_IS_CONNECTION (cnc), FALSE);
+        g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
         g_return_val_if_fail (cnc->priv, FALSE);
         g_return_val_if_fail (datasource && *datasource, FALSE);
 
@@ -921,6 +1020,8 @@
         if (!dsn)
                 return FALSE;
 
+	gda_connection_lock ((GdaLockable*) cnc);
+
 	g_free (cnc->priv->dsn);
 	cnc->priv->dsn = g_strdup (datasource);
 #ifdef GDA_DEBUG_signal
@@ -931,6 +1032,7 @@
         g_print ("<< 'DSN_CHANGED' from %s\n", __FUNCTION__);
 #endif
 
+	gda_connection_unlock ((GdaLockable*) cnc);
 	return TRUE;
 }
 
@@ -982,13 +1084,17 @@
 const gchar *
 gda_connection_get_authentication (GdaConnection *cnc)
 {
+	const gchar *str;
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
 	g_return_val_if_fail (cnc->priv, NULL);
 
-	if (cnc->priv->auth_string)
-		return (const gchar *) cnc->priv->auth_string;
-	else
-		return "";
+	gda_connection_lock ((GdaLockable*) cnc);
+	if (cnc->priv->auth_string) 
+		str = (const gchar *) cnc->priv->auth_string;
+	else 
+		str = "";
+	gda_connection_unlock ((GdaLockable*) cnc);
+	return str;
 }
 
 /**
@@ -1015,6 +1121,7 @@
 	g_return_if_fail (cnc->priv);
 	g_return_if_fail (GDA_IS_CONNECTION_EVENT (event));
 
+	gda_connection_lock ((GdaLockable*) cnc);
 	if (debug == -1) {
 		const gchar *str;
 		debug = 0;
@@ -1065,6 +1172,7 @@
 
 	if (gda_connection_event_get_event_type (event) == GDA_CONNECTION_EVENT_ERROR)
 		g_signal_emit (G_OBJECT (cnc), gda_connection_signals[ERROR], 0, event);
+	gda_connection_unlock ((GdaLockable*) cnc);
 }
 
 /**
@@ -1133,12 +1241,14 @@
 	g_return_if_fail (cnc->priv);
 	g_return_if_fail (events_list != NULL);
 
+	gda_connection_lock ((GdaLockable*) cnc);
 	for (l = events_list; l ; l = l->next) {
 		cnc->priv->events_list = g_list_prepend (cnc->priv->events_list, l->data);
 		if (gda_connection_event_get_event_type (GDA_CONNECTION_EVENT (l->data)) ==
 		    GDA_CONNECTION_EVENT_ERROR)
 			g_signal_emit (G_OBJECT (cnc), gda_connection_signals[ERROR], 0, l->data);
 	}
+	gda_connection_unlock ((GdaLockable*) cnc);
 
 	g_list_free (events_list);
 }
@@ -1156,10 +1266,12 @@
 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
 	g_return_if_fail (cnc->priv);
 	
+	gda_connection_lock ((GdaLockable*) cnc);
 	if (cnc->priv->events_list != NULL) {
 		g_list_foreach (cnc->priv->events_list, (GFunc) g_object_unref, NULL);
 		cnc->priv->events_list =  NULL;
 	}
+	gda_connection_unlock ((GdaLockable*) cnc);
 }
 
 /**
@@ -1256,8 +1368,9 @@
 	GSList *retlist = NULL, *stmt_list;
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
 	g_return_val_if_fail (cnc->priv, NULL);
-	g_return_val_if_fail (GDA_IS_BATCH (cnc), NULL);
+	g_return_val_if_fail (GDA_IS_BATCH (batch), NULL);
 
+	gda_connection_lock ((GdaLockable*) cnc);
 	for (stmt_list = (GSList*) gda_batch_get_statements (batch); stmt_list; stmt_list = stmt_list->next) {
 		GObject *obj;
 		obj = gda_connection_statement_execute (cnc, GDA_STATEMENT (stmt_list->data), params,
@@ -1266,6 +1379,7 @@
 			break;
 		retlist = g_slist_prepend (retlist, obj);
 	}
+	gda_connection_unlock ((GdaLockable*) cnc);
 	
 	return g_slist_reverse (retlist);
 }
@@ -2753,6 +2867,8 @@
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
 	g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
 
+	gda_connection_lock ((GdaLockable*) cnc);
+
 	/* Get or create the GdaMetaStore object */
 	store = gda_connection_get_meta_store (cnc);
 	g_assert (store);
@@ -2776,6 +2892,7 @@
 		if (!up_templates) {
 			if (lerror) {
 				g_propagate_error (error, lerror);
+				gda_connection_unlock ((GdaLockable*) cnc);
 				return FALSE;
 			}
 		}
@@ -2783,6 +2900,7 @@
 		if (!dn_templates) {
 			if (lerror) {
 				g_propagate_error (error, lerror);
+				gda_connection_unlock ((GdaLockable*) cnc);
 				return FALSE;
 			}
 		}
@@ -2836,6 +2954,7 @@
 		g_slist_free (cbd.context_templates);
 		g_hash_table_destroy (cbd.context_templates_hash);
 
+		gda_connection_unlock ((GdaLockable*) cnc);
 		return retval;
 	}
 	else {
@@ -2873,6 +2992,7 @@
 			{"_parameters", "_routine_par", NULL}
 		};
 		GdaServerProvider *provider = cnc->priv->provider_obj;
+		gboolean retval;
 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._info;
 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._btypes;
 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._udt;
@@ -2897,8 +3017,10 @@
 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._routine_par;
 		g_assert (nb == sizeof (rmeta) / sizeof (RMeta));
 
-		if (! _gda_meta_store_begin_data_reset (store, error))
+		if (! _gda_meta_store_begin_data_reset (store, error)) {
+			gda_connection_unlock ((GdaLockable*) cnc);
 			return FALSE;
+		}
 
 		lcontext.size = 0;
 		for (i = 0; i < nb; i++) {
@@ -2913,10 +3035,13 @@
 				}
 			}
 		}
-		return _gda_meta_store_finish_data_reset (store, error);
+		retval = _gda_meta_store_finish_data_reset (store, error);
+		gda_connection_unlock ((GdaLockable*) cnc);
+		return retval;
 
 	onerror:
 		_gda_meta_store_cancel_data_reset (store, NULL);
+		gda_connection_unlock ((GdaLockable*) cnc);
 		return FALSE;
 	}
 }
@@ -3209,8 +3334,14 @@
 {
 	GdaTransactionStatus *parent, *st;
 
+	g_return_if_fail (GDA_IS_CONNECTION (cnc));
+	g_return_if_fail (cnc->priv);
+
 	st = gda_transaction_status_new (trans_name);
 	st->isolation_level = isol_level;
+
+	gda_connection_lock ((GdaLockable*) cnc);
+
 	parent = gda_transaction_status_find (cnc->priv->trans_status, parent_trans, NULL);
 	if (!parent)
 		cnc->priv->trans_status = st;
@@ -3230,6 +3361,8 @@
 	if (cnc->priv->trans_status)
 		gda_transaction_status_dump (cnc->priv->trans_status, 5);
 #endif
+
+	gda_connection_unlock ((GdaLockable*) cnc);
 }
 
 void 
@@ -3238,6 +3371,11 @@
 	GdaTransactionStatus *st = NULL;
 	GdaTransactionStatusEvent *ev = NULL;
 
+	g_return_if_fail (GDA_IS_CONNECTION (cnc));
+	g_return_if_fail (cnc->priv);
+
+	gda_connection_lock ((GdaLockable*) cnc);
+
 	if (cnc->priv->trans_status)
 		st = gda_transaction_status_find (cnc->priv->trans_status, trans_name, &ev);
 	if (st) {
@@ -3268,6 +3406,8 @@
 	if (cnc->priv->trans_status)
 		gda_transaction_status_dump (cnc->priv->trans_status, 5);
 #endif
+
+	gda_connection_unlock ((GdaLockable*) cnc);
 }
 
 void 
@@ -3276,6 +3416,11 @@
 	GdaTransactionStatus *st = NULL;
 	GdaTransactionStatusEvent *ev = NULL;
 
+	g_return_if_fail (GDA_IS_CONNECTION (cnc));
+	g_return_if_fail (cnc->priv);
+
+	gda_connection_lock ((GdaLockable*) cnc);
+
 	if (cnc->priv->trans_status)
 		st = gda_transaction_status_find (cnc->priv->trans_status, trans_name, &ev);
 	if (st) {
@@ -3306,6 +3451,8 @@
 	if (cnc->priv->trans_status)
 		gda_transaction_status_dump (cnc->priv->trans_status, 5);
 #endif
+
+	gda_connection_unlock ((GdaLockable*) cnc);
 }
 
 void
@@ -3313,6 +3460,11 @@
 {
 	GdaTransactionStatus *st;
 
+	g_return_if_fail (GDA_IS_CONNECTION (cnc));
+	g_return_if_fail (cnc->priv);
+
+	gda_connection_lock ((GdaLockable*) cnc);
+
 	st = gda_transaction_status_find (cnc->priv->trans_status, parent_trans, NULL);
 	if (st) {
 		gda_transaction_status_add_event_svp (st, svp_name);
@@ -3334,6 +3486,8 @@
 	if (cnc->priv->trans_status)
 		gda_transaction_status_dump (cnc->priv->trans_status, 5);
 #endif
+
+	gda_connection_unlock ((GdaLockable*) cnc);
 }
 
 void
@@ -3342,6 +3496,11 @@
 	GdaTransactionStatus *st;
 	GdaTransactionStatusEvent *ev = NULL;
 
+	g_return_if_fail (GDA_IS_CONNECTION (cnc));
+	g_return_if_fail (cnc->priv);
+
+	gda_connection_lock ((GdaLockable*) cnc);
+
 	st = gda_transaction_status_find (cnc->priv->trans_status, svp_name, &ev);
 	if (st) {
 		gda_transaction_status_free_events (st, ev, TRUE);
@@ -3363,6 +3522,8 @@
 	if (cnc->priv->trans_status)
 		gda_transaction_status_dump (cnc->priv->trans_status, 5);
 #endif	
+
+	gda_connection_unlock ((GdaLockable*) cnc);
 }
 
 void
@@ -3371,6 +3532,11 @@
 	GdaTransactionStatus *st;
 	GdaTransactionStatusEvent *ev = NULL;
 
+	g_return_if_fail (GDA_IS_CONNECTION (cnc));
+	g_return_if_fail (cnc->priv);
+
+	gda_connection_lock ((GdaLockable*) cnc);
+
 	st = gda_transaction_status_find (cnc->priv->trans_status, svp_name, &ev);
 	if (st) {
 		gda_transaction_status_free_events (st, ev, FALSE);
@@ -3391,12 +3557,17 @@
 #ifdef GDA_DEBUG_NO
 	if (cnc->priv->trans_status)
 		gda_transaction_status_dump (cnc->priv->trans_status, 5);
-#endif		
+#endif
+
+	gda_connection_unlock ((GdaLockable*) cnc);
 }
 
 void 
 gda_connection_internal_statement_executed (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params, GdaConnectionEvent *error)
 {
+	g_return_if_fail (GDA_IS_CONNECTION (cnc));
+	g_return_if_fail (cnc->priv);
+
 	if (!error || (error && (gda_connection_event_get_event_type (error) != GDA_CONNECTION_EVENT_ERROR))) {
 		GdaSqlStatement *sqlst;
 		GdaSqlStatementTransaction *trans;
@@ -3427,6 +3598,8 @@
 		default: {
 			GdaTransactionStatus *st = NULL;
 			
+			gda_connection_lock ((GdaLockable*) cnc);
+
 			if (cnc->priv->trans_status)
 				st = gda_transaction_status_find_current (cnc->priv->trans_status, NULL, FALSE);
 			if (st) {
@@ -3452,6 +3625,7 @@
 			if (cnc->priv->trans_status)
 				gda_transaction_status_dump (cnc->priv->trans_status, 5);
 #endif
+			gda_connection_unlock ((GdaLockable*) cnc);
 			break;
 		}
 		}
@@ -3463,6 +3637,11 @@
 gda_connection_internal_change_transaction_state (GdaConnection *cnc,
 						  GdaTransactionStatusState newstate)
 {
+	g_return_if_fail (GDA_IS_CONNECTION (cnc));
+	g_return_if_fail (cnc->priv);
+
+	gda_connection_lock ((GdaLockable*) cnc);
+
 	g_return_if_fail (cnc->priv->trans_status);
 
 	if (cnc->priv->trans_status->state == newstate)
@@ -3476,6 +3655,7 @@
 #ifdef GDA_DEBUG_signal
 	g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
 #endif
+	gda_connection_unlock ((GdaLockable*) cnc);
 }
 
 /*
@@ -3488,17 +3668,25 @@
 static void 
 prepared_stms_stmt_destroyed_cb (GdaStatement *gda_stmt, GdaConnection *cnc)
 {
+	gda_connection_lock ((GdaLockable*) cnc);
+
 	g_signal_handlers_disconnect_by_func (gda_stmt, G_CALLBACK (prepared_stms_stmt_destroyed_cb), cnc);
 	g_object_weak_unref (G_OBJECT (gda_stmt), (GWeakNotify) statement_weak_notify_cb, cnc);
 	g_assert (cnc->priv->prepared_stmts);
 	g_hash_table_remove (cnc->priv->prepared_stmts, gda_stmt);
+
+	gda_connection_unlock ((GdaLockable*) cnc);
 }
 
 static void
 statement_weak_notify_cb (GdaConnection *cnc, GdaStatement *stmt)
 {
+	gda_connection_lock ((GdaLockable*) cnc);
+
 	g_assert (cnc->priv->prepared_stmts);
 	g_hash_table_remove (cnc->priv->prepared_stmts, stmt);
+
+	gda_connection_unlock ((GdaLockable*) cnc);
 }
 
 void 
@@ -3507,6 +3695,8 @@
 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
 	g_return_if_fail (cnc->priv);
 
+	gda_connection_lock ((GdaLockable*) cnc);
+
 	if (!cnc->priv->prepared_stmts)
 		cnc->priv->prepared_stmts = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
 	g_hash_table_remove (cnc->priv->prepared_stmts, gda_stmt);
@@ -3515,25 +3705,36 @@
 	/* destroy the prepared statement if gda_stmt is destroyed, or changes */
 	g_object_weak_ref (G_OBJECT (gda_stmt), (GWeakNotify) statement_weak_notify_cb, cnc);
 	g_signal_connect (G_OBJECT (gda_stmt), "reset", G_CALLBACK (prepared_stms_stmt_destroyed_cb), cnc);
+
+	gda_connection_unlock ((GdaLockable*) cnc);
 }
 
 gpointer
 gda_connection_get_prepared_statement (GdaConnection *cnc, GdaStatement *gda_stmt)
 {
+	gpointer retval = NULL;
+
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
 	g_return_val_if_fail (cnc->priv, NULL);
 
-	if (!cnc->priv->prepared_stmts) 
-		return NULL;
+	gda_connection_lock ((GdaLockable*) cnc);
+	if (cnc->priv->prepared_stmts) 
+		retval = g_hash_table_lookup (cnc->priv->prepared_stmts, gda_stmt);
+	gda_connection_unlock ((GdaLockable*) cnc);
 
-	return g_hash_table_lookup (cnc->priv->prepared_stmts, gda_stmt);
+	return retval;
 }
 
 void
 gda_connection_del_prepared_statement (GdaConnection *cnc, GdaStatement *gda_stmt)
 {
 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
+	g_return_if_fail (cnc->priv);
+
+	gda_connection_lock ((GdaLockable*) cnc);
+	g_return_if_fail (GDA_IS_CONNECTION (cnc));
 	prepared_stms_stmt_destroyed_cb (gda_stmt, cnc);
+	gda_connection_unlock ((GdaLockable*) cnc);
 }
 
 static void
@@ -3559,9 +3760,14 @@
 void 
 gda_connection_internal_set_provider_data (GdaConnection *cnc, gpointer data, GDestroyNotify destroy_func)
 {
+
 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
+	g_return_if_fail (cnc->priv);
+
+	gda_connection_lock ((GdaLockable*) cnc);
 	cnc->priv->provider_data = data;
 	cnc->priv->provider_data_destroy_func = destroy_func;
+	gda_connection_unlock ((GdaLockable*) cnc);
 }
 
 /**
@@ -3576,10 +3782,18 @@
 gpointer
 gda_connection_internal_get_provider_data (GdaConnection *cnc)
 {
+	gpointer retval;
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+	g_return_val_if_fail (cnc->priv, NULL);
+
+	gda_connection_lock ((GdaLockable*) cnc);
+	
 	if (! cnc->priv->provider_data)
 		gda_connection_add_event_string (cnc, _("Internal error: invalid provider handle"));
-	return cnc->priv->provider_data;
+	retval = cnc->priv->provider_data;
+
+	gda_connection_unlock ((GdaLockable*) cnc);
+	return retval;
 }
 
 /**
@@ -3593,10 +3807,101 @@
 GdaMetaStore *
 gda_connection_get_meta_store (GdaConnection *cnc)
 {
+	GdaMetaStore *store;
+
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-	if (cnc->priv->meta_store)
-		return cnc->priv->meta_store;
+	g_return_val_if_fail (cnc->priv, NULL);
+
+	gda_connection_lock ((GdaLockable*) cnc);
+	if (!cnc->priv->meta_store)
+		cnc->priv->meta_store = gda_meta_store_new (NULL);
+	store = cnc->priv->meta_store;
+	gda_connection_unlock ((GdaLockable*) cnc);
+	
+	return store;
+}
+
+/*
+ * This method is usefull only in a multi threading environment (it has no effect in a
+ * single thread program).
+ * Locks @cnc for the current thread. If the lock can't be obtained, then the current thread
+ * will be blocked until it can acquire @cnc's lock. 
+ *
+ * The cases when the connection can't be locked are:
+ * <itemizedlist>
+ *   <listitem><para>another thread is already using the connection</para></listitem>
+ *   <listitem><para>the connection can only be used by a single thread (see the 
+ *     <link linkend="GdaConnection--thread-owner">thread-owner</link> property)</para></listitem>
+ * </itemizedlist>
+ *
+ * To avoid the thread being blocked (possibly forever if the single thread which can use the
+ * connection is not the current thead), then it is possible to use gda_connection_trylock() instead.
+ */
+static void
+gda_connection_lock (GdaLockable *lockable)
+{
+	GdaConnection *cnc = (GdaConnection *) lockable;
+	g_return_if_fail (cnc->priv);
+	
+	gda_mutex_lock (cnc->priv->mutex);
+	if (cnc->priv->unique_possible_thread && 
+	    (cnc->priv->unique_possible_thread != g_thread_self ())) {
+		if (!cnc->priv->unique_possible_mutex)
+			cnc->priv->unique_possible_mutex = g_mutex_new ();
+		if (!cnc->priv->unique_possible_cond)
+			cnc->priv->unique_possible_cond = g_cond_new ();
+
+		g_mutex_lock (cnc->priv->unique_possible_mutex);
+		gda_mutex_unlock (cnc->priv->mutex);
+
+		g_cond_wait (cnc->priv->unique_possible_cond, cnc->priv->unique_possible_mutex);
+		while (1) {
+			if (cnc->priv->unique_possible_thread &&
+			    (cnc->priv->unique_possible_thread != g_thread_self ())) {
+				g_cond_signal (cnc->priv->unique_possible_cond);
+				g_cond_wait (cnc->priv->unique_possible_cond, cnc->priv->unique_possible_mutex);
+			}
+			else {
+				g_mutex_unlock (cnc->priv->unique_possible_mutex);
+				gda_mutex_lock (cnc->priv->mutex);
+				break;
+			}
+		}
+	}
+}
+
+/*
+ * Tries to lock @cnc for the exclusive usage of the current thread, as gda_connection_lock(), except
+ * that if it can't, then the calling thread is not locked by it simply returns FALSE.
+ *
+ * Returns: TRUE if sucessfully locked, or FALSE if lock could not be acquired
+ */
+static gboolean
+gda_connection_trylock (GdaLockable *lockable)
+{
+	gboolean retval;
+	GdaConnection *cnc = (GdaConnection *) lockable;
 
-	cnc->priv->meta_store = gda_meta_store_new (NULL);
-	return cnc->priv->meta_store;
+	g_return_val_if_fail (cnc->priv, FALSE);
+	
+	retval = gda_mutex_trylock (cnc->priv->mutex);
+	if (retval && cnc->priv->unique_possible_thread &&
+	    (cnc->priv->unique_possible_thread != g_thread_self ())) {
+		retval = FALSE;
+		gda_mutex_unlock (cnc->priv->mutex);
+	}
+	return retval;
+}
+
+/*
+ * Unlocks @cnc's usage. Any other thread blocked (after having called gda_connection_lock()) gets
+ * the opportunity to lock the connection.
+ */
+static void
+gda_connection_unlock  (GdaLockable *lockable)
+{
+	GdaConnection *cnc = (GdaConnection *) lockable;
+	g_return_if_fail (cnc->priv);
+	
+	gda_mutex_unlock (cnc->priv->mutex);
 }

Modified: trunk/libgda/gda-connection.h
==============================================================================
--- trunk/libgda/gda-connection.h	(original)
+++ trunk/libgda/gda-connection.h	Thu Jul 17 20:25:20 2008
@@ -204,7 +204,6 @@
 gboolean             gda_connection_update_meta_store    (GdaConnection *cnc, GdaMetaContext *context, GError **error);
 GdaDataModel        *gda_connection_get_meta_store_data  (GdaConnection *cnc, GdaConnectionMetaType meta_type,
 							  GError **error, gint nb_filters, ...);
-
 G_END_DECLS
 
 #endif

Modified: trunk/libgda/gda-data-comparator.c
==============================================================================
--- trunk/libgda/gda-data-comparator.c	(original)
+++ trunk/libgda/gda-data-comparator.c	Thu Jul 17 20:25:20 2008
@@ -120,13 +120,13 @@
         thisvalue = g_value_get_boolean (handler_return);
         g_value_set_boolean (return_accu, thisvalue);
 
-        return thisvalue; /* stop signal if 'thisvalue' is FALSE */
+        return !thisvalue; /* stop signal if 'thisvalue' is FALSE */
 }
 
 static gboolean
 m_diff_computed (GdaDataComparator *comparator, GdaDiff *diff)
 {
-        return TRUE; /* default is to allow differences computing to proceed */
+        return FALSE; /* default is to allow differences computing to proceed (understand it as: FALSE => don't stop) */
 }
 
 static void

Modified: trunk/libgda/gda-data-model-iter.c
==============================================================================
--- trunk/libgda/gda-data-model-iter.c	(original)
+++ trunk/libgda/gda-data-model-iter.c	Thu Jul 17 20:25:20 2008
@@ -393,18 +393,31 @@
 			/* compute parameters */
 			ncols = gda_data_model_get_n_columns (model);
 			for (col = 0; col < ncols; col++) {
-				const gchar *str;
+				gchar *str;
 				column = gda_data_model_describe_column (model, col);
 				param = (GdaHolder *) g_object_new (GDA_TYPE_HOLDER, 
 								    "g_type", 
 								    gda_column_get_g_type (column), NULL);
 
 				gda_holder_set_not_null (param, !gda_column_get_allow_null (column));
-				str = gda_column_get_title (column);
-				if (!str)
-					str = gda_column_get_name (column);
-				if (str)
+				g_object_get (G_OBJECT (column), "id", &str, NULL);
+				if (str) {
 					g_object_set (G_OBJECT (param), "id", str, NULL);
+					g_free (str);
+				}
+				else {
+					const gchar *cstr;
+					cstr = gda_column_get_title (column);
+					if (!cstr)
+						cstr = gda_column_get_name (column);
+					if (cstr)
+						g_object_set (G_OBJECT (param), "id", cstr, NULL);
+					else {
+						gchar *tmp = g_strdup_printf ("col%d", col);
+						g_object_set (G_OBJECT (param), "id", tmp, NULL);
+						g_free (tmp);
+					}
+				}
 				if (gda_column_get_default_value (column))
 					gda_holder_set_default_value (param, gda_column_get_default_value (column));
 				else if (gda_column_get_auto_increment (column)) {

Modified: trunk/libgda/gda-data-model.c
==============================================================================
--- trunk/libgda/gda-data-model.c	(original)
+++ trunk/libgda/gda-data-model.c	Thu Jul 17 20:25:20 2008
@@ -1386,16 +1386,26 @@
 	xmlNodePtr node;
 	gint i;
 	gint *rcols, rnb_cols;
+	const gchar *cstr;
 
 	g_return_val_if_fail (GDA_IS_DATA_MODEL (model), NULL);
 
 	node = xmlNewNode (NULL, BAD_CAST "gda_array");
-	xmlSetProp (node, BAD_CAST "id", BAD_CAST "EXPORT");
+	cstr = g_object_get_data (G_OBJECT (model), "id");
+	if (cstr)
+		xmlSetProp (node, BAD_CAST "id", BAD_CAST cstr);
+	else
+		xmlSetProp (node, BAD_CAST "id", BAD_CAST "EXPORT");
 
 	if (name)
 		xmlSetProp (node, BAD_CAST "name", BAD_CAST name);
-	else
-		xmlSetProp (node, BAD_CAST "name", BAD_CAST _("Exported Data"));
+	else {
+		cstr = g_object_get_data (G_OBJECT (model), "name");
+		if (cstr)
+			xmlSetProp (node, BAD_CAST "name", BAD_CAST cstr);
+		else
+			xmlSetProp (node, BAD_CAST "name", BAD_CAST _("Exported Data"));
+	}
 
 	/* compute columns if not provided */
 	if (!cols) {
@@ -1423,7 +1433,9 @@
 		}
 
 		field = xmlNewChild (node, NULL, BAD_CAST "gda_array_field", NULL);
-		str = g_strdup_printf ("FI%d", i);
+		g_object_get (G_OBJECT (column), "id", &str, NULL);
+		if (!str)
+			str = g_strdup_printf ("FI%d", i);
 		xmlSetProp (field, BAD_CAST "id", BAD_CAST str);
 		g_free (str);
 		xmlSetProp (field, BAD_CAST "name", BAD_CAST gda_column_get_name (column));
@@ -1703,7 +1715,8 @@
 		return FALSE;
 	}
 
-	/* make a list of the parameters which will be used during copy (stored in reverse order!) ,
+	/* make a list of the parameters which will be used during copy (stored in reverse order: last column of data model
+	 * represented by the 1st GdaHolder) ,
 	 * an some tests */
 	for (i = 0; i < to_nb_cols; i++) {
 		GdaHolder *param = NULL;
@@ -1747,17 +1760,29 @@
 				return FALSE;
 			}
 		}
+		
 		copy_params = g_slist_prepend (copy_params, param);
 	}
 
+#ifdef GDA_DEBUG_NO
+	{
+		GSList *list;
+		for (list = copy_params; list; list = list->next) {
+			GdaHolder *param = GDA_HOLDER (list->data);
+			g_print ("Copy Param: %s (%s)\n", gda_holder_get_id (param), 
+				 gda_g_type_to_string (gda_holder_get_g_type (param)));
+		}
+	}
+#endif
+
 	/* build the append_values list (stored in reverse order!)
 	 * node->data is:
 	 * - NULL if the value must be replaced by the value of the copied model
 	 * - a GValue of type GDA_VALYE_TYPE_NULL if a null value must be inserted in the dest data model
-	 * - a GValue of a different type if the value must be converted from the ser data model
+	 * - a GValue of a different type if the value must be converted from the src data model
 	 */
 	append_types = g_new0 (GType, to_nb_cols);
-	for (plist = copy_params, i = 0; plist; plist = plist->next, i++) {
+	for (plist = copy_params, i = to_nb_cols - 1; plist; plist = plist->next, i--) {
 		GdaColumn *column;
 
 		column = gda_data_model_describe_column (to, i);
@@ -1779,6 +1804,13 @@
 			append_values = g_list_prepend (append_values, gda_value_new_null ());
 	}
 	append_values = g_list_reverse (append_values);
+#ifdef GDA_DEBUG_NO
+	{
+		GList *list;
+		for (list = append_values; list; list = list->next) 
+			g_print ("Append Value: %s\n", list->data ? gda_g_type_to_string (G_VALUE_TYPE ((GValue *) (list->data))) : "NULL");
+	}
+#endif
 	
 	/* actual data copy (no memory allocation is needed here) */
 	gda_data_model_send_hint (to, GDA_DATA_MODEL_HINT_START_BATCH_UPDATE, NULL);
@@ -2089,7 +2121,7 @@
 		GdaColumn *gdacol;
 		GType coltype;
 
-#ifdef GDA_DEBUG_NO
+#ifdef GDA_DEBUG
 		{
 			GdaColumn *col = gda_data_model_describe_column (model, i);
 			g_print ("Model col %d has type %s\n", i, gda_g_type_to_string (gda_column_get_g_type (col)));

Added: trunk/libgda/gda-lockable.c
==============================================================================
--- (empty file)
+++ trunk/libgda/gda-lockable.c	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,137 @@
+/* 
+ * GDA common library
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <libgda/gda-lockable.h>
+
+static GStaticRecMutex init_mutex = G_STATIC_REC_MUTEX_INIT;
+static void gda_lockable_class_init (gpointer g_class);
+
+GType
+gda_lockable_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo info = {
+			sizeof (GdaLockableClass),
+			(GBaseInitFunc) gda_lockable_class_init,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) NULL,
+			NULL,
+			NULL,
+			0,
+			0,
+			(GInstanceInitFunc) NULL
+		};
+		
+		g_static_rec_mutex_lock (&init_mutex);
+		if (type == 0) {
+			type = g_type_register_static (G_TYPE_INTERFACE, "GdaLockable", &info, 0);
+			g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
+		}
+		g_static_rec_mutex_unlock (&init_mutex);
+	}
+	return type;
+}
+
+static void
+gda_lockable_class_init (gpointer g_class)
+{
+	static gboolean initialized = FALSE;
+
+	g_static_rec_mutex_lock (&init_mutex);
+	if (! initialized) {
+		initialized = TRUE;
+	}
+	g_static_rec_mutex_unlock (&init_mutex);
+}
+
+/**
+ * gda_lockable_lock
+ * @lockable: a #GdaLockable object.
+ *
+ * Locks @lockable. If it is already locked by another thread, the current thread will block until it is unlocked 
+ * by the other thread.
+ *
+ * This function can be used even if g_thread_init() has not yet been called, and, in that case, will do nothing.
+ *
+ * Note: unlike g_mutex_lock(), this method recursive, which means a thread can lock @lockable several times 
+ * (and has to unlock it as many times to actually unlock it).
+ */
+void
+gda_lockable_lock (GdaLockable *lockable)
+{
+	g_return_if_fail (GDA_IS_LOCKABLE (lockable));
+	
+	if (GDA_LOCKABLE_GET_CLASS (lockable)->i_lock)
+		(GDA_LOCKABLE_GET_CLASS (lockable)->i_lock) (lockable);
+	else
+		g_warning ("Internal implementation error: %s() method not implemented\n", "i_lock");
+}
+
+/**
+ * gda_lockable_trylock
+ * @lockable: a #GdaLockable object.
+ *
+ * Tries to lock @lockable. If it is already locked by another thread, then it immediately returns FALSE, otherwise
+ * it locks @lockable.
+ *
+ * This function can be used even if g_thread_init() has not yet been called, and, in that case, will do nothing.
+ *
+ * Note: unlike g_mutex_lock(), this method recursive, which means a thread can lock @lockable several times 
+ * (and has to unlock it as many times to actually unlock it).
+ *
+ * Returns: TRUE if the object has successfully been locked.
+ */
+gboolean
+gda_lockable_trylock (GdaLockable *lockable)
+{
+	g_return_val_if_fail (GDA_IS_LOCKABLE (lockable), FALSE);
+	
+	if (GDA_LOCKABLE_GET_CLASS (lockable)->i_trylock)
+		return (GDA_LOCKABLE_GET_CLASS (lockable)->i_trylock) (lockable);
+	else {
+		g_warning ("Internal implementation error: %s() method not implemented\n", "i_trylock");
+		return FALSE;
+	}
+}
+
+/**
+ * gda_lockable_unlock
+ * @lockable: a #GdaLockable object.
+ *
+ * Unlocks @lockable. This method should not be called if the current does not already holds a lock on @lockable (having
+ * used gda_lockable_lock() or gda_lockable_trylock()).
+ *
+ * This function can be used even if g_thread_init() has not yet been called, and, in that case, will do nothing.
+ */
+void
+gda_lockable_unlock (GdaLockable *lockable)
+{
+	g_return_if_fail (GDA_IS_LOCKABLE (lockable));
+	
+	if (GDA_LOCKABLE_GET_CLASS (lockable)->i_unlock)
+		(GDA_LOCKABLE_GET_CLASS (lockable)->i_unlock) (lockable);
+	else
+		g_warning ("Internal implementation error: %s() method not implemented\n", "i_unlock");
+}

Added: trunk/libgda/gda-lockable.h
==============================================================================
--- (empty file)
+++ trunk/libgda/gda-lockable.h	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,56 @@
+/* GDA common library
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GDA_LOCKABLE_H__
+#define __GDA_LOCKABLE_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GDA_TYPE_LOCKABLE            (gda_lockable_get_type())
+#define GDA_LOCKABLE(obj)            (G_TYPE_CHECK_INSTANCE_CAST (obj, GDA_TYPE_LOCKABLE, GdaLockable))
+#define GDA_IS_LOCKABLE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE (obj, GDA_TYPE_LOCKABLE))
+#define GDA_LOCKABLE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GDA_TYPE_LOCKABLE, GdaLockableClass))
+
+typedef struct _GdaLockableClass   GdaLockableClass;
+typedef struct _GdaLockable        GdaLockable;
+
+/* struct for the interface */
+struct _GdaLockableClass {
+	GTypeInterface           g_iface;
+
+	/* virtual table */
+	void                 (* i_lock)       (GdaLockable *lock);
+	gboolean             (* i_trylock)    (GdaLockable *lock);
+	void                 (* i_unlock)     (GdaLockable *lock);
+};
+
+GType      gda_lockable_get_type   (void) G_GNUC_CONST;
+
+void       gda_lockable_lock       (GdaLockable *lockable);
+gboolean   gda_lockable_trylock    (GdaLockable *lockable);
+void       gda_lockable_unlock     (GdaLockable *lockable);
+
+G_END_DECLS
+
+#endif

Modified: trunk/libgda/gda-meta-store.c
==============================================================================
--- trunk/libgda/gda-meta-store.c	(original)
+++ trunk/libgda/gda-meta-store.c	Thu Jul 17 20:25:20 2008
@@ -179,7 +179,7 @@
         GHashTable    *table_cond_info_hash; /* key = string composed of the column names of
 					      * the parameters separated by a period, 
 					      * value = a TableConditionInfo structure */
-	GHashTable    *provider_specifics; /* key = a ProviderSpecificKey , value = a ProviderSpecificValue) */
+	GHashTable    *provider_specifics; /* key = a ProviderSpecificKey , value = a ProviderSpecificValue */
 };
 
 typedef struct {
@@ -785,7 +785,7 @@
 	if (gda_connection_statement_execute_non_select (store->priv->cnc,
 							 klass->cpriv->prep_stmts[STMT_SET_VERSION],
 							 NULL, NULL, NULL) == -1) {
-		g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_INCORRECT_SCHEMA,
+		g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_INCORRECT_SCHEMA_ERROR,
 			_ ("Could not set the internal schema's version"));
 		return FALSE;
 	}
@@ -1856,7 +1856,7 @@
 	if (model) {
 		const GValue *version;
 		if (gda_data_model_get_n_rows (model) != 1) {
-			g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_INCORRECT_SCHEMA,
+			g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_INCORRECT_SCHEMA_ERROR,
 				_ ("Could not get the internal schema's version"));
 			g_object_unref (model);
 			return FALSE;
@@ -1864,7 +1864,7 @@
 		
 		version = gda_data_model_get_value_at (model, 0, 0);
 		if (gda_value_is_null (version) || !gda_value_isa (version, G_TYPE_STRING)) {
-			g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_INCORRECT_SCHEMA,
+			g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_INCORRECT_SCHEMA_ERROR,
 				_ ("Could not get the internal schema's version"));
 			g_object_unref (model);
 			return FALSE;
@@ -1874,7 +1874,7 @@
 		if (store->priv->version != 1) {
 			TO_IMPLEMENT; /* migrate to current version */
 			/* As there is now only version 1 => it's an error */
-			g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_INCORRECT_SCHEMA,
+			g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_INCORRECT_SCHEMA_ERROR,
 				_ ("Unknown internal schema's version: %d"), g_value_get_int (version));
 			g_object_unref (model);
 			return FALSE;
@@ -1883,7 +1883,7 @@
 		return TRUE;
 	}
 	else {
-		g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_INCORRECT_SCHEMA,
+		g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_INCORRECT_SCHEMA_ERROR,
 			_ ("Could not get the internal schema's version"));
 		return FALSE;
 	}

Modified: trunk/libgda/gda-meta-store.h
==============================================================================
--- trunk/libgda/gda-meta-store.h	(original)
+++ trunk/libgda/gda-meta-store.h	Thu Jul 17 20:25:20 2008
@@ -38,8 +38,8 @@
 #define GDA_META_STORE_ERROR gda_meta_store_error_quark ()
 
 typedef enum {
-	GDA_META_STORE_INCORRECT_SCHEMA,
-	GDA_META_STORE_UNSUPPORTED_PROVIDER,
+	GDA_META_STORE_INCORRECT_SCHEMA_ERROR,
+	GDA_META_STORE_UNSUPPORTED_PROVIDER_ERROR,
 	GDA_META_STORE_INTERNAL_ERROR,
 	GDA_META_STORE_META_CONTEXT_ERROR,
 	GDA_META_STORE_MODIFY_CONTENTS_ERROR,

Added: trunk/libgda/gda-meta-struct-io.c
==============================================================================
--- (empty file)
+++ trunk/libgda/gda-meta-struct-io.c	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,386 @@
+/* gda-meta-struct-io.c
+ *
+ * Copyright (C) 2008 Vivien Malerba
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <libgda/gda-util.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libgda/gda-meta-struct-private.h>
+
+#include <libgda/sql-parser/gda-statement-struct-util.h>
+
+
+static GdaMetaDbObject *create_table_object (GdaMetaStruct *mstruct, const GValue *catalog, const gchar *quoted_catalog,
+					     const GValue *schema, const gchar *quoted_schema, xmlNodePtr node, GError **error);
+static GdaMetaDbObject *create_view_object (GdaMetaStruct *mstruct, const GValue *catalog, const gchar *quoted_catalog,
+					    const GValue *schema, const gchar *quoted_schema, xmlNodePtr node, GError **error);
+
+
+
+/**
+ * gda_meta_struct_load_from_xml_file
+ * @mstruct:
+ * @xml_spec_file:
+ * @error:
+ *
+ * returns: TRUE if no error has occurred
+ */
+gboolean
+gda_meta_struct_load_from_xml_file (GdaMetaStruct *mstruct, const gchar *catalog, const gchar *schema, 
+				    const gchar *xml_spec_file, GError **error)
+{
+	xmlNodePtr node;
+	xmlDocPtr doc;
+
+	GValue *catalog_value = NULL;
+	gchar *quoted_catalog = NULL;
+	GValue *schema_value = NULL;
+	gchar *quoted_schema = NULL;
+
+	g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), FALSE);
+	g_return_val_if_fail (mstruct->priv, FALSE);
+	g_return_val_if_fail (xml_spec_file && *xml_spec_file, FALSE);
+
+	if (catalog) {
+		g_value_set_string ((catalog_value = gda_value_new (G_TYPE_STRING)), catalog);
+		if (_identifier_needs_quotes (catalog)) 
+			quoted_catalog = _add_quotes (catalog);
+		else
+			quoted_catalog = g_strdup (catalog);
+	}
+	if (schema) {
+		g_value_set_string ((schema_value = gda_value_new (G_TYPE_STRING)), schema);
+		if (_identifier_needs_quotes (schema)) 
+			quoted_schema = _add_quotes (schema);
+		else
+			quoted_schema = g_strdup (schema);
+	}
+
+	/* load information schema's structure XML file */
+	doc = xmlParseFile (xml_spec_file);
+	if (!doc) {
+		g_set_error (error, GDA_META_STRUCT_ERROR, 0, /* FIXME */
+			     _("Could not load file '%s'"), xml_spec_file);
+		return FALSE;
+	}
+	
+	node = xmlDocGetRootElement (doc);
+	if (!node || strcmp ((gchar *) node->name, "schema")) {
+		g_set_error (error, GDA_META_STRUCT_ERROR, 0, /* FIXME */
+			     _("Root node of file '%s' should be <schema>."), xml_spec_file);
+		xmlFreeDoc (doc);
+		return FALSE;
+	}
+	
+	/* walk through the xmlDoc */
+	for (node = node->children; node; node = node->next) {
+		/* <table> tag for table creation */
+		if (!strcmp ((gchar *) node->name, "table")) {
+			GdaMetaDbObject *dbo;
+			dbo = create_table_object (mstruct, catalog_value, quoted_catalog,
+						   schema_value, quoted_schema, node, error);
+			if (!dbo) {
+				xmlFreeDoc (doc);
+				return FALSE;
+			}
+		}
+		/* <view> tag for view creation */
+		else if (!strcmp ((gchar *) node->name, "view")) {
+			TO_IMPLEMENT;
+			/*
+			GdaMetaDbObject *dbo;
+			dbo = create_view_object (mstruct, catalog_value, quoted_catalog,
+			schema_value, quoted_schema, node, error);
+			if (!dbo) {
+				xmlFreeDoc (doc);
+				return FALSE;
+			}
+			*/
+		}
+	}
+	xmlFreeDoc (doc);
+
+	/* sort database objects */
+	if (! gda_meta_struct_sort_db_objects (mstruct, GDA_META_SORT_DEPENDENCIES, error)) 
+		return FALSE;
+
+	/* dump as a graph */
+#ifdef GDA_DEBUG
+	gchar *graph;
+	GError *lerror = NULL;
+	graph = gda_meta_struct_dump_as_graph (mstruct, GDA_META_GRAPH_COLUMNS, &lerror);
+	if (graph) {
+		if (g_file_set_contents ("graph.dot", graph, -1, &lerror))
+			g_print ("Graph written to 'graph.dot'\n");
+		else {
+			g_print ("Could not save graph to file: %s\n", lerror && lerror->message ? lerror->message : "No detail");
+			g_error_free (lerror);
+		}
+		g_free (graph);
+	}
+	else {
+		g_print ("Could not create a graph: %s\n", lerror && lerror->message ? lerror->message : "No detail");
+		g_error_free (lerror);
+	}
+#endif
+
+	return TRUE;
+}
+
+static GdaMetaDbObject *
+create_table_object (GdaMetaStruct *mstruct, const GValue *catalog, const gchar *quoted_catalog,
+		     const GValue *schema, const gchar *quoted_schema, xmlNodePtr node, GError **error)
+{
+	GdaMetaDbObject *dbobj;
+	xmlChar *table_name, *table_schema;
+	GString *full_table_name;
+	GValue *v1 = NULL, *v2 = NULL, *v3 = NULL;
+
+	table_name = xmlGetProp (node, BAD_CAST "name");
+	if (!table_name) {
+		g_set_error (error, GDA_META_STRUCT_ERROR, 0, /* FIXME */
+			     _("Missing table name from <table> node"));
+		return NULL;
+	}
+	table_schema = xmlGetProp (node, BAD_CAST "schema");
+
+	/* determine object's complete name */
+	full_table_name = g_string_new ("");
+	if (quoted_catalog) {
+		v1 = gda_value_copy (catalog);
+		g_string_append (full_table_name, quoted_catalog);
+		g_string_append_c (full_table_name, '.');
+	}
+	if (table_schema) {
+		g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), (gchar *) table_schema);
+		if (_identifier_needs_quotes ((gchar *) table_schema)) {
+			gchar *tmp = _add_quotes ((gchar *) table_schema);
+			g_string_append (full_table_name, tmp);
+			g_free (tmp);
+		}
+		else
+			g_string_append (full_table_name, (gchar*) table_schema);
+		g_string_append_c (full_table_name, '.');
+	}
+	else if (quoted_schema) {
+		v2 = gda_value_copy (schema);
+		g_string_append (full_table_name, quoted_schema);
+		g_string_append_c (full_table_name, '.');
+	}
+	g_value_set_string ((v3 = gda_value_new (G_TYPE_STRING)), (gchar *) table_name);
+	if (_identifier_needs_quotes ((gchar *) table_name)) {
+		gchar *tmp = _add_quotes ((gchar *) table_name);
+		g_string_append (full_table_name, tmp);
+		g_free (tmp);
+	}
+	else
+		g_string_append (full_table_name, (gchar *) table_name);
+
+	/* a new GdaMetaDbObject structure */
+	dbobj = g_new0 (GdaMetaDbObject, 1);
+	dbobj->obj_type = GDA_META_DB_TABLE;
+	dbobj->obj_catalog = catalog ? g_value_dup_string (catalog) : NULL;
+	dbobj->obj_schema = table_schema ? g_strdup ((gchar *) table_schema) : 
+		(schema ? g_value_dup_string (schema) : NULL);
+	dbobj->obj_name = g_strdup ((gchar *) table_name);
+	dbobj->obj_full_name = full_table_name->str;
+	g_string_free (full_table_name, FALSE);
+	dbobj = gda_meta_struct_add_db_object (mstruct, dbobj, error);
+	if (!dbobj)
+		goto onerror;
+	
+	/* walk through the columns and Fkey nodes */
+	GdaMetaTable *mtable = GDA_META_TABLE (dbobj);
+	xmlNodePtr cnode;
+	GArray *pk_cols_array = g_array_new (FALSE, FALSE, sizeof (gint));
+	gint colsindex = 0;
+	for (cnode = node->children; cnode; cnode = cnode->next) {
+		if (!strcmp ((gchar *) cnode->name, "column")) {
+			xmlChar *cname, *ctype, *xstr;
+                        gboolean pkey = FALSE;
+                        gboolean nullok = FALSE; 
+ 
+                        if (strcmp ((gchar *) cnode->name, "column"))
+                                continue;
+                        cname = xmlGetProp (cnode, BAD_CAST "name");
+                        if (!cname) {
+				g_set_error (error, GDA_META_STRUCT_ERROR, 0, /* FIXME */
+					     _("Missing column name for table '%s'"), dbobj->obj_full_name);
+				goto onerror;
+			}
+			xstr = xmlGetProp (cnode, BAD_CAST "pkey");
+                        if (xstr) {
+                                if ((*xstr == 't') || (*xstr == 'T'))
+                                        pkey = TRUE;
+                                xmlFree (xstr);
+                        }
+                        xstr = xmlGetProp (cnode, BAD_CAST "nullok");
+                        if (xstr) {
+                                if ((*xstr == 't') || (*xstr == 'T'))
+                                        nullok = TRUE;
+                                xmlFree (xstr);
+                        }
+                        ctype = xmlGetProp (cnode, BAD_CAST "type");
+                        
+                        /* a field */
+			GdaMetaTableColumn *tcol;
+
+			tcol = g_new0 (GdaMetaTableColumn, 1);
+			tcol->column_name = g_strdup ((gchar *) cname);
+			xmlFree (cname);
+			tcol->column_type = g_strdup (ctype ? (gchar *) ctype : "string");
+			tcol->gtype = ctype ? gda_g_type_from_string ((gchar *) ctype) : G_TYPE_STRING;
+			if (ctype)
+				xmlFree (ctype);
+			tcol->pkey = pkey;
+			tcol->nullok = nullok;
+			if (pkey) 
+				g_array_append_val (pk_cols_array, colsindex);
+			colsindex++;
+				
+			/* FIXME: handle default value */
+			mtable->columns = g_slist_append (mtable->columns, tcol);
+		}
+		else if (!strcmp ((gchar *) cnode->name, "fkey")) {
+			xmlNodePtr fnode;
+			xmlChar *ref_table;
+
+			ref_table = xmlGetProp (cnode, BAD_CAST "ref_table");
+			if (!ref_table) {
+				g_set_error (error, GDA_META_STRUCT_ERROR, 0, /* FIXME */
+					     _("Missing foreign key's referenced table name for table '%s'"), 
+					     dbobj->obj_full_name);
+				goto onerror;
+			}
+			
+			/* referenced GdaMetaDbObject */
+			GdaMetaDbObject *ref_obj;
+			gchar *name_part, *schema_part, *catalog_part = NULL;
+			gchar *tmp = g_strdup (ref_table);
+			if (!_split_identifier_string (tmp, &schema_part, &name_part)) {
+				g_set_error (error, GDA_META_STRUCT_ERROR, 0, /* FIXME */
+					     _("Invalid referenced table name '%s'"), ref_table);
+				xmlFree (ref_table);
+				goto onerror;
+			}
+			if (schema_part && !_split_identifier_string (schema_part, &catalog_part, &schema_part)) {
+				g_set_error (error, GDA_META_STRUCT_ERROR, 0, /* FIXME */
+					     _("Invalid referenced table name '%s'"), ref_table);
+				xmlFree (ref_table);
+				goto onerror;
+			}
+			if (catalog_part) {
+				g_set_error (error, GDA_META_STRUCT_ERROR, 0, /* FIXME */
+					     _("Invalid referenced table name '%s'"), ref_table);
+				xmlFree (ref_table);
+				goto onerror;
+			}
+			GValue *rv2 = NULL, *rv3;
+			if (schema_part)
+				g_value_set_string ((rv2 = gda_value_new (G_TYPE_STRING)), schema_part);
+			g_value_set_string ((rv3 = gda_value_new (G_TYPE_STRING)), name_part);
+			ref_obj = gda_meta_struct_get_db_object (mstruct, NULL, rv2, rv3);
+			if (rv2) gda_value_free (rv2);
+			gda_value_free (rv3);
+
+			if (!ref_obj) {
+				ref_obj = g_new0 (GdaMetaDbObject, 1);
+				ref_obj->obj_type = GDA_META_DB_UNKNOWN;
+				ref_obj->obj_full_name = g_strdup ((gchar *) ref_table);
+				ref_obj->obj_name = name_part;
+				ref_obj->obj_schema = schema_part;
+				xmlFree (ref_table);
+				ref_obj = gda_meta_struct_add_db_object (mstruct, ref_obj, error);
+				if (! ref_obj) 
+					goto onerror;
+			}
+			else
+				xmlFree (ref_table);
+		
+			/* GdaMetaTableForeignKey structure */
+			GdaMetaTableForeignKey *mfkey;
+			GArray *fk_names_array = g_array_new (FALSE, FALSE, sizeof (gchar *));
+			GArray *ref_pk_names_array = g_array_new (FALSE, FALSE, sizeof (gchar *));
+			
+			for (fnode = cnode->children; fnode; fnode = fnode->next) {
+				xmlChar *col, *ref_col;
+				gchar *tmp;
+				if (strcmp ((gchar *) fnode->name, "part"))
+					continue;
+				col = xmlGetProp (fnode, BAD_CAST "column");
+				if (!col) {
+					g_set_error (error, GDA_META_STRUCT_ERROR, 0, /* FIXME */
+						     _("Missing foreign key's column name for table '%s'"), 
+						     dbobj->obj_full_name);
+					g_array_free (fk_names_array, TRUE);
+					g_array_free (ref_pk_names_array, TRUE);
+					goto onerror;
+				}
+				tmp = g_strdup ((gchar *) col);
+				g_array_append_val (fk_names_array, tmp);
+				ref_col = xmlGetProp (fnode, BAD_CAST "ref_column");
+				if (ref_col) {
+					tmp = g_strdup ((gchar *) ref_col);
+					g_array_append_val (ref_pk_names_array, tmp);
+					xmlFree (ref_col);
+				}
+				else {
+					tmp = g_strdup ((gchar *) col);
+					g_array_append_val (ref_pk_names_array, tmp);
+				}
+				xmlFree (col);
+			}
+
+			mfkey = g_new0 (GdaMetaTableForeignKey, 1);
+			mfkey->meta_table = dbobj;
+			mfkey->depend_on = ref_obj;
+			mfkey->cols_nb = fk_names_array->len;
+			mfkey->fk_cols_array = NULL;
+			mfkey->fk_names_array = (gchar **) fk_names_array->data;
+			mfkey->ref_pk_cols_array = NULL;
+			mfkey->ref_pk_names_array = (gchar **) ref_pk_names_array->data;
+			g_array_free (fk_names_array, FALSE);
+			g_array_free (ref_pk_names_array, FALSE);
+			mtable->fk_list = g_slist_append (mtable->fk_list, mfkey);
+		}
+	}
+	mtable->pk_cols_array = (gint*) pk_cols_array->data;
+	mtable->pk_cols_nb = pk_cols_array->len;
+	g_array_free (pk_cols_array, FALSE);
+
+	return dbobj;
+
+ onerror:
+	if (v1) gda_value_free (v1);
+	if (v2) gda_value_free (v2);
+	gda_value_free (v3);
+
+	return NULL;
+}
+
+static GdaMetaDbObject *
+create_view_object (GdaMetaStruct *mstruct, const GValue *catalog, const gchar *quoted_catalog,
+		    const GValue *schema, const gchar *quoted_schema, xmlNodePtr node, GError **error)
+{
+	TO_IMPLEMENT;
+	return NULL;
+}
+

Added: trunk/libgda/gda-meta-struct-private.h
==============================================================================
--- (empty file)
+++ trunk/libgda/gda-meta-struct-private.h	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,36 @@
+/* GDA common library
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GDA_META_STRUCT_PRIVATE_H__
+#define __GDA_META_STRUCT_PRIVATE_H__
+
+#include <libgda/gda-meta-struct.h>
+
+G_BEGIN_DECLS
+
+GdaMetaDbObject    *gda_meta_struct_add_db_object      (GdaMetaStruct *mstruct, GdaMetaDbObject *dbo, GError **error);
+gboolean            gda_meta_struct_load_from_xml_file (GdaMetaStruct *mstruct, const gchar *catalog, const gchar *schema, 
+							const gchar *xml_spec_file, GError **error);
+
+G_END_DECLS
+
+#endif

Modified: trunk/libgda/gda-meta-struct.c
==============================================================================
--- trunk/libgda/gda-meta-struct.c	(original)
+++ trunk/libgda/gda-meta-struct.c	Thu Jul 17 20:25:20 2008
@@ -59,6 +59,7 @@
 						    const GValue *catalog, const GValue *schema, const GValue *name);
 
 static void gda_meta_db_object_free (GdaMetaDbObject *dbo);
+static void gda_meta_db_object_free_contents (GdaMetaDbObject *dbo);
 static void gda_meta_table_free_contents (GdaMetaTable *table);
 static void gda_meta_view_free_contents (GdaMetaView *view);
 static void gda_meta_table_column_free (GdaMetaTableColumn *tcol);
@@ -1400,8 +1401,10 @@
 		fullname = g_strdup_printf ("%s.%s.%s", dbo->obj_catalog, dbo->obj_schema, dbo->obj_name);
 		if (dbo->obj_short_name) 
 			objname = g_strdup (dbo->obj_short_name);
-		else
+		else if (dbo->obj_schema)
 			objname = g_strdup_printf ("%s.%s", dbo->obj_schema, dbo->obj_name);
+		else
+			objname = g_strdup (dbo->obj_name);
 
 		/* node */
 		switch (dbo->obj_type) {
@@ -1502,7 +1505,7 @@
 }
 
 static void
-gda_meta_db_object_free (GdaMetaDbObject *dbo)
+gda_meta_db_object_free_contents (GdaMetaDbObject *dbo)
 {
 	g_free (dbo->obj_catalog);
 	g_free (dbo->obj_schema);
@@ -1526,6 +1529,13 @@
 }
 
 static void
+gda_meta_db_object_free (GdaMetaDbObject *dbo)
+{
+	gda_meta_db_object_free_contents (dbo);
+	g_free (dbo);
+}
+
+static void
 gda_meta_table_free_contents (GdaMetaTable *table)
 {
 	g_slist_foreach (table->columns, (GFunc) gda_meta_table_column_free, NULL);
@@ -1800,3 +1810,63 @@
 	
 	return FALSE;
 }
+
+/**
+ * gda_meta_struct_add_db_object
+ * @mstruct: a #GdaMetaStruct object
+ * @dbo: a #GdaMetaDbObject structure
+ * @error: a place to store errors, or %NULL
+ *
+ * Adds @dbo to the database objects known to @mstruct. In any case (whether an error occured or not)
+ * @dbo's responsability is then transferred to @smtruct and should
+ * not be used after calling this function (it may have been destroyed). If you need a pointer to the #GdaMetaDbObject
+ * for a database object, use gda_meta_struct_get_db_object().
+ *
+ * Returns: a pointer to the #GdaMetaDbObject used in @mstruct to represent the added database object (may be @dbo or not)
+ */
+GdaMetaDbObject *
+gda_meta_struct_add_db_object (GdaMetaStruct *mstruct, GdaMetaDbObject *dbo, GError **error)
+{
+	GdaMetaDbObject *edbo;
+	GValue *v1 = NULL, *v2 = NULL, *v3 = NULL;
+	g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), NULL);
+	g_return_val_if_fail (dbo, NULL);
+
+	if (!dbo->obj_name) {
+		g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_INCOHERENCE_ERROR,
+			     _("Missing object name in GdaMetaDbObject structure"));
+		gda_meta_db_object_free (dbo);
+		return NULL;
+	}
+	if (dbo->obj_catalog)
+		g_value_set_string ((v1 = gda_value_new (G_TYPE_STRING)), dbo->obj_catalog);
+	if (dbo->obj_schema)
+		g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), dbo->obj_schema);
+	g_value_set_string ((v3 = gda_value_new (G_TYPE_STRING)), dbo->obj_name);
+
+	edbo = gda_meta_struct_get_db_object (mstruct, v1, v2, v3);
+	if (v1) gda_value_free (v1);
+	if (v2) gda_value_free (v2);
+	gda_value_free (v3);
+
+	if (edbo) {
+		if (edbo->obj_type == GDA_META_DB_UNKNOWN) {
+			/* overwrite */
+			gda_meta_db_object_free_contents (edbo);
+			*edbo = *dbo;
+			g_free (dbo);
+			return edbo;
+		}
+		else {
+			g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_DUPLICATE_OBJECT_ERROR,
+				     _("Database object '%s' already exists"), edbo->obj_full_name);
+			gda_meta_db_object_free (dbo);
+			return NULL;
+		}
+	}
+	else {
+		mstruct->priv->db_objects = g_slist_append (mstruct->priv->db_objects, dbo);
+		g_hash_table_insert (mstruct->priv->index, dbo->obj_full_name, dbo);
+		return dbo;
+	}
+}

Modified: trunk/libgda/gda-meta-struct.h
==============================================================================
--- trunk/libgda/gda-meta-struct.h	(original)
+++ trunk/libgda/gda-meta-struct.h	Thu Jul 17 20:25:20 2008
@@ -113,12 +113,10 @@
 } GdaMetaView;
 
 /*
- * Struture to hold information about each object
- * which can be created in the internal GdaMetaStore's connection.
- * It is available for tables, views, triggers, ...
+ * Struture to hold information about each database object (tables, views, triggers, ...)
  *
  * Note: @obj_catalog, @obj_schema, @obj_name, @obj_short_name and @obj_full_name are case sensitive:
- *       one must call _identifier_needs_quotes() to know is it is necessary to surround by double quotes
+ *       one must call _identifier_needs_quotes() to know if is it is necessary to surround by double quotes
  *       before using in an SQL statement
  */
 typedef struct {

Added: trunk/libgda/gda-mutex.c
==============================================================================
--- (empty file)
+++ trunk/libgda/gda-mutex.c	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,218 @@
+/* GDA Library
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <libgda/gda-mutex.h>
+
+enum MutexRecStatus {
+	UNKNOWN,
+	RECURSIVE,
+	NON_RECURSIVE,
+	NON_SUPPORTED
+};
+
+static enum MutexRecStatus impl_status = UNKNOWN;
+
+struct _GdaMutex {
+	GMutex  *mutex; /* internal mutex to access the structure's data */
+	GCond   *cond;  /* condition to lock on */
+	GThread *owner; /* current owner of the mutex, or NULL if not owned */
+	short    depth;
+};
+
+/**
+ * gda_mutex_new
+ *
+ * Creates a new #GdaMutex.
+ *
+ * Note: Unlike g_mutex_new(), this function will return %NULL if g_thread_init() has not been called yet.
+ *
+ * Returns: a new #GdaMutex
+ */
+GdaMutex*
+gda_mutex_new ()
+{
+	if (G_UNLIKELY (impl_status == UNKNOWN)) {
+		static GStaticMutex init_mutex = G_STATIC_MUTEX_INIT;
+
+		g_static_mutex_lock (&init_mutex);
+		if (impl_status == UNKNOWN) {
+			if (!g_thread_supported ()) 
+				impl_status = NON_SUPPORTED;
+			else {
+				GMutex *m;
+				m = g_mutex_new ();
+				g_mutex_lock (m);
+				if (g_mutex_trylock (m)) {
+					impl_status = RECURSIVE;
+					g_mutex_unlock (m);
+				}
+				else
+					impl_status = NON_RECURSIVE;
+				g_mutex_unlock (m);
+				g_mutex_free (m);
+#ifdef GDA_DEBUG_NO
+				g_message ("GMutex %s recursive\n", (impl_status == RECURSIVE) ? "is" : "isn't");
+#endif
+			}
+		}
+                g_static_mutex_unlock (&init_mutex);
+	}
+
+	if (impl_status == NON_SUPPORTED) {
+		GdaMutex *m;
+		m = g_new0 (GdaMutex, 1);
+		return m;
+	}
+	else {
+		GdaMutex *m;
+		m = g_new0 (GdaMutex, 1);
+		m->mutex = g_mutex_new ();
+		m->cond = g_cond_new ();
+		m->owner = NULL;
+		m->depth = 0;
+		
+		return m;
+	}
+}
+
+/**
+ * gda_mutex_lock
+ * @m: a #GdaMutex
+ *
+ * Locks @m. If @m is already locked by another thread, the current thread will block until @m is unlocked by the other thread.
+ *
+ * This function can be used even if g_thread_init() has not yet been called, and, in that case, will do nothing.
+ *
+ * Note: unlike g_mutex_lock(), the #GdaMutex is recursive, which means a thread can lock it several times (and has
+ * to unlock it as many times to actually unlock it).
+ */
+void
+gda_mutex_lock (GdaMutex *m)
+{
+	if (impl_status == RECURSIVE)
+		g_mutex_lock (m->mutex);
+	else if (impl_status == NON_SUPPORTED)
+		return;
+	else {
+		GThread *th = g_thread_self ();
+		g_mutex_lock (m->mutex);
+		while (1) {
+			if (!m->owner) {
+				m->owner = th;
+				m->depth = 1;
+				break;
+			}
+			else if (m->owner == th) {
+				m->depth++;
+				break;
+			}
+			else {
+				g_cond_wait (m->cond, m->mutex);
+			}
+                }
+		g_mutex_unlock (m->mutex);
+	}
+}
+
+/**
+ * gda_mutex_trylock
+ * @m: a #GdaMutex
+ * 
+ * Returns: Tries to lock @m. If @m is already locked by another thread, it immediately returns FALSE.
+ * Otherwise it locks @m and returns TRUE
+ *
+ * This function can be used even if g_thread_init() has not yet been called, and, in that case, will immediately return TRUE.
+ *
+ * Note: Unlike g_mutex_trylock(), the #GdaMutex is recursive, which means a thread can lock it several times (and has
+ * to unlock it as many times to actually unlock it)
+ *
+ * Returns: TRUE, if @m could be locked.
+ */
+gboolean
+gda_mutex_trylock (GdaMutex *m)
+{
+	if (impl_status == RECURSIVE)
+		return g_mutex_trylock (m->mutex);
+	else if (impl_status == NON_SUPPORTED)
+		return TRUE;
+	else {
+		GThread *th = g_thread_self ();
+		gboolean retval;
+		g_mutex_lock (m->mutex);
+		if (!m->owner) {
+			m->owner = th;
+			m->depth = 1;
+			retval = TRUE;
+		}
+		else if (m->owner == th) {
+			m->depth++;
+			retval = TRUE;
+		}
+		else
+			retval = FALSE;
+		g_mutex_unlock (m->mutex);
+		return retval;
+	}
+}
+
+/**
+ * gda_mutex_unlock
+ * @m: a #GdaMutex
+ *
+ * Unlocks @m. If another thread is blocked in a gda_mutex_lock() call for @m, it will be woken and can lock @m itself.
+ * This function can be used even if g_thread_init() has not yet been called, and, in that case, will do nothing. 
+ */
+void
+gda_mutex_unlock (GdaMutex *m)
+{
+	if (impl_status == RECURSIVE)
+		g_mutex_unlock (m->mutex);
+	else if (impl_status == NON_SUPPORTED)
+		return;
+	else {
+		GThread *th = g_thread_self ();
+		g_mutex_lock (m->mutex);
+		g_assert (th == m->owner);
+		m->depth--;
+                if (m->depth == 0) {
+                        m->owner = NULL;
+			g_cond_signal (m->cond);
+                }
+		g_mutex_unlock (m->mutex);
+	}
+}
+
+/**
+ * gda_mutex_free
+ * @m: a #GdaMutex
+ *
+ * Destroys @m.
+ */
+void
+gda_mutex_free (GdaMutex *m)
+{
+	g_assert (m);
+	if (m->cond)
+		g_cond_free (m->cond);
+	m->cond = NULL;
+	if (m->mutex)
+		g_mutex_free (m->mutex);
+	m->mutex = NULL;
+	g_free (m);
+}

Added: trunk/libgda/gda-mutex.h
==============================================================================
--- (empty file)
+++ trunk/libgda/gda-mutex.h	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,40 @@
+/* GDA library
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GDA_MUTEX_H__
+#define __GDA_MUTEX_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GdaMutex GdaMutex;
+
+GdaMutex*   gda_mutex_new       (void);
+void        gda_mutex_lock      (GdaMutex *mutex);
+gboolean    gda_mutex_trylock   (GdaMutex *mutex);
+void        gda_mutex_unlock    (GdaMutex *mutex);
+void        gda_mutex_free      (GdaMutex *mutex);
+
+G_END_DECLS
+
+#endif

Modified: trunk/libgda/gda-server-provider.c
==============================================================================
--- trunk/libgda/gda-server-provider.c	(original)
+++ trunk/libgda/gda-server-provider.c	Thu Jul 17 20:25:20 2008
@@ -32,8 +32,8 @@
 #include <sql-parser/gda-sql-parser.h>
 #include <string.h>
 #include <glib/gi18n-lib.h>
+#include <libgda/gda-lockable.h>
 
-#define PARENT_TYPE G_TYPE_OBJECT
 #define CLASS(provider) (GDA_SERVER_PROVIDER_CLASS (G_OBJECT_GET_CLASS (provider)))
 
 static void gda_server_provider_class_init (GdaServerProviderClass *klass);
@@ -116,6 +116,8 @@
 	memset (&(klass->meta_funcs), 0, sizeof (GdaServerProviderMeta));
 	klass->xa_funcs = NULL;
 
+	klass->limiting_thread = g_thread_self (); /* default safe behaviour */
+
 	 /* Properties */
         object_class->set_property = gda_server_provider_set_property;
         object_class->get_property = gda_server_provider_get_property;
@@ -206,7 +208,7 @@
 		};
 		g_static_mutex_lock (&registering);
 		if (type == 0)
-			type = g_type_register_static (PARENT_TYPE, "GdaServerProvider", &info, G_TYPE_FLAG_ABSTRACT);
+			type = g_type_register_static (G_TYPE_OBJECT, "GdaServerProvider", &info, G_TYPE_FLAG_ABSTRACT);
 		g_static_mutex_unlock (&registering);
 	}
 
@@ -282,7 +284,7 @@
 /**
  * gda_server_provider_get_server_version
  * @provider: a #GdaServerProvider object.
- * @cnc: a #GdaConnection object.
+ * @cnc: a #GdaConnection object
  *
  * Get the version of the database to which the connection is opened.
  * 
@@ -291,10 +293,16 @@
 const gchar *
 gda_server_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc)
 {
+	const gchar *retval;
 	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
 	g_return_val_if_fail (CLASS (provider)->get_server_version != NULL, NULL);
 
-	return CLASS (provider)->get_server_version (provider, cnc);
+	gda_lockable_lock ((GdaLockable*) cnc);
+	retval = CLASS (provider)->get_server_version (provider, cnc);
+	gda_lockable_unlock ((GdaLockable*) cnc);
+
+	return retval;
 }
 
 /**
@@ -313,11 +321,17 @@
 gda_server_provider_supports_operation (GdaServerProvider *provider, GdaConnection *cnc, 
 					GdaServerOperationType type, GdaSet *options)
 {
+	gboolean retval = FALSE;
 	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
+	g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), FALSE);
+
+	if (cnc)
+		gda_lockable_lock ((GdaLockable*) cnc);
 	if (CLASS (provider)->supports_operation)
-		return CLASS (provider)->supports_operation (provider, cnc, type, options);
-	else
-		return FALSE;
+		retval = CLASS (provider)->supports_operation (provider, cnc, type, options);
+	if (cnc)
+		gda_lockable_unlock ((GdaLockable*) cnc);
+	return retval;
 }
 
 typedef struct {
@@ -447,10 +461,13 @@
 	g_static_mutex_unlock (&init_mutex);
 
 	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
+	g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), FALSE);
 
 	if (CLASS (provider)->create_operation) {
 		GdaServerOperation *op;
 
+		if (cnc)
+			gda_lockable_lock ((GdaLockable*) cnc);
 		op = CLASS (provider)->create_operation (provider, cnc, type, options, error);
 		if (op) {
 			/* test op's conformance */
@@ -493,6 +510,8 @@
 				xmlFreeNode (top);
 			}
 		}
+		if (cnc)
+			gda_lockable_unlock ((GdaLockable*) cnc);
 		return op;
 	}
 	else
@@ -519,8 +538,17 @@
 				      GdaServerOperation *op, GError **error)
 {
 	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
-	if (CLASS (provider)->render_operation)
-		return CLASS (provider)->render_operation (provider, cnc, op, error);
+	g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
+
+	if (CLASS (provider)->render_operation) {
+		gchar *retval;
+		if (cnc)
+			gda_lockable_lock ((GdaLockable*) cnc);
+		retval = CLASS (provider)->render_operation (provider, cnc, op, error);
+		if (cnc)
+			gda_lockable_unlock ((GdaLockable*) cnc);
+		return retval;
+	}
 	else
 		return NULL;
 }
@@ -541,7 +569,9 @@
 gda_server_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc, 
 				       GdaServerOperation *op, GError **error)
 {
+	gboolean retval;
 	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
+	g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), FALSE);
 
 #ifdef GDA_DEBUG_NO
 	{
@@ -555,11 +585,15 @@
 		xmlFreeDoc (doc);
 	}
 #endif
-
+	if (cnc)
+		gda_lockable_lock ((GdaLockable*) cnc);
 	if (CLASS (provider)->perform_operation)
-		return CLASS (provider)->perform_operation (provider, cnc, op, NULL, NULL, NULL, error);
+		retval = CLASS (provider)->perform_operation (provider, cnc, op, NULL, NULL, NULL, error);
 	else 
-		return gda_server_provider_perform_operation_default (provider, cnc, op, error);
+		retval = gda_server_provider_perform_operation_default (provider, cnc, op, error);
+	if (cnc)
+		gda_lockable_unlock ((GdaLockable*) cnc);
+	return retval;
 }
 
 /**
@@ -579,7 +613,10 @@
 	gboolean retval = FALSE;
 
 	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
+	g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), FALSE);
 
+	if (cnc)
+		gda_lockable_lock ((GdaLockable*) cnc);
 	if (CLASS (provider)->supports_feature)
 		retval = CLASS (provider)->supports_feature (provider, cnc, feature);
 
@@ -604,7 +641,8 @@
 			break;
 		}
 	}
-
+	if (cnc)
+		gda_lockable_unlock ((GdaLockable*) cnc);
 	return retval;
 }
 
@@ -621,12 +659,19 @@
 GdaDataHandler *
 gda_server_provider_get_data_handler_gtype (GdaServerProvider *provider, GdaConnection *cnc, GType for_type)
 {
+	GdaDataHandler *retval;
 	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
+	g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
 
+	if (cnc)
+		gda_lockable_lock ((GdaLockable*) cnc);
 	if (CLASS (provider)->get_data_handler)
-		return CLASS (provider)->get_data_handler (provider, cnc, for_type, NULL);
+		retval = CLASS (provider)->get_data_handler (provider, cnc, for_type, NULL);
 	else
-		return gda_server_provider_get_data_handler_default (provider, cnc, for_type, NULL);
+		retval = gda_server_provider_get_data_handler_default (provider, cnc, for_type, NULL);
+	if (cnc)
+		gda_lockable_unlock ((GdaLockable*) cnc);
+	return retval;
 }
 
 /**
@@ -642,13 +687,20 @@
 GdaDataHandler *
 gda_server_provider_get_data_handler_dbms (GdaServerProvider *provider, GdaConnection *cnc, const gchar *for_type)
 {
+	GdaDataHandler *retval;
 	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
 	g_return_val_if_fail (for_type && *for_type, NULL);
+	g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
 
+	if (cnc)
+		gda_lockable_lock ((GdaLockable*) cnc);
 	if (CLASS (provider)->get_data_handler)
-		return CLASS (provider)->get_data_handler (provider, cnc, G_TYPE_INVALID, for_type);
+		retval = CLASS (provider)->get_data_handler (provider, cnc, G_TYPE_INVALID, for_type);
 	else
-		return gda_server_provider_get_data_handler_default (provider, cnc, G_TYPE_INVALID, for_type);
+		retval = gda_server_provider_get_data_handler_default (provider, cnc, G_TYPE_INVALID, for_type);
+	if (cnc)
+		gda_lockable_unlock ((GdaLockable*) cnc);
+	return retval;
 }
 
 /**
@@ -668,19 +720,26 @@
 const gchar *
 gda_server_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConnection *cnc, GType type)
 {
+	const gchar *retval = NULL;
 	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
-	
-	if (CLASS (provider)->get_def_dbms_type)
-		return (CLASS (provider)->get_def_dbms_type)(provider, cnc, type);
-	else
-		return NULL;
+	g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
+
+	if (CLASS (provider)->get_def_dbms_type) {
+		if (cnc)
+			gda_lockable_lock ((GdaLockable*) cnc);
+		retval = (CLASS (provider)->get_def_dbms_type) (provider, cnc, type);
+		if (cnc)
+			gda_lockable_unlock ((GdaLockable*) cnc);
+	}
+
+	return retval;
 }
 
 
 /**
  * gda_server_provider_string_to_value
  * @provider: a server provider.
- * @cnc: a #GdaConnection object.
+ * @cnc: a #GdaConnection object, or %NULL
  * @string: the SQL string to convert to a value
  * @prefered_type: a #GType, or G_TYPE_INVALID
  *
@@ -706,7 +765,10 @@
 	gint i;
 
 	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
+	g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
 
+	if (cnc)
+		gda_lockable_lock ((GdaLockable*) cnc);
 	if (prefered_type != G_TYPE_INVALID) {
 		dh = gda_server_provider_get_data_handler_gtype (provider, cnc, prefered_type);
 		if (dh) {
@@ -775,6 +837,8 @@
 			}
 		}
 	}
+	if (cnc)
+		gda_lockable_unlock ((GdaLockable*) cnc);
 
 	return retval;
 }
@@ -795,18 +859,21 @@
 					 GdaConnection *cnc,
 					 GValue *from)
 {
+	gchar *retval = NULL;
 	GdaDataHandler *dh;
 
 	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
-	if (cnc)
-		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+	g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
 	g_return_val_if_fail (from != NULL, NULL);
 
+	if (cnc)
+		gda_lockable_lock ((GdaLockable*) cnc);
 	dh = gda_server_provider_get_data_handler_gtype (provider, cnc, G_VALUE_TYPE (from));
 	if (dh)
 		return gda_data_handler_get_sql_from_value (dh, from);
-	else
-		return NULL;
+	if (cnc)
+		gda_lockable_unlock ((GdaLockable*) cnc);
+	return retval;
 }
 
 /**
@@ -824,16 +891,21 @@
 gda_server_provider_escape_string (GdaServerProvider *provider, GdaConnection *cnc, const gchar *str)
 {
 	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
-	if (cnc)
-		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+	g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
 
 	if (CLASS (provider)->escape_string) {
+		gchar *retval;
 		if (! CLASS (provider)->unescape_string)
 			g_warning (_("GdaServerProvider object implements the %s virtual method but "
 				     "does not implement the %s one, please report this bug to "
 				     "http://bugzilla.gnome.org/ for the \"libgda\" product."), 
 				   "escape_string()", "unescape_string()");
-		return (CLASS (provider)->escape_string)(provider, cnc, str);
+		if (cnc)
+			gda_lockable_lock ((GdaLockable*) cnc);
+		retval = (CLASS (provider)->escape_string) (provider, cnc, str);
+		if (cnc)
+			gda_lockable_unlock ((GdaLockable*) cnc);
+		return retval;
 	}
 	else 
 		return gda_default_escape_string (str);
@@ -853,16 +925,21 @@
 gda_server_provider_unescape_string (GdaServerProvider *provider, GdaConnection *cnc, const gchar *str)
 {
 	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
-	if (cnc)
-		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+	g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
 
 	if (CLASS (provider)->unescape_string) {
+		gchar *retval;
 		if (! CLASS (provider)->escape_string)
 			g_warning (_("GdaServerProvider object implements the %s virtual method but "
 				     "does not implement the %s one, please report this bug to "
 				     "http://bugzilla.gnome.org/ for the \"libgda\" product."),
 				   "unescape_string()", "escape_string()");
-		return (CLASS (provider)->unescape_string)(provider, cnc, str);
+		if (cnc)
+			gda_lockable_lock ((GdaLockable*) cnc);
+		retval = (CLASS (provider)->unescape_string)(provider, cnc, str);
+		if (cnc)
+			gda_lockable_unlock ((GdaLockable*) cnc);
+		return retval;
 	}
 	else
 		return gda_default_unescape_string (str);
@@ -885,11 +962,17 @@
 GdaSqlParser *
 gda_server_provider_create_parser (GdaServerProvider *provider, GdaConnection *cnc)
 {
+	GdaSqlParser *parser = NULL;
+
 	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
+	g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
 
+	if (cnc)
+		gda_lockable_lock ((GdaLockable*) cnc);
 	if (CLASS (provider)->create_parser)
-		return (CLASS (provider)->create_parser)(provider, cnc);
-	else
-		return NULL;
+		parser = (CLASS (provider)->create_parser) (provider, cnc);
+	if (cnc)
+		gda_lockable_unlock ((GdaLockable*) cnc);
+	return parser;
 }
 

Modified: trunk/libgda/gda-server-provider.h
==============================================================================
--- trunk/libgda/gda-server-provider.h	(original)
+++ trunk/libgda/gda-server-provider.h	Thu Jul 17 20:25:20 2008
@@ -193,12 +193,15 @@
 } GdaServerProviderXa;
 
 typedef void (*GdaServerProviderAsyncCallback) (GdaServerProvider *provider, GdaConnection *cnc, guint task_id, 
-						gboolean result_status, gpointer data);
+						gboolean result_status, const GError *error, gpointer data);
+typedef void (*GdaServerProviderExecCallback) (GdaServerProvider *provider, GdaConnection *cnc, guint task_id, 
+					       GObject *result_obj, const GError *error, gpointer data);
 
 struct _GdaServerProviderClass {
 	GObjectClass parent_class;
 
 	/* provider information */
+	GThread                 * limiting_thread; /* if not NULL, then using the provider will be limited to this thread */
 	const gchar           *(* get_name)              (GdaServerProvider *provider);
 	const gchar           *(* get_version)           (GdaServerProvider *provider);
 	const gchar           *(* get_server_version)    (GdaServerProvider *provider, GdaConnection *cnc);
@@ -257,7 +260,7 @@
 							  GdaStatement *stmt, GdaSet *params, 
 							  GdaStatementModelUsage model_usage, 
 							  GType *col_types, GdaSet **last_inserted_row, 
-							  guint *task_id, GdaServerProviderAsyncCallback async_cb, 
+							  guint *task_id, GdaServerProviderExecCallback exec_cb, 
 							  gpointer cb_data, GError **error);
 
 	/* Misc */

Modified: trunk/libgda/gda-set.c
==============================================================================
--- trunk/libgda/gda-set.c	(original)
+++ trunk/libgda/gda-set.c	Thu Jul 17 20:25:20 2008
@@ -1235,6 +1235,7 @@
 gda_set_real_add_holder (GdaSet *set, GdaHolder *holder)
 {
 	GdaHolder *similar;
+	const gchar *hid;
 
 	if (g_slist_find (set->holders, holder))
 		return FALSE;
@@ -1243,11 +1244,17 @@
 	 * try to find a similar holder in the set->holders:
 	 * a holder B is similar to a holder A if it has the same ID
 	 */
-	similar = (GdaHolder*) g_hash_table_lookup (set->priv->holders_hash, gda_holder_get_id (holder));
+	hid = gda_holder_get_id (holder);
+	if (!hid) {
+		g_warning (_("GdaHolder needs to have an ID"));
+		return FALSE;
+	}
+	g_return_val_if_fail (hid, FALSE);
+	similar = (GdaHolder*) g_hash_table_lookup (set->priv->holders_hash, hid);
 	if (!similar) {
 		/* really add @holder to the set */
 		set->holders = g_slist_append (set->holders, holder);
-		g_hash_table_insert (set->priv->holders_hash, (gchar*) gda_holder_get_id (holder), holder);
+		g_hash_table_insert (set->priv->holders_hash, (gchar*) hid, holder);
 		g_object_ref (holder);
 		g_signal_connect (G_OBJECT (holder), "changed",
 				  G_CALLBACK (changed_holder_cb), set);

Modified: trunk/libgda/libgda.h.in
==============================================================================
--- trunk/libgda/libgda.h.in	(original)
+++ trunk/libgda/libgda.h.in	Thu Jul 17 20:25:20 2008
@@ -42,6 +42,7 @@
 #include <libgda/gda-data-model-dir.h>
 #include <libgda/gda-data-access-wrapper.h>
 #include <libgda/gda-data-proxy.h>
+#include <libgda/gda-lockable.h>
 #include <libgda/gda-log.h>
 #include <libgda/gda-quark-list.h>
 #include <libgda/gda-row.h>
@@ -72,6 +73,8 @@
 
 #include <libgda/gda-meta-store.h>
 
+#include <libgda/gda-mutex.h>
+
 G_BEGIN_DECLS
 
 void gda_init (void);

Modified: trunk/libgda/sql-parser/gda-sql-parser-private.h
==============================================================================
--- trunk/libgda/sql-parser/gda-sql-parser-private.h	(original)
+++ trunk/libgda/sql-parser/gda-sql-parser-private.h	Thu Jul 17 20:25:20 2008
@@ -25,6 +25,7 @@
 #include <glib-object.h>
 #include "gda-sql-parser.h"
 #include "gda-statement-struct-pspec.h"
+#include <libgda/gda-mutex.h>
 
 G_BEGIN_DECLS
 
@@ -39,6 +40,7 @@
 } TokenizerContext;
 
 struct _GdaSqlParserPrivate {
+	GdaMutex *mutex;
  	gchar    *sql;
 	GSList   *parsed_statements;
 

Modified: trunk/libgda/sql-parser/gda-sql-parser.c
==============================================================================
--- trunk/libgda/sql-parser/gda-sql-parser.c	(original)
+++ trunk/libgda/sql-parser/gda-sql-parser.c	Thu Jul 17 20:25:20 2008
@@ -28,6 +28,7 @@
 #include <libgda/gda-debug-macros.h>
 #include <libgda/sql-parser/gda-statement-struct-util.h>
 #include <libgda/sql-parser/token_types.h>
+#include <libgda/gda-lockable.h>
 
 /* 
  * Main static functions 
@@ -45,10 +46,15 @@
 					guint param_id,
 					GValue *value,
 					GParamSpec *pspec);
+
+/* GdaLockable interface */
+static void                 gda_sql_parser_lockable_init (GdaLockableClass *iface);
+static void                 gda_sql_parser_lock      (GdaLockable *lockable);
+static gboolean             gda_sql_parser_trylock   (GdaLockable *lockable);
+static void                 gda_sql_parser_unlock    (GdaLockable *lockable);
+
 /* get a pointer to the parents to be able to call their destructor */
 static GObjectClass  *parent_class = NULL;
-static GStaticRecMutex usage_mutex = G_STATIC_REC_MUTEX_INIT;
-
 
 static void gda_sql_parser_reset (GdaSqlParser *parser);
 static GValue *tokenizer_get_next_token (GdaSqlParser *parser); 
@@ -120,10 +126,18 @@
 			0,
 			(GInstanceInitFunc) gda_sql_parser_init
 		};
+
+		static GInterfaceInfo lockable_info = {
+                        (GInterfaceInitFunc) gda_sql_parser_lockable_init,
+			NULL,
+                        NULL
+                };
 		
 		g_static_mutex_lock (&registering);
-		if (type == 0)
+		if (type == 0) {
 			type = g_type_register_static (G_TYPE_OBJECT, "GdaSqlParser", &info, 0);
+			g_type_add_interface_static (type, GDA_TYPE_LOCKABLE, &lockable_info);
+		}
 		g_static_mutex_unlock (&registering);
 	}
 	return type;
@@ -170,6 +184,14 @@
 }
 
 static void
+gda_sql_parser_lockable_init (GdaLockableClass *iface)
+{
+	iface->i_lock = gda_sql_parser_lock;
+	iface->i_trylock = gda_sql_parser_trylock;
+	iface->i_unlock = gda_sql_parser_unlock;
+}
+
+static void
 gda_sql_parser_reset (GdaSqlParser *parser)
 {
 	g_free (parser->priv->sql);
@@ -209,6 +231,7 @@
 	klass = (GdaSqlParserClass*) G_OBJECT_GET_CLASS (parser);
 
 	parser->priv = g_new0 (GdaSqlParserPrivate, 1);
+	parser->priv->mutex = gda_mutex_new ();
 	parser->priv->flavour = GDA_SQL_PARSER_FLAVOUR_STANDARD;
 	if (klass->delim_alloc)
 		parser->priv->lemon_delimiter = klass->delim_alloc ((void*(*)(size_t)) g_malloc);
@@ -299,6 +322,8 @@
 			gda_sql_parserFree (parser->priv->lemon_parser, g_free);
 
 		g_array_free (parser->priv->passed_tokens, TRUE);
+
+		gda_mutex_free (parser->priv->mutex);
 		g_free (parser->priv);
 		parser->priv = NULL;
 	}
@@ -318,6 +343,7 @@
 
 	parser = GDA_SQL_PARSER (object);
 	if (parser->priv) {
+		gda_mutex_lock (parser->priv->mutex);
 		switch (param_id) {
 		case PROP_FLAVOUR:
 			parser->priv->flavour = g_value_get_int (value);
@@ -354,6 +380,7 @@
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
 			break;
 		}
+		gda_mutex_unlock (parser->priv->mutex);
 	}
 }
 
@@ -420,7 +447,7 @@
 	if (!sql)
 		return NULL;
 
-	g_static_rec_mutex_lock (&usage_mutex);
+	gda_mutex_lock (parser->priv->mutex);
 
 	if (remain)
 		*remain = NULL;
@@ -605,7 +632,7 @@
 
 	parser->priv->mode = parse_mode;
 
-	g_static_rec_mutex_unlock (&usage_mutex);
+	gda_mutex_unlock (parser->priv->mutex);
 
 	return stmt;
 }
@@ -649,7 +676,7 @@
 	if (!sql)
 		return batch;
 
-	g_static_rec_mutex_lock (&usage_mutex);
+	gda_mutex_lock (parser->priv->mutex);
 
 	int_sql = sql;
 	while (int_sql && allok) {
@@ -693,7 +720,7 @@
 		batch = NULL;
 	}
 
-	g_static_rec_mutex_unlock (&usage_mutex);
+	gda_mutex_unlock (parser->priv->mutex);
 	
 	return batch;
 }
@@ -1583,3 +1610,30 @@
 								parser->priv->pushed_contexts->data);
 	}
 }
+
+static void
+gda_sql_parser_lock (GdaLockable *lockable)
+{
+	GdaSqlParser *parser = (GdaSqlParser *) lockable;
+	g_return_if_fail (parser->priv);
+
+	gda_mutex_lock (parser->priv->mutex);
+}
+
+static gboolean
+gda_sql_parser_trylock (GdaLockable *lockable)
+{
+	GdaSqlParser *parser = (GdaSqlParser *) lockable;
+	g_return_val_if_fail (parser->priv, FALSE);
+
+	return gda_mutex_trylock (parser->priv->mutex);
+}
+
+static void
+gda_sql_parser_unlock (GdaLockable *lockable)
+{
+	GdaSqlParser *parser = (GdaSqlParser *) lockable;
+	g_return_if_fail (parser->priv);
+
+	gda_mutex_unlock (parser->priv->mutex);
+}

Modified: trunk/libgda/sql-parser/gda-sql-parser.h
==============================================================================
--- trunk/libgda/sql-parser/gda-sql-parser.h	(original)
+++ trunk/libgda/sql-parser/gda-sql-parser.h	Thu Jul 17 20:25:20 2008
@@ -103,7 +103,6 @@
 GdaBatch           *gda_sql_parser_parse_file_as_batch    (GdaSqlParser *parser, 
 							   const gchar *filename, GError **error);
 
-
 /* private API */
 void                gda_sql_parser_set_syntax_error      (GdaSqlParser *parser);
 void                gda_sql_parser_set_overflow_error    (GdaSqlParser *parser);

Modified: trunk/libgda/sqlite/gda-sqlite-provider.c
==============================================================================
--- trunk/libgda/sqlite/gda-sqlite-provider.c	(original)
+++ trunk/libgda/sqlite/gda-sqlite-provider.c	Thu Jul 17 20:25:20 2008
@@ -274,6 +274,16 @@
 
 	/* SQLite doe not support distributed transactions */
 	provider_class->xa_funcs = NULL;
+
+	/* If SQLite was not compiled with the SQLITE_THREADSAFE flag, then it is not
+	 * considered thread safe, and we limit the usage of the provider from the current thread */
+	if (! sqlite3_threadsafe ()) {
+		gda_log_message ("SQLite was not compiled with the SQLITE_THREADSAFE flag, "
+				 "only one thread can access the provider");
+		provider_class->limiting_thread = g_thread_self ();
+	}
+	else
+		provider_class->limiting_thread = NULL;
 }
 
 static void
@@ -626,6 +636,7 @@
 	}
 
 	cdata = g_new0 (SqliteConnectionData, 1);
+
 #ifdef HAVE_SQLITE
 	opening_cdata = cdata;
 #endif
@@ -724,6 +735,11 @@
 		db_connections_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
 	g_hash_table_insert (db_connections_hash, cdata->connection, cdata);
 #endif
+	
+	/* Note: we need to set the thread owner because as mentionned in
+	 * http://www.sqlite.org/cvstrac/wiki?p=MultiThreading, for portability, a connection should only
+	 * be used by the thread which created it. */
+	g_object_set (G_OBJECT (cnc), "thread-owner", g_thread_self (), NULL);
 
 	g_static_rec_mutex_unlock (&cnc_mutex);
 	return TRUE;
@@ -738,7 +754,7 @@
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
 	g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
 
-	/* nothing specific to do */
+	/* nothing specific to do: sqlite3_close() is called when SqliteConnectionData is destroyed */
 	return TRUE;
 }
 

Modified: trunk/po/POTFILES.in
==============================================================================
--- trunk/po/POTFILES.in	(original)
+++ trunk/po/POTFILES.in	Thu Jul 17 20:25:20 2008
@@ -19,6 +19,7 @@
 libgda/gda-log.c
 libgda/gda-meta-store.c
 libgda/gda-meta-struct.c
+libgda/gda-meta-struct-io.c
 libgda/gda-server-operation.c
 libgda/gda-server-provider.c
 libgda/gda-server-provider-extra.c

Modified: trunk/po/POTFILES.skip
==============================================================================
--- trunk/po/POTFILES.skip	(original)
+++ trunk/po/POTFILES.skip	Thu Jul 17 20:25:20 2008
@@ -58,3 +58,4 @@
 providers/xbase/libmain.c
 providers/xbase/xbase_specs_dsn.xml.in
 testing/html.c
+tests/gda-ddl-creator.c

Modified: trunk/providers/mysql/gda-mysql-meta.c
==============================================================================
--- trunk/providers/mysql/gda-mysql-meta.c	(original)
+++ trunk/providers/mysql/gda-mysql-meta.c	Thu Jul 17 20:25:20 2008
@@ -33,17 +33,18 @@
 #include <libgda/gda-set.h>
 #include <libgda/gda-holder.h>
 
-static gboolean append_a_row (GdaDataModel  *to_model,
-			      GError       **error,
-			      gint           nb,
-			                     ...);
+static gboolean
+append_a_row (GdaDataModel  *to_model,
+	      GError       **error,
+	      gint           nb,
+	      ...);
 
 /*
  * predefined statements' IDs
  */
 typedef enum {
 	I_STMT_CATALOG,
-        I_STMT_BTYPES,
+        /* I_STMT_BTYPES, */
         I_STMT_SCHEMAS,
         I_STMT_SCHEMAS_ALL,
         I_STMT_SCHEMA_NAMED,
@@ -58,10 +59,28 @@
         I_STMT_TABLES_CONSTRAINTS,
         I_STMT_TABLES_CONSTRAINTS_ALL,
         I_STMT_TABLES_CONSTRAINTS_NAMED,
+#if MYSQL_VERSION_ID >= 50110
         I_STMT_REF_CONSTRAINTS,
         I_STMT_REF_CONSTRAINTS_ALL,
+#endif
         I_STMT_KEY_COLUMN_USAGE,
-        I_STMT_KEY_COLUMN_USAGE_ALL
+        I_STMT_KEY_COLUMN_USAGE_ALL,
+        /* I_STMT_UDT, */
+        /* I_STMT_UDT_ALL, */
+        /* I_STMT_UDT_COLUMNS, */
+        /* I_STMT_UDT_COLUMNS_ALL, */
+        /* I_STMT_DOMAINS, */
+        /* I_STMT_DOMAINS_ALL, */
+        /* I_STMT_DOMAINS_CONSTRAINTS, */
+        /* I_STMT_DOMAINS_CONSTRAINTS_ALL, */
+        I_STMT_VIEWS_COLUMNS,
+        I_STMT_VIEWS_COLUMNS_ALL,
+        I_STMT_TRIGGERS,
+        I_STMT_TRIGGERS_ALL/* , */
+        /* I_STMT_EL_TYPES_COL, */
+        /* I_STMT_EL_TYPES_DOM, */
+        /* I_STMT_EL_TYPES_UDT, */
+        /* I_STMT_EL_TYPES_ALL */
 } InternalStatementItem;
 
 
@@ -73,7 +92,6 @@
         "SELECT DATABASE()",
 
         /* I_STMT_BTYPES */
-        "SELECT DISTINCT data_type, CONCAT(table_schema, '.', data_type), CASE data_type WHEN 'int' THEN 'gint' WHEN 'bigint' THEN 'gint64' WHEN 'blob' THEN 'GdaBinary' WHEN 'date' THEN 'GDate' WHEN 'time' THEN 'GdaTime' WHEN 'double' THEN 'gdouble' WHEN 'timestamp' THEN 'GdaTimestamp' ELSE 'string' END, CONCAT('Desc:', data_type), NULL, 0 FROM information_schema.columns WHERE table_schema = SCHEMA() ORDER BY 1",
 
         /* I_STMT_SCHEMAS */
 	"SELECT IFNULL(catalog_name, schema_name), schema_name, NULL, CASE schema_name WHEN 'information_schema' THEN 1 ELSE 0 END FROM information_schema.schemata WHERE schema_name = ##cat::string",
@@ -112,22 +130,24 @@
 	"SELECT IFNULL(constraint_catalog, constraint_schema), constraint_schema, constraint_name, IFNULL(table_catalog, table_schema), table_schema, table_name, constraint_type, NULL, 0, 0 FROM information_schema.table_constraints WHERE constraint_catalog = ##cat::string AND constraint_schema = ##schema::string AND table_name = ##name::string",
 
         /* I_STMT_TABLES_CONSTRAINTS_ALL */
-	"SELECT IFNULL(constraint_catalog, constraint_schema), constraint_schema, constraint_name, IFNULL(table_catalog, table_schema), table_schema, table_name, constraint_type, NULL, 0, 0 FROM information_schema.table_constraints",
+	"SELECT IFNULL(constraint_catalog, constraint_schema), constraint_schema, constraint_name, IFNULL(constraint_catalog, constraint_schema), table_schema, table_name, constraint_type, NULL, 0, 0 FROM information_schema.table_constraints",
 
         /* I_STMT_TABLES_CONSTRAINTS_NAMED */
 	"SELECT IFNULL(constraint_catalog, constraint_schema), constraint_schema, constraint_name, IFNULL(table_catalog, table_schema), table_schema, table_name, constraint_type, NULL, 0, 0 FROM information_schema.table_constraints WHERE constraint_catalog = ##cat::string AND constraint_schema = ##schema::string AND table_name = ##name::string AND constraint_name = ##name2::string",
 
+#if MYSQL_VERSION_ID >= 50110
         /* I_STMT_REF_CONSTRAINTS */
-	"SELECT IFNULL(t.constraint_catalog, t.constraint_schema), t.table_schema, t.table_name, t.constraint_name, IFNULL(k.constraint_catalog, k.constraint_schema), k.table_schema, k.table_name, k.constraint_name, NULL, NULL, NULL FROM information_schema.table_constraints t INNER JOIN information_schema.key_column_usage k ON t.table_schema=k.table_schema AND t.table_name=k.table_name AND t.constraint_name=k.constraint_name AND ((t.constraint_type = 'FOREIGN KEY' AND k.referenced_table_schema IS NOT NULL) OR (t.constraint_type != 'FOREIGN KEY' AND k.referenced_table_schema IS NULL)) WHERE t.constraint_catalog = ##cat::string AND t.table_schema = ##schema::string AND t.table_name = ##name::string AND t.constraint_name =  ##name2::string",
+	"SELECT IFNULL(t.constraint_catalog, t.constraint_schema), t.constraint_schema, r.constraint_name, IFNULL(r.constraint_catalog, r.constraint_schema), r.constraint_schema, r.match_option, r.update_rule, delete_rule FROM information_schema.referential_constraint r INNER JOIN information_schema.table_constraints t ON r.constraint_schema=t.constraint_schema AND r.constraint_name=t.constraint_name AND r.table_name=t.table_name WHERE r.constraint_catalog = ##cat::string AND r.constraint_schema = ##schema::string AND r.table_name = ##name AND r.constraint_name = ##name2::string",
 
         /* I_STMT_REF_CONSTRAINTS_ALL */
-	"SELECT IFNULL(t.constraint_catalog, t.constraint_schema), t.table_schema, t.table_name, t.constraint_name, IFNULL(k.constraint_catalog, k.constraint_schema), k.table_schema, k.table_name, k.constraint_name, NULL, NULL, NULL FROM information_schema.table_constraints t INNER JOIN information_schema.key_column_usage k ON t.table_schema=k.table_schema AND t.table_name=k.table_name AND t.constraint_name=k.constraint_name AND ((t.constraint_type = 'FOREIGN KEY' AND k.referenced_table_schema IS NOT NULL) OR (t.constraint_type != 'FOREIGN KEY' AND k.referenced_table_schema IS NULL))",
+	"SELECT IFNULL(t.constraint_catalog, t.constraint_schema), t.constraint_schema, r.constraint_name, IFNULL(r.constraint_catalog, r.constraint_schema), r.constraint_schema, r.match_option, r.update_rule, delete_rule FROM information_schema.referential_constraint r INNER JOIN information_schema.table_constraints t ON r.constraint_schema=t.constraint_schema AND r.constraint_name=t.constraint_name AND r.table_name=t.table_name",
+#endif
 
         /* I_STMT_KEY_COLUMN_USAGE */
-	"SELECT IFNULL(table_catalog, table_schema), table_schema, table_name, constraint_name, column_name WHERE table_catalog = ##cat::string AND table_schema = ##schema::string AND table_name = ##name::string AND constraint_name = ##name2::string",
+	"SELECT IFNULL(table_catalog, table_schema), table_schema, table_name, constraint_name, column_name FROM information_schema.key_column_usage WHERE table_catalog = ##cat::string AND table_schema = ##schema::string AND table_name = ##name::string AND constraint_name = ##name2::string",
 
         /* I_STMT_KEY_COLUMN_USAGE_ALL */
-	"SELECT IFNULL(table_catalog, table_schema), table_schema, table_name, constraint_name, column_name",
+	"SELECT IFNULL(table_catalog, table_schema), table_schema, table_name, constraint_name, column_name, ordinal_position FROM information_schema.key_column_usage",
 
         /* I_STMT_UDT */
 
@@ -146,12 +166,16 @@
         /* I_STMT_DOMAINS_CONSTRAINTS_ALL */
 
         /* I_STMT_VIEWS_COLUMNS */
+	"SELECT IFNULL(v.table_catalog, v.table_schema), v.table_schema, v.table_name, IFNULL(c.table_catalog, c.table_schema), c.table_schema, c.table_name, c.column_name FROM information_schema.columns c INNER JOIN information_schema.views v ON c.table_schema=v.table_schema AND c.table_name=v.table_name WHERE v.table_catalog = ##cat::string AND v.table_schema = ##schema::string AND v.table_name = ##name::string",
 
         /* I_STMT_VIEWS_COLUMNS_ALL */
+	"SELECT IFNULL(v.table_catalog, v.table_schema), v.table_schema, v.table_name, IFNULL(c.table_catalog, c.table_schema), c.table_schema, c.table_name, c.column_name FROM information_schema.columns c INNER JOIN information_schema.views v ON c.table_schema=v.table_schema AND c.table_name=v.table_name",
 
         /* I_STMT_TRIGGERS */
+	"SELECT IFNULL(trigger_catalog, trigger_schema), trigger_schema, trigger_name, event_manipulation, IFNULL(event_object_catalog, event_object_schema), event_object_schema, event_object_table, action_statement, action_orientation, action_timing, NULL, trigger_name, trigger_name FROM information_schema.triggers WHERE trigger_catalog = ##cat::string AND trigger_schema =  ##schema::string AND trigger_name = ##name::string",
 
         /* I_STMT_TRIGGERS_ALL */
+	"SELECT IFNULL(trigger_catalog, trigger_schema), trigger_schema, trigger_name, event_manipulation, IFNULL(event_object_catalog, event_object_schema), event_object_schema, event_object_table, action_statement, action_orientation, action_timing, NULL, trigger_name, trigger_name FROM information_schema.triggers",
 
         /* I_STMT_EL_TYPES_COL */
 
@@ -227,18 +251,91 @@
 			 GdaMetaContext     *context,
 			 GError            **error)
 {
-	GType col_types[] = {
-                G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
-                G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_NONE
-        };
+	typedef struct
+	{
+		gchar  *tname;
+		gchar  *gtype;
+		gchar  *comments;
+		gchar  *synonyms;
+	} BuiltinDataType;
+	BuiltinDataType data_types[] = {
+		{ "AUTO_INCREMENT", "gint" "The AUTO_INCREMENT attribute can be used to generate a unique identity for new rows", "" },
+		{ "BIGINT", "gint64", "A large integer. The signed range is -9223372036854775808 to 9223372036854775807. The unsigned range is 0 to 18446744073709551615.", "" },
+		{ "BINARY", "GdaBinary", "The BINARY type is similar to the CHAR type, but stores binary byte strings rather than non-binary character strings. M represents the column length in bytes.", "CHAR BYTE" },
+		{ "BIT", "gint" "A bit-field type. M indicates the number of bits per value, from 1 to 64. The default is 1 if M is omitted.", "" },
+		{ "BLOB", "GdaBinary", "A BLOB column with a maximum length of 65,535 (216 - 1) bytes. Each BLOB value is stored using a two-byte length prefix that indicates the number of bytes in the value.", "" },
+		{ "BLOB DATA TYPE", "GdaBinary", "A BLOB is a binary large object that can hold a variable amount of data. The four BLOB types are TINYBLOB, BLOB, MEDIUMBLOB, and LONGBLOB. These differ only in the maximum length of the values they can hold.", "" },
+		{ "BOOLEAN", "gboolean", "These types are synonyms for TINYINT(1). A value of zero is considered false. Non-zero values are considered true", "" },
+		{ "CHAR", "gchararray", "A fixed-length string that is always right-padded with spaces to the specified length when stored. M represents the column length in characters. The range of M is 0 to 255. If M is omitted, the length is 1.", "" },
+		{ "DATE", "GDate", "A date. The supported range is '1000-01-01' to '9999-12-31'. MySQL displays DATE values in 'YYYY-MM-DD' format, but allows assignment of values to DATE columns using either strings or numbers.", "" },
+		{ "DATETIME", "GdaTimestamp", "A date and time combination. The supported range is '1000-01-01 00:00:00' to '9999-12-31 23:59:59'. MySQL displays DATETIME values in 'YYYY-MM-DD HH:MM:SS' format, but allows assignment of values to DATETIME columns using either strings or numbers.", "" },
+		{ "DECIMAL", "GdaNumeric", "A packed \"exact\" fixed-point number. M is the total number of digits (the precision) and D is the number of digits after the decimal point (the scale). The decimal point and (for negative numbers) the \"-\" sign are not counted in M. If D is 0, values have no decimal point or fractional part. The maximum number of digits (M) for DECIMAL is 65 (64 from 5.0.3 to 5.0.5). The maximum number of supported decimals (D) is 30. If D is omitted, the default is 0. If M is omitted, the default is 10.", "DEC" },
+		{ "DOUBLE", "gdouble", "A normal-size (double-precision) floating-point number. Allowable values are -1.7976931348623157E+308 to -2.2250738585072014E-308, 0, and 2.2250738585072014E-308 to 1.7976931348623157E+308. These are the theoretical limits, based on the IEEE standard. The actual range might be slightly smaller depending on your hardware or operating system.", "DOUBLE PRECISION" },
+		{ "ENUM", "gchararray", "An enumeration. A string object that can have only one value, chosen from the list of values 'value1', 'value2', ..., NULL or the special '' error value. An ENUM column can have a maximum of 65,535 distinct values. ENUM values are represented internally as integers.", "" },
+		{ "FLOAT", "gfloat", "A small (single-precision) floating-point number. Allowable values are -3.402823466E+38 to -1.175494351E-38, 0, and 1.175494351E-38 to 3.402823466E+38. These are the theoretical limits, based on the IEEE standard. The actual range might be slightly smaller depending on your hardware or operating system.", "" },
+		{ "INT", "gint", "A normal-size integer. The signed range is -2147483648 to 2147483647. The unsigned range is 0 to 4294967295.", "INTEGER" },
+		{ "LONGBLOB", "GdaBinary", "A BLOB column with a maximum length of 4,294,967,295 or 4GB (232 - 1) bytes. The effective maximum length of LONGBLOB columns depends on the configured maximum packet size in the client/server protocol and available memory. Each LONGBLOB value is stored using a four-byte length prefix that indicates the number of bytes in the value.", "" },
+		{ "LONGTEXT", "GdaBinary", "A TEXT column with a maximum length of 4,294,967,295 or 4GB (232 - 1) characters. The effective maximum length is less if the value contains multi-byte characters. The effective maximum length of LONGTEXT columns also depends on the configured maximum packet size in the client/server protocol and available memory. Each LONGTEXT value is stored using a four-byte length prefix that indicates the number of bytes in the value.", "" },
+		{ "MEDIUMBLOB", "GdaBinary", "A BLOB column with a maximum length of 16,777,215 (224 - 1) bytes. Each MEDIUMBLOB value is stored using a three-byte length prefix that indicates the number of bytes in the value.", "" },
+		{ "MEDIUMINT", "gint", "A medium-sized integer. The signed range is -8388608 to 8388607. The unsigned range is 0 to 16777215.", "" },
+		{ "MEDIUMTEXT", "GdaBinary", "A TEXT column with a maximum length of 16,777,215 (224 - 1) characters. The effective maximum length is less if the value contains multi-byte characters. Each MEDIUMTEXT value is stored using a three-byte length prefix that indicates the number of bytes in the value.", "" },
+		{ "SET DATA TYPE", "gchararray", "A set. A string object that can have zero or more values, each of which must be chosen from the list of values 'value1', 'value2', ... A SET column can have a maximum of 64 members. SET values are represented internally as integers.", "" },
+		{ "SMALLINT", "gshort", "A small integer. The signed range is -32768 to 32767. The unsigned range is 0 to 65535.", "" },
+		{ "TEXT", "GdaBinary", "A TEXT column with a maximum length of 65,535 (216 - 1) characters. The effective maximum length is less if the value contains multi-byte characters. Each TEXT value is stored using a two-byte length prefix that indicates the number of bytes in the value.", "" },
+		{ "TIME", "GdaTime", "A time. The range is '-838:59:59' to '838:59:59'. MySQL displays TIME values in 'HH:MM:SS' format, but allows assignment of values to TIME columns using either strings or numbers.", "" },
+		{ "TIMESTAMP", "GdaTimestamp", "A timestamp. The range is '1970-01-01 00:00:01' UTC to partway through the year 2038. TIMESTAMP values are stored as the number of seconds since the epoch ('1970-01-01 00:00:00' UTC). A TIMESTAMP cannot represent the value '1970-01-01 00:00:00' because that is equivalent to 0 seconds from the epoch and the value 0 is reserved for representing '0000-00-00 00:00:00', the \"zero\" TIMESTAMP value.", "" },
+		{ "TINYBLOB", "GdaBinary", "A BLOB column with a maximum length of 255 (28 - 1) bytes. Each TINYBLOB value is stored using a one-byte length prefix that indicates the number of bytes in the value.", "" },
+		{ "TINYINT", "gchar", "A very small integer. The signed range is -128 to 127. The unsigned range is 0 to 255.", "" },
+		{ "TINYTEXT", "GdaBinary", "A TEXT column with a maximum length of 255 (28 - 1) characters. The effective maximum length is less if the value contains multi-byte characters. Each TINYTEXT value is stored using a one-byte length prefix that indicates the number of bytes in the value.", "" },
+		{ "VARBINARY", "GdaBinary", "The VARBINARY type is similar to the VARCHAR type, but stores binary byte strings rather than non-binary character strings. M represents the maximum column length in bytes.", "" },
+		{ "VARCHAR", "gchararray", "A variable-length string. M represents the maximum column length in characters. In MySQL 5.0, the range of M is 0 to 255 before MySQL 5.0.3, and 0 to 65,535 in MySQL 5.0.3 and later. The effective maximum length of a VARCHAR in MySQL 5.0.3 and later is subject to the maximum row size (65,535 bytes, which is shared among all columns) and the character set used. For example, utf8 characters can require up to three bytes per character, so a VARCHAR column that uses the utf8 character set can be declared to be a maximum of 21,844 characters.", "" },
+		{ "YEAR DATA TYPE", "gint", "A year in two-digit or four-digit format. The default is four-digit format. In four-digit format, the allowable values are 1901 to 2155, and 0000. In two-digit format, the allowable values are 70 to 69, representing years from 1970 to 2069. MySQL displays YEAR values in YYYY format, but allows you to assign values to YEAR columns using either strings or numbers.", "" } 
+	};
         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);
+
+	model = gda_meta_store_create_modify_data_model (store, context->table_name);
         if (model == NULL)
                 retval = FALSE;
 	else {
-                retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
+		gint i;
+		for (i = 0; i < sizeof(data_types) / sizeof(BuiltinDataType); ++i) {
+			BuiltinDataType *data_type = &(data_types[i]);
+			GList *values = NULL;
+			GValue *tmp_value = { 0, };
+
+			g_value_set_string (tmp_value = gda_value_new (G_TYPE_STRING), data_type->tname);
+			values = g_list_append (values, tmp_value); 
+
+			g_value_set_string (tmp_value = gda_value_new (G_TYPE_STRING), data_type->tname);
+			values = g_list_append (values, tmp_value); 
+
+			g_value_set_string (tmp_value = gda_value_new (G_TYPE_STRING), data_type->gtype);
+			values = g_list_append (values, tmp_value); 
+
+			g_value_set_string (tmp_value = gda_value_new (G_TYPE_STRING), data_type->comments);
+			values = g_list_append (values, tmp_value); 
+
+			if (data_type->synonyms && *(data_type->synonyms))
+				g_value_set_string (tmp_value = gda_value_new (G_TYPE_STRING), data_type->synonyms);
+			else
+				tmp_value = gda_value_new_null ();
+			values = g_list_append (values, tmp_value); 
+
+			g_value_set_boolean (tmp_value = gda_value_new (G_TYPE_BOOLEAN), FALSE);
+			values = g_list_append (values, tmp_value); 
+
+			if (gda_data_model_append_values (model, values, NULL) < 0) {
+				retval = FALSE;
+				break;
+			}
+
+			g_list_foreach (values, (GFunc) gda_value_free, NULL);
+			g_list_free (values);
+		}
+
+		if (retval != 0)
+			retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
 		g_object_unref (G_OBJECT(model));
 	}
 
@@ -252,7 +349,7 @@
 		      GdaMetaContext     *context,
 		      GError            **error)
 {
-	TO_IMPLEMENT;
+	// TO_IMPLEMENT;
 	return TRUE;
 }
 
@@ -265,7 +362,7 @@
 		     const GValue       *udt_catalog,
 		     const GValue       *udt_schema)
 {
-	TO_IMPLEMENT;
+	// TO_IMPLEMENT;
 	return TRUE;
 }
 
@@ -277,7 +374,7 @@
 			   GdaMetaContext     *context,
 			   GError            **error)
 {
-	TO_IMPLEMENT;
+	// TO_IMPLEMENT;
 	return TRUE;	
 }
 
@@ -291,7 +388,7 @@
 			  const GValue       *udt_schema,
 			  const GValue       *udt_name)
 {
-	TO_IMPLEMENT;
+	// TO_IMPLEMENT;
 	return TRUE;	
 }
 
@@ -483,7 +580,9 @@
 			retval = FALSE;
 		else {
 			retval = gda_meta_store_modify (store, context->table_name, model,
-							"schema_name=##name::string", error, "name", schema_name_n, NULL);
+							"schema_name=##name::string",
+							error,
+							"name", schema_name_n, NULL);
 			g_object_unref (G_OBJECT(model));
 		}
 	}
@@ -850,7 +949,8 @@
 
 		if (retval != 0)
 			retval = gda_meta_store_modify (store, context->table_name, proxy,
-							"table_schema=##schema::string AND table_name=##name::string", error,
+							"table_schema=##schema::string AND table_name=##name::string",
+							error,
 							"schema", table_schema, "name", table_name, NULL);
 		g_object_unref (G_OBJECT(proxy));
 		g_object_unref (G_OBJECT(model));
@@ -867,8 +967,30 @@
 			    GdaMetaContext     *context,
 			    GError            **error)
 {
-	TO_IMPLEMENT;
-	return TRUE;
+	// TO_IMPLEMENT;
+
+	GdaDataModel *model;
+	gboolean retval;
+	/* Check correct mysql server version. */
+	MysqlConnectionData *cdata;
+	cdata = (MysqlConnectionData *) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata)
+		return FALSE;
+	if (cdata->version_long < 50000) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_SERVER_VERSION_ERROR,
+			     _("Mysql version 5.0 at least is required"));
+		return FALSE;
+	}
+
+	model = gda_connection_statement_execute_select	(cnc, internal_stmt[I_STMT_VIEWS_COLUMNS_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
@@ -881,8 +1003,23 @@
 			   const GValue       *view_schema, 
 			   const GValue       *view_name)
 {
-	TO_IMPLEMENT;
-	return TRUE;
+	// TO_IMPLEMENT;
+	GdaDataModel *model;
+	gboolean retval;
+
+	gda_holder_set_value (gda_set_get_holder (i_set, "cat"), view_catalog);
+	gda_holder_set_value (gda_set_get_holder (i_set, "schema"), view_schema);
+	gda_holder_set_value (gda_set_get_holder (i_set, "name"), view_name);
+	model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_VIEWS_COLUMNS], 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
@@ -892,8 +1029,19 @@
 				  GdaMetaContext     *context,
 				  GError            **error)
 {
-	TO_IMPLEMENT;
-	return TRUE;
+	// TO_IMPLEMENT;
+
+	GdaDataModel *model;
+	gboolean retval;
+	model = gda_connection_statement_execute_select	(cnc, internal_stmt[I_STMT_TABLES_CONSTRAINTS_ALL], NULL, 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
@@ -907,8 +1055,40 @@
 				 const GValue       *table_name,
 				 const GValue       *constraint_name_n)
 {
-	TO_IMPLEMENT;
-	return TRUE;
+	// TO_IMPLEMENT;
+	
+	GdaDataModel *model;
+	gboolean retval;
+
+	gda_holder_set_value (gda_set_get_holder (i_set, "cat"), table_catalog);
+	gda_holder_set_value (gda_set_get_holder (i_set, "schema"), table_schema);
+	gda_holder_set_value (gda_set_get_holder (i_set, "name"), table_name);
+	if (!constraint_name_n) {
+		model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_TABLES_CONSTRAINTS], i_set, error);
+		if (model == NULL)
+			retval = FALSE;
+		else {
+			retval = gda_meta_store_modify (store, context->table_name, model,
+							"table_schema = ##schema::string AND table_name = ##name::string",
+							error,
+							"schema", table_schema, "name", table_name, NULL);
+			g_object_unref (G_OBJECT(model));
+		}
+	} else {
+		gda_holder_set_value (gda_set_get_holder (i_set, "name2"), constraint_name_n);
+		model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_TABLES_CONSTRAINTS_NAMED], i_set, error);
+		if (model == NULL)
+			retval = FALSE;
+		else {
+			retval = gda_meta_store_modify (store, context->table_name, model,
+							"table_schema=##schema::string AND table_name=##name::string AND constraint_name=##name2::string",
+							error,
+							"schema", table_schema, "name", table_name, "name2", constraint_name_n, NULL);
+			g_object_unref (G_OBJECT(model));
+		}
+	}
+
+	return retval;
 }
 
 gboolean
@@ -920,9 +1100,10 @@
 {
 	// TO_IMPLEMENT;
 
+#if MYSQL_VERSION_ID >= 50110
 	GdaDataModel *model;
 	gboolean retval;
-	model = gda_connection_statement_execute_select	(cnc, internal_stmt[I_STMT_REF_CONSTRAINTS_ALL], NULL, error);
+	model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_REF_CONSTRAINTS_ALL], NULL, error);
 	if (model == NULL)
 		retval = FALSE;
 	else {
@@ -931,6 +1112,9 @@
 	}
 
 	return retval;
+#else
+	return TRUE;
+#endif
 }
 
 gboolean
@@ -946,18 +1130,9 @@
 {
 	// TO_IMPLEMENT;
 
+#if MYSQL_VERSION_ID >= 50110
 	GdaDataModel *model;
 	gboolean retval;
-	/* Check correct mysql server version. */
-	MysqlConnectionData *cdata;
-	cdata = (MysqlConnectionData *) gda_connection_internal_get_provider_data (cnc);
-	if (!cdata)
-		return FALSE;
-	if (cdata->version_long < 50000) {
-		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_SERVER_VERSION_ERROR,
-			     _("Mysql version 5.0 at least is required"));
-		return FALSE;
-	}
 
 	/* Use a prepared statement for the "base" model. */
 	gda_holder_set_value (gda_set_get_holder (i_set, "cat"), table_catalog);
@@ -969,13 +1144,17 @@
 		retval = FALSE;
 	else {
 		retval = gda_meta_store_modify (store, context->table_name, model,
-						"table_schema=##schema::string AND table_name=##name::string AND constraint_name=##name2::string", error,
+						"table_schema=##schema::string AND table_name=##name::string AND constraint_name=##name2::string",
+						error,
 						"schema", table_schema, "name", table_name, "name2", constraint_name, NULL);
 		g_object_unref (G_OBJECT(model));
 
 	}
 
 	return retval;
+#else
+	return TRUE;
+#endif
 }
 
 gboolean
@@ -1036,7 +1215,8 @@
 		retval = FALSE;
 	else {
 		retval = gda_meta_store_modify (store, context->table_name, model,
-						"table_schema=##schema::string AND table_name=##name::string AND constraint_name=##name2::string", error,
+						"table_schema=##schema::string AND table_name=##name::string AND constraint_name=##name2::string",
+						error,
 						"schema", table_schema, "name", table_name, "name2", constraint_name, NULL);
 		g_object_unref (G_OBJECT(model));
 
@@ -1078,8 +1258,30 @@
 			   GdaMetaContext     *context,
 			   GError            **error)
 {
-	TO_IMPLEMENT;
-	return TRUE;
+	// TO_IMPLEMENT;
+
+	GdaDataModel *model;
+	gboolean retval;
+	/* Check correct mysql server version. */
+	MysqlConnectionData *cdata;
+	cdata = (MysqlConnectionData *) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata)
+		return FALSE;
+	if (cdata->version_long < 50000) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_SERVER_VERSION_ERROR,
+			     _("Mysql version 5.0 at least is required"));
+		return FALSE;
+	}
+
+	model = gda_connection_statement_execute_select	(cnc, internal_stmt[I_STMT_TRIGGERS_ALL], NULL, 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
@@ -1092,8 +1294,34 @@
 			  const GValue       *table_schema, 
 			  const GValue       *table_name)
 {
-	TO_IMPLEMENT;
-	return TRUE;
+	// TO_IMPLEMENT;
+
+	GdaDataModel *model;
+	gboolean retval;
+	/* Check correct mysql server version. */
+	MysqlConnectionData *cdata;
+	cdata = (MysqlConnectionData *) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata)
+		return FALSE;
+	if (cdata->version_long < 50000) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_SERVER_VERSION_ERROR,
+			     _("Mysql version 5.0 at least is required"));
+		return FALSE;
+	}
+
+	gda_holder_set_value (gda_set_get_holder (i_set, "cat"), table_catalog);
+	gda_holder_set_value (gda_set_get_holder (i_set, "schema"), table_schema);
+	gda_holder_set_value (gda_set_get_holder (i_set, "name"), table_name);
+	model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_TRIGGERS], 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-meta.h
==============================================================================
--- trunk/providers/mysql/gda-mysql-meta.h	(original)
+++ trunk/providers/mysql/gda-mysql-meta.h	Thu Jul 17 20:25:20 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
@@ -26,169 +26,362 @@
 
 G_BEGIN_DECLS
 
-void     _gda_mysql_provider_meta_init    (GdaServerProvider *provider);
+void
+_gda_mysql_provider_meta_init    (GdaServerProvider  *provider);
 
 /* _information_schema_catalog_name */
-gboolean _gda_mysql_meta__info            (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean
+_gda_mysql_meta__info            (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error);
 
 /* _builtin_data_types */
-gboolean _gda_mysql_meta__btypes          (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean
+_gda_mysql_meta__btypes          (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error);
 
 /* _udt */
-gboolean _gda_mysql_meta__udt             (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_mysql_meta_udt              (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
-					  const GValue *udt_catalog, const GValue *udt_schema);
+gboolean
+_gda_mysql_meta__udt             (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error);
+gboolean
+_gda_mysql_meta_udt              (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error,
+				  const GValue       *udt_catalog,
+				  const GValue       *udt_schema);
 
 /* _udt_columns */
-gboolean _gda_mysql_meta__udt_cols        (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_mysql_meta_udt_cols         (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
-					  const GValue *udt_catalog, const GValue *udt_schema, const GValue *udt_name);
+gboolean
+_gda_mysql_meta__udt_cols        (GdaServerProvider  *prov,
+				  GdaConnection *cnc, 
+				  GdaMetaStore *store,
+				  GdaMetaContext *context,
+				  GError **error);
+gboolean
+_gda_mysql_meta_udt_cols         (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error,
+				  const GValue       *udt_catalog,
+				  const GValue       *udt_schema,
+				  const GValue       *udt_name);
 
 /* _enums */
-gboolean _gda_mysql_meta__enums           (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_mysql_meta_enums            (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
-					  const GValue *udt_catalog, const GValue *udt_schema, const GValue *udt_name);
+gboolean
+_gda_mysql_meta__enums           (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error);
+gboolean
+_gda_mysql_meta_enums            (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error,
+				  const GValue       *udt_catalog,
+				  const GValue       *udt_schema,
+				  const GValue       *udt_name);
 
 /* _domains */
-gboolean _gda_mysql_meta__domains         (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_mysql_meta_domains          (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
-					  const GValue *domain_catalog, const GValue *domain_schema);
+gboolean
+_gda_mysql_meta__domains         (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store, 
+				  GdaMetaContext     *context,
+				  GError            **error);
+gboolean
+_gda_mysql_meta_domains          (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error,
+				  const GValue       *domain_catalog,
+				  const GValue       *domain_schema);
 
 /* _domain_constraints */
-gboolean _gda_mysql_meta__constraints_dom (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_mysql_meta_constraints_dom  (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
-					  const GValue *domain_catalog, const GValue *domain_schema, 
-					  const GValue *domain_name);
+gboolean
+_gda_mysql_meta__constraints_dom (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error);
+gboolean
+_gda_mysql_meta_constraints_dom  (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error,
+				  const GValue       *domain_catalog,
+				  const GValue       *domain_schema, 
+				  const GValue       *domain_name);
 
 /* _element_types */
-gboolean _gda_mysql_meta__el_types        (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_mysql_meta_el_types         (GdaServerProvider *prov, GdaConnection *cnc, 
-					   GdaMetaStore *store, GdaMetaContext *context, GError **error,
-					   const GValue *specific_name);
+gboolean
+_gda_mysql_meta__el_types        (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error);
+gboolean
+_gda_mysql_meta_el_types         (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error,
+				  const GValue       *specific_name);
 
 /* _collations */
-gboolean _gda_mysql_meta__collations      (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_mysql_meta_collations       (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
-					  const GValue *collation_catalog, const GValue *collation_schema, 
-					  const GValue *collation_name_n);
+gboolean
+_gda_mysql_meta__collations      (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error);
+gboolean
+_gda_mysql_meta_collations       (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error,
+				  const GValue       *collation_catalog,
+				  const GValue       *collation_schema, 
+				  const GValue       *collation_name_n);
 
 /* _character_sets */
-gboolean _gda_mysql_meta__character_sets  (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_mysql_meta_character_sets   (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
-					  const GValue *chset_catalog, const GValue *chset_schema, 
-					  const GValue *chset_name_n);
+gboolean
+_gda_mysql_meta__character_sets  (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error);
+gboolean
+_gda_mysql_meta_character_sets   (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error,
+				  const GValue       *chset_catalog,
+				  const GValue       *chset_schema, 
+				  const GValue       *chset_name_n);
 
 /* _schemata */
-gboolean _gda_mysql_meta__schemata        (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_mysql_meta_schemata         (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error, 
-					  const GValue *catalog_name, const GValue *schema_name_n);
+gboolean
+_gda_mysql_meta__schemata        (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error);
+gboolean
+_gda_mysql_meta_schemata         (GdaServerProvider *prov,
+				  GdaConnection     *cnc, 
+				  GdaMetaStore      *store,
+				  GdaMetaContext    *context,
+				  GError           **error, 
+				  const GValue      *catalog_name,
+				  const GValue      *schema_name_n);
 
 /* _tables or _views */
-gboolean _gda_mysql_meta__tables_views    (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_mysql_meta_tables_views     (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
-					  const GValue *table_catalog, const GValue *table_schema, 
-					  const GValue *table_name_n);
+gboolean
+_gda_mysql_meta__tables_views    (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error);
+gboolean
+_gda_mysql_meta_tables_views     (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error,
+				  const GValue       *table_catalog,
+				  const GValue       *table_schema, 
+				  const GValue       *table_name_n);
 
 /* _columns */
-gboolean _gda_mysql_meta__columns         (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_mysql_meta_columns          (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
-					  const GValue *table_catalog, const GValue *table_schema, 
-					  const GValue *table_name);
+gboolean
+_gda_mysql_meta__columns         (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error);
+gboolean
+_gda_mysql_meta_columns          (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error,
+				  const GValue       *table_catalog,
+				  const GValue       *table_schema, 
+				  const GValue       *table_name);
 
 /* _view_column_usage */
-gboolean _gda_mysql_meta__view_cols       (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_mysql_meta_view_cols        (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
-					  const GValue *view_catalog, const GValue *view_schema, 
-					  const GValue *view_name);
+gboolean
+_gda_mysql_meta__view_cols       (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error);
+gboolean
+_gda_mysql_meta_view_cols        (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error,
+				  const GValue       *view_catalog,
+				  const GValue       *view_schema, 
+				  const GValue       *view_name);
 
 /* _table_constraints */
-gboolean _gda_mysql_meta__constraints_tab (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_mysql_meta_constraints_tab  (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error, 
-					  const GValue *table_catalog, const GValue *table_schema, 
-					  const GValue *table_name, const GValue *constraint_name_n);
+gboolean
+_gda_mysql_meta__constraints_tab (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error);
+gboolean
+_gda_mysql_meta_constraints_tab  (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error, 
+				  const GValue       *table_catalog,
+				  const GValue       *table_schema, 
+				  const GValue       *table_name,
+				  const GValue       *constraint_name_n);
 
 /* _referential_constraints */
-gboolean _gda_mysql_meta__constraints_ref (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_mysql_meta_constraints_ref  (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
-					  const GValue *table_catalog, const GValue *table_schema, const GValue *table_name, 
-					  const GValue *constraint_name);
+gboolean
+_gda_mysql_meta__constraints_ref (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error);
+gboolean _gda_mysql_meta_constraints_ref  (GdaServerProvider  *prov,
+					   GdaConnection      *cnc, 
+					   GdaMetaStore       *store,
+					   GdaMetaContext     *context,
+					   GError            **error,
+					   const GValue       *table_catalog,
+					   const GValue       *table_schema,
+					   const GValue       *table_name, 
+					   const GValue       *constraint_name);
 
 /* _key_column_usage */
-gboolean _gda_mysql_meta__key_columns     (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_mysql_meta_key_columns      (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
-					  const GValue *table_catalog, const GValue *table_schema, 
-					  const GValue *table_name, const GValue *constraint_name);
+gboolean
+_gda_mysql_meta__key_columns     (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error);
+gboolean
+_gda_mysql_meta_key_columns      (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error,
+				  const GValue       *table_catalog,
+				  const GValue       *table_schema, 
+				  const GValue       *table_name,
+				  const GValue       *constraint_name);
 
 /* _check_column_usage */
-gboolean _gda_mysql_meta__check_columns   (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_mysql_meta_check_columns    (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
-					  const GValue *table_catalog, const GValue *table_schema, 
-					  const GValue *table_name, const GValue *constraint_name);
+gboolean
+_gda_mysql_meta__check_columns   (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error);
+gboolean
+_gda_mysql_meta_check_columns    (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error,
+				  const GValue       *table_catalog,
+				  const GValue       *table_schema, 
+				  const GValue       *table_name,
+				  const GValue       *constraint_name);
 
 /* _triggers */
-gboolean _gda_mysql_meta__triggers        (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_mysql_meta_triggers         (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
-					  const GValue *table_catalog, const GValue *table_schema, 
-					  const GValue *table_name);
+gboolean
+_gda_mysql_meta__triggers        (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error);
+gboolean
+_gda_mysql_meta_triggers         (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error,
+				  const GValue       *table_catalog,
+				  const GValue       *table_schema, 
+				  const GValue       *table_name);
 
 /* _routines */
-gboolean _gda_mysql_meta__routines       (GdaServerProvider *prov, GdaConnection *cnc, 
-					 GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_mysql_meta_routines        (GdaServerProvider *prov, GdaConnection *cnc, 
-					 GdaMetaStore *store, GdaMetaContext *context, GError **error,
-					 const GValue *routine_catalog, const GValue *routine_schema, 
-					 const GValue *routine_name_n);
+gboolean
+_gda_mysql_meta__routines       (GdaServerProvider  *prov,
+				 GdaConnection      *cnc, 
+				 GdaMetaStore       *store,
+				 GdaMetaContext     *context,
+				 GError            **error);
+gboolean
+_gda_mysql_meta_routines        (GdaServerProvider  *prov,
+				 GdaConnection      *cnc, 
+				 GdaMetaStore       *store,
+				 GdaMetaContext     *context,
+				 GError            **error,
+				 const GValue       *routine_catalog,
+				 const GValue       *routine_schema, 
+				 const GValue       *routine_name_n);
 
 /* _routine_columns */
-gboolean _gda_mysql_meta__routine_col     (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_mysql_meta_routine_col      (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
-					  const GValue *rout_catalog, const GValue *rout_schema, 
-					  const GValue *rout_name);
+gboolean
+_gda_mysql_meta__routine_col     (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error);
+gboolean
+_gda_mysql_meta_routine_col      (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error,
+				  const GValue       *rout_catalog,
+				  const GValue       *rout_schema, 
+				  const GValue       *rout_name);
 
 /* _parameters */
-gboolean _gda_mysql_meta__routine_par     (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_mysql_meta_routine_par      (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
-					  const GValue *rout_catalog, const GValue *rout_schema, 
-					  const GValue *rout_name);
+gboolean
+_gda_mysql_meta__routine_par     (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error);
+gboolean
+_gda_mysql_meta_routine_par      (GdaServerProvider  *prov,
+				  GdaConnection      *cnc, 
+				  GdaMetaStore       *store,
+				  GdaMetaContext     *context,
+				  GError            **error,
+				  const GValue       *rout_catalog,
+				  const GValue       *rout_schema, 
+				  const GValue       *rout_name);
 
 
 G_END_DECLS

Modified: trunk/providers/mysql/gda-mysql-parser.c
==============================================================================
--- trunk/providers/mysql/gda-mysql-parser.c	(original)
+++ trunk/providers/mysql/gda-mysql-parser.c	Thu Jul 17 20:25:20 2008
@@ -3,7 +3,7 @@
  * Copyright (C) 2008 The GNOME Foundation
  *
  * AUTHORS:
- *      TO_ADD: your name and email
+ *       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

Modified: trunk/providers/mysql/gda-mysql-provider.c
==============================================================================
--- trunk/providers/mysql/gda-mysql-provider.c	(original)
+++ trunk/providers/mysql/gda-mysql-provider.c	Thu Jul 17 20:25:20 2008
@@ -306,6 +306,13 @@
 	provider_class->xa_funcs->xa_rollback = gda_mysql_provider_xa_rollback;
 	provider_class->xa_funcs->xa_recover = gda_mysql_provider_xa_recover;
 	
+	if (! mysql_thread_safe ()) {
+		gda_log_message ("MySQL was not compiled with the --enable-thread-safe-client flag, "
+				 "only one thread can access the provider");
+		provider_class->limiting_thread = g_thread_self ();
+	}
+	else
+		provider_class->limiting_thread = NULL;
 }
 
 static void
@@ -1447,7 +1454,7 @@
 	if (mysql_stmt_execute (cdata->mysql_stmt)) {
 		event = _gda_mysql_make_error (cnc, NULL, cdata->mysql_stmt, error);
 	} else {
-		//	
+
 		/* execute prepared statement using C API depending on its kind */
 		if (!g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "SELECT", 6) ||
 		    !g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "SHOW", 4) ||

Modified: trunk/providers/mysql/libmain.c
==============================================================================
--- trunk/providers/mysql/libmain.c	(original)
+++ trunk/providers/mysql/libmain.c	Thu Jul 17 20:25:20 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

Modified: trunk/providers/postgres/gda-postgres-provider.c
==============================================================================
--- trunk/providers/postgres/gda-postgres-provider.c	(original)
+++ trunk/providers/postgres/gda-postgres-provider.c	Thu Jul 17 20:25:20 2008
@@ -260,6 +260,16 @@
 	provider_class->xa_funcs->xa_commit = gda_postgres_provider_xa_commit;
 	provider_class->xa_funcs->xa_rollback = gda_postgres_provider_xa_rollback;
 	provider_class->xa_funcs->xa_recover = gda_postgres_provider_xa_recover;
+
+	/* If PostgreSQL was not compiled with the --enable-thread-safety flag, then libPQ is not
+	 * considered thread safe, and we limit the usage of the provider from the current thread */
+	if (! PQisthreadsafe ()) {
+		gda_log_message ("PostgreSQL was not compiled with the --enable-thread-safety flag, "
+				 "only one thread can access the provider");
+		provider_class->limiting_thread = g_thread_self ();
+	}
+	else
+		provider_class->limiting_thread = NULL;
 }
 
 static void

Modified: trunk/tests/Makefile.am
==============================================================================
--- trunk/tests/Makefile.am	(original)
+++ trunk/tests/Makefile.am	Thu Jul 17 20:25:20 2008
@@ -1,2 +1,30 @@
-SUBDIRS = providers parser value-holders meta-store data-models
+noinst_LTLIBRARIES = libgda-test-4.0.la
+noinst_PROGRAMS = test-ddl-creator
 
+SUBDIRS = providers parser value-holders meta-store data-models multi-threading
+
+AM_CPPFLAGS = \
+        -I$(top_builddir) \
+        -I$(top_srcdir) \
+        -I$(top_srcdir)/libgda \
+        $(LIBGDA_CFLAGS)
+
+test_headers = \
+        gda-ddl-creator.h
+
+libgda_test_4_0_la_SOURCES = \
+        $(test_headers) \
+        gda-ddl-creator.c
+
+libgda_test_4_0_la_LDFLAGS = -version-info $(GDA_CURRENT):$(GDA_REVISION):$(GDA_AGE) $(NO_UNDEFINED)
+libgda_test_4_0_la_LIBADD = \
+	$(LIBGDA_LIBS) \
+	$(top_builddir)/libgda/libgda-4.0.la 
+
+test_ddl_creator_SOURCES = \
+        test-ddl-creator.c
+
+test_ddl_creator_LDADD = \
+        $(top_builddir)/libgda/libgda-4.0.la \
+	libgda-test-4.0.la \
+        $(LIBGDA_LIBS)

Modified: trunk/tests/data-models/Makefile.am
==============================================================================
--- trunk/tests/data-models/Makefile.am	(original)
+++ trunk/tests/data-models/Makefile.am	Thu Jul 17 20:25:20 2008
@@ -5,8 +5,8 @@
 	$(LIBGDA_CFLAGS) \
 	-DCHECK_FILES=\""$(top_srcdir)"\"
 
-check_PROGRAMS = check_model_import check_virtual check_data_proxy
-TESTS = check_model_import check_virtual check_data_proxy
+check_PROGRAMS = check_model_import check_virtual check_data_proxy check_model_copy
+TESTS = check_model_import check_virtual check_data_proxy check_model_copy
 
 common_sources = 
 
@@ -28,8 +28,13 @@
 	$(top_builddir)/libgda/libgda-4.0.la \
 	$(LIBGDA_LIBS)
 
+check_model_copy_SOURCES = $(common_sources) check_model_copy.c
+check_model_copy_LDADD = \
+	$(top_builddir)/libgda/libgda-4.0.la \
+	$(LIBGDA_LIBS)
 
 EXTRA_DIST = \
 	check_virtual.csv \
 	city.csv \
-	country.csv
+	country.csv \
+	data1.xml

Modified: trunk/tests/data-models/check_data_proxy.c
==============================================================================
--- trunk/tests/data-models/check_data_proxy.c	(original)
+++ trunk/tests/data-models/check_data_proxy.c	Thu Jul 17 20:25:20 2008
@@ -433,7 +433,7 @@
 	clean_expected_signals (proxy);
 	if (!check_data_model_n_rows (proxy, 159)) goto out;
 
-	values = make_values_list (0, G_TYPE_STRING, "BigCity2", G_TYPE_STRING, NULL, G_TYPE_STRING, "567890", 0);
+	values = make_values_list (0, G_TYPE_STRING, "BigCity2", G_TYPE_STRING, NULL, G_TYPE_STRING, "567890", (GType) 0);
 	declare_expected_signals ("U158", "Set values of new proxied row - 1");
 	if (!check_data_model_set_values (model, 158, values)) goto out;
 	free_values_list (values);
@@ -499,7 +499,7 @@
 	/*
 	 * change new proxied's rows values
 	 */
-	values = make_values_list (0, G_TYPE_STRING, "SmallCity2", G_TYPE_STRING, NULL, G_TYPE_STRING, "4907", 0);
+	values = make_values_list (0, G_TYPE_STRING, "SmallCity2", G_TYPE_STRING, NULL, G_TYPE_STRING, "4907", (GType) 0);
 	declare_expected_signals ("U1", "Set values of new proxied row - 2");
 	if (!check_data_model_set_values (model, 21, values)) goto out;
 	free_values_list (values);
@@ -728,7 +728,7 @@
 	/*
 	 * set several values for the new row 
 	 */
-	values = make_values_list (0, G_TYPE_STRING, "MyCity2", G_TYPE_STRING, NULL, G_TYPE_STRING, "12345", 0);
+	values = make_values_list (0, G_TYPE_STRING, "MyCity2", G_TYPE_STRING, NULL, G_TYPE_STRING, "12345", (GType) 0);
 	declare_expected_signals ("U159", "Set values of new row - new row");
 	if (!check_data_model_set_values (proxy, 159, values)) goto out;
 	free_values_list (values);
@@ -741,7 +741,7 @@
 	if (!check_data_model_value (proxy, 159, 5, G_TYPE_STRING, NULL)) goto out;
 	if (!check_data_model_n_rows (proxy, 160)) goto out;
 
-	values = make_values_list (0, G_TYPE_STRING, "MyCity3", G_TYPE_STRING, "ZZZ", G_TYPE_STRING, "787", 0);
+	values = make_values_list (0, G_TYPE_STRING, "MyCity3", G_TYPE_STRING, "ZZZ", G_TYPE_STRING, "787", (GType) 0);
 	declare_expected_signals ("U157", "Set values of new row - existing row");
 	if (!check_data_model_set_values (proxy, 157, values)) goto out;
 	free_values_list (values);
@@ -838,16 +838,16 @@
 	 * Set values for those 3 new rows
 	 */
 	declare_expected_signals ("4U50", "Set values of 3 new rows");
-	values = make_values_list (0, G_TYPE_STRING, "NR1", G_TYPE_STRING, "AAA", G_TYPE_STRING, "319", 0);
+	values = make_values_list (0, G_TYPE_STRING, "NR1", G_TYPE_STRING, "AAA", G_TYPE_STRING, "319", (GType) 0);
 	if (!check_data_model_set_values (proxy, 50, values)) goto out;
 	free_values_list (values);
-	values = make_values_list (0, G_TYPE_STRING, "NR2", G_TYPE_STRING, "BBB", G_TYPE_STRING, "320", 0);
+	values = make_values_list (0, G_TYPE_STRING, "NR2", G_TYPE_STRING, "BBB", G_TYPE_STRING, "320", (GType) 0);
 	if (!check_data_model_set_values (proxy, 51, values)) goto out;
 	free_values_list (values);
-	values = make_values_list (0, G_TYPE_STRING, "NR3", G_TYPE_STRING, "CCC", G_TYPE_STRING, "321", 0);
+	values = make_values_list (0, G_TYPE_STRING, "NR3", G_TYPE_STRING, "CCC", G_TYPE_STRING, "321", (GType) 0);
 	if (!check_data_model_set_values (proxy, 52, values)) goto out;
 	free_values_list (values);
-	values = make_values_list (0, G_TYPE_STRING, "NR4", G_TYPE_STRING, "DDD", G_TYPE_STRING, "330", 0);
+	values = make_values_list (0, G_TYPE_STRING, "NR4", G_TYPE_STRING, "DDD", G_TYPE_STRING, "330", (GType) 0);
 	if (!check_data_model_set_values (proxy, 53, values)) goto out;
 	free_values_list (values);
 	clean_expected_signals (proxy);
@@ -944,16 +944,16 @@
 	 * Set values for those 4 new rows
 	 */
 	declare_expected_signals ("4U159", "Set values of 4 new rows");
-	values = make_values_list (0, G_TYPE_STRING, "NR1", G_TYPE_STRING, "AAA", G_TYPE_STRING, "319", 0);
+	values = make_values_list (0, G_TYPE_STRING, "NR1", G_TYPE_STRING, "AAA", G_TYPE_STRING, "319", (GType) 0);
 	if (!check_data_model_set_values (proxy, 159, values)) goto out;
 	free_values_list (values);
-	values = make_values_list (0, G_TYPE_STRING, "NR2", G_TYPE_STRING, "BBB", G_TYPE_STRING, "320", 0);
+	values = make_values_list (0, G_TYPE_STRING, "NR2", G_TYPE_STRING, "BBB", G_TYPE_STRING, "320", (GType) 0);
 	if (!check_data_model_set_values (proxy, 160, values)) goto out;
 	free_values_list (values);
-	values = make_values_list (0, G_TYPE_STRING, "NR3", G_TYPE_STRING, "CCC", G_TYPE_STRING, "321", 0);
+	values = make_values_list (0, G_TYPE_STRING, "NR3", G_TYPE_STRING, "CCC", G_TYPE_STRING, "321", (GType) 0);
 	if (!check_data_model_set_values (proxy, 161, values)) goto out;
 	free_values_list (values);
-	values = make_values_list (0, G_TYPE_STRING, "NR4", G_TYPE_STRING, "DDD", G_TYPE_STRING, "330", 0);
+	values = make_values_list (0, G_TYPE_STRING, "NR4", G_TYPE_STRING, "DDD", G_TYPE_STRING, "330", (GType) 0);
 	if (!check_data_model_set_values (proxy, 162, values)) goto out;
 	free_values_list (values);
 	clean_expected_signals (proxy);
@@ -1045,7 +1045,7 @@
 		/*
 		 * Try to alter first row
 		 */
-		values = make_values_list (0, G_TYPE_STRING, "MyCity3", G_TYPE_STRING, "ZZZ", G_TYPE_STRING, "787", 0);
+		values = make_values_list (0, G_TYPE_STRING, "MyCity3", G_TYPE_STRING, "ZZZ", G_TYPE_STRING, "787", (GType) 0);
 		if (gda_data_model_set_values (proxy, 0, values, NULL)) {
 #ifdef CHECK_EXTRA_INFO
 			g_print ("ERROR: Should not be able to alter row 0 (as it is the prepended row)\n");

Added: trunk/tests/data-models/check_model_copy.c
==============================================================================
--- (empty file)
+++ trunk/tests/data-models/check_model_copy.c	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,142 @@
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <libgda/libgda.h>
+
+#define fail(x) g_warning (x)
+#define fail_if(x,y) if (x) g_warning (y)
+#define fail_unless(x,y) if (!(x)) g_warning (y)
+
+#define CHECK_EXTRA_INFO
+static gboolean do_test_load_file (const gchar *filename);
+
+int
+main (int argc, char **argv)
+{
+	int number_failed = 0;
+	GDir *dir;
+	GError *err = NULL;
+	const gchar *name;
+
+	gda_init ();
+
+	
+
+	if (argc == 2) {
+		if (g_str_has_suffix (argv[1], ".xml")) {
+			g_print ("Tested: %s\n", argv[1]);
+			if (!do_test_load_file (argv[1]))
+				number_failed ++;
+		}
+	}
+	else {
+		/* data models in tests/providers */
+		gchar *dirname;
+		dirname = g_build_filename (CHECK_FILES, "tests", "providers", NULL);
+		if (!(dir = g_dir_open (dirname, 0, &err))) {
+#ifdef CHECK_EXTRA_INFO
+			g_warning ("Could not open directory '%s': %s", dirname,
+				   err && err->message ? err->message : "No detail");
+#endif
+			return EXIT_FAILURE;
+		}
+
+		while ((name = g_dir_read_name (dir))) {
+			if (g_str_has_suffix (name, ".xml")) {
+				gchar *full_path = g_build_filename (dirname, name, NULL);
+				g_print ("Tested: %s\n", full_path);
+				if (!do_test_load_file (full_path))
+					number_failed ++;
+				g_free (full_path);
+			}
+		}
+		g_free (dirname);
+
+		/* data models in the current dir */
+		dirname = g_build_filename (CHECK_FILES, "tests", "data-models", NULL);
+		if (!(dir = g_dir_open (dirname, 0, &err))) {
+#ifdef CHECK_EXTRA_INFO
+			g_warning ("Could not open directory '%s': %s", dirname,
+				   err && err->message ? err->message : "No detail");
+#endif
+			return EXIT_FAILURE;
+		}
+
+		while ((name = g_dir_read_name (dir))) {
+			if (g_str_has_suffix (name, ".xml")) {
+				gchar *full_path = g_build_filename (dirname, name, NULL);
+				g_print ("Tested: %s\n", full_path);
+				if (!do_test_load_file (full_path))
+					number_failed ++;
+				g_free (full_path);
+			}
+		}
+		g_free (dirname);
+	}
+	g_dir_close (dir);
+
+	if (number_failed == 0)
+		g_print ("Ok.\n");
+	else
+		g_print ("%d failed\n", number_failed);
+
+	return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+static gboolean
+do_test_load_file (const gchar *filename)
+{
+	GdaDataModel *import, *copy = NULL;
+	GdaDataComparator *cmp = NULL;
+	GSList *errors;
+	gboolean retval = TRUE;
+	GError *error = NULL;
+
+	import = gda_data_model_import_new_file (filename, TRUE, NULL);
+
+	if ((errors = gda_data_model_import_get_errors (GDA_DATA_MODEL_IMPORT (import)))) {
+#ifdef CHECK_EXTRA_INFO
+		g_warning ("Could not load file '%s': ", filename);
+		for (; errors; errors = errors->next) 
+			g_print ("\t%s\n", 
+				 ((GError *)(errors->data))->message ? ((GError *)(errors->data))->message : "No detail");
+#endif
+		retval = FALSE;
+		goto out;
+	}
+
+	copy = (GdaDataModel*) gda_data_model_array_copy_model (import, &error);
+	if (!copy) {
+#ifdef CHECK_EXTRA_INFO
+		g_warning ("Could not copy data model: %s", error && error->message ? error->message : "No detail");
+#endif
+		g_error_free (error);
+		retval = FALSE;
+		goto out;
+	}
+
+	cmp = (GdaDataComparator*) gda_data_comparator_new (import, copy);
+	if (! gda_data_comparator_compute_diff (cmp, &error)) {
+#ifdef CHECK_EXTRA_INFO
+		g_warning ("Could not compute differences: %s", error && error->message ? error->message : "No detail");
+#endif
+		g_error_free (error);
+		retval = FALSE;
+		goto out;
+	}
+
+	if (gda_data_comparator_get_n_diffs (cmp) > 0) {
+#ifdef CHECK_EXTRA_INFO
+		g_print ("There are %d difference(s)\n", gda_data_comparator_get_n_diffs (cmp));
+#endif
+		retval = FALSE;
+	}
+
+ out:
+	g_object_unref (import);
+	if (copy)
+		g_object_unref (copy);
+	if (cmp)
+		g_object_unref (cmp);
+	return retval;
+}

Modified: trunk/tests/data-models/check_model_import.c
==============================================================================
--- trunk/tests/data-models/check_model_import.c	(original)
+++ trunk/tests/data-models/check_model_import.c	Thu Jul 17 20:25:20 2008
@@ -15,21 +15,12 @@
 {
 	int number_failed = 0;
 	GDir *dir;
-	gchar *dirname;
 	GError *err = NULL;
 	const gchar *name;
 
 	gda_init ();
 
-	dirname = g_build_filename (CHECK_FILES, "tests", "providers", NULL);
-	if (!(dir = g_dir_open (dirname, 0, &err))) {
-#ifdef CHECK_EXTRA_INFO
-		g_warning ("Could not open directory '%s': %s", dirname,
-			   err && err->message ? err->message : "No detail");
-#endif
-		return EXIT_FAILURE;
-	}
-	g_free (dirname);
+	
 
 	if (argc == 2) {
 		if (g_str_has_suffix (argv[1], ".xml")) {
@@ -38,38 +29,73 @@
 				number_failed ++;
 		}
 	}
-	else 
+	else {
+		/* data models in tests/providers */
+		gchar *dirname;
+		dirname = g_build_filename (CHECK_FILES, "tests", "providers", NULL);
+		if (!(dir = g_dir_open (dirname, 0, &err))) {
+#ifdef CHECK_EXTRA_INFO
+			g_warning ("Could not open directory '%s': %s", dirname,
+				   err && err->message ? err->message : "No detail");
+#endif
+			return EXIT_FAILURE;
+		}
+
 		while ((name = g_dir_read_name (dir))) {
 			if (g_str_has_suffix (name, ".xml")) {
-				g_print ("Tested: %s\n", name);
-				if (!do_test_load_file (name))
+				gchar *full_path = g_build_filename (dirname, name, NULL);
+				g_print ("Tested: %s\n", full_path);
+				if (!do_test_load_file (full_path))
 					number_failed ++;
+				g_free (full_path);
 			}
 		}
+		g_free (dirname);
+
+		/* data models in the current dir */
+		dirname = g_build_filename (CHECK_FILES, "tests", "data-models", NULL);
+		if (!(dir = g_dir_open (dirname, 0, &err))) {
+#ifdef CHECK_EXTRA_INFO
+			g_warning ("Could not open directory '%s': %s", dirname,
+				   err && err->message ? err->message : "No detail");
+#endif
+			return EXIT_FAILURE;
+		}
+
+		while ((name = g_dir_read_name (dir))) {
+			if (g_str_has_suffix (name, ".xml")) {
+				gchar *full_path = g_build_filename (dirname, name, NULL);
+				g_print ("Tested: %s\n", full_path);
+				if (!do_test_load_file (full_path))
+					number_failed ++;
+				g_free (full_path);
+			}
+		}
+		g_free (dirname);
+	}
 	g_dir_close (dir);
 
 	if (number_failed == 0)
 		g_print ("Ok.\n");
 	else
 		g_print ("%d failed\n", number_failed);
+
 	return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
 static gboolean
 do_test_load_file (const gchar *filename)
 {
-	gchar *file;
 	GdaDataModel *import;
 	GSList *errors;
 	gboolean retval = TRUE;
 	gchar *export, *contents;
 
-	file = g_build_filename (CHECK_FILES, "tests", "providers", filename, NULL);
-	import = gda_data_model_import_new_file (file, TRUE, NULL);
+	import = gda_data_model_import_new_file (filename, TRUE, NULL);
 
 	if ((errors = gda_data_model_import_get_errors (GDA_DATA_MODEL_IMPORT (import)))) {
 #ifdef CHECK_EXTRA_INFO
-		g_warning ("Could not load the expected schema file '%s': ", file);
+		g_warning ("Could not load file '%s': ", filename);
 		for (; errors; errors = errors->next) 
 			g_print ("\t%s\n", 
 				 ((GError *)(errors->data))->message ? ((GError *)(errors->data))->message : "No detail");
@@ -79,7 +105,7 @@
 	}
 
 	export = gda_data_model_export_to_string (import, GDA_DATA_MODEL_IO_DATA_ARRAY_XML, NULL, 0, NULL, 0, NULL);
-	g_assert (g_file_get_contents (file, &contents, NULL, NULL));
+	g_assert (g_file_get_contents (filename, &contents, NULL, NULL));
 	if (strcmp (export, contents)) {
 #ifdef CHECK_EXTRA_INFO
 		g_print ("========== Imported data model ==========\n");

Added: trunk/tests/data-models/data1.xml
==============================================================================
--- (empty file)
+++ trunk/tests/data-models/data1.xml	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<gda_array id="FIELDS_A" name="Table's columns">
+  <gda_array_field id="COLUMN_NAME" name="Field name" title="Field name" gdatype="gchararray"/>
+  <gda_array_field id="COLUMN_TYPE" name="Data type" title="Data type" gdatype="gchararray"/>
+  <gda_array_field id="COLUMN_SIZE" name="Size" title="Size" gdatype="guint"/>
+  <gda_array_field id="COLUMN_SCALE" name="Scale" title="Scale" gdatype="guint"/>
+  <gda_array_field id="COLUMN_NNUL" name="Not NULL" title="Not NULL" gdatype="gboolean"/>
+  <gda_array_field id="COLUMN_AUTOINC" name="Auto increment" title="Auto increment" gdatype="gboolean"/>
+  <gda_array_field id="COLUMN_UNIQUE" name="Unique" title="Unique" gdatype="gboolean"/>
+  <gda_array_field id="COLUMN_PKEY" name="Primary key" title="Primary key" gdatype="gboolean"/>
+  <gda_array_field id="COLUMN_DEFAULT" name="Default" title="Default" gdatype="gchararray"/>
+  <gda_array_field id="COLUMN_CHECK" name="Check" title="Check" gdatype="gchararray"/>
+  <gda_array_data>
+    <gda_array_row>
+      <gda_value>id</gda_value>
+      <gda_value>serial</gda_value>
+      <gda_value isnull="t"/>
+      <gda_value isnull="t"/>
+      <gda_value>TRUE</gda_value>
+      <gda_value>TRUE</gda_value>
+      <gda_value>TRUE</gda_value>
+      <gda_value>TRUE</gda_value>
+      <gda_value/>
+      <gda_value/>
+    </gda_array_row>
+  </gda_array_data>
+</gda_array>

Added: trunk/tests/dbstruct.xml
==============================================================================
--- (empty file)
+++ trunk/tests/dbstruct.xml	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Tests databases schema
+-->
+
+
+<schema>
+  <!-- provider specific information 
+       use <replace> to replace something with something else (context can only be "/FIELDS_A/@COLUMN_TYPE" at the moment)
+       use <ignore> to ignore some parts (context can only be "/FKEY_S" or "/FIELDS_A/@COLUMN_PKEY" at the moment)
+    -->
+  <specifics>
+    <provider name="PostgreSQL">
+      <replace context="/FIELDS_A/@COLUMN_TYPE" expr="string" replace_with="varchar"/>
+      <replace context="/FIELDS_A/@COLUMN_TYPE" expr="gint" replace_with="int"/>
+    </provider>
+
+    <provider name="MySQL">
+      <replace context="/FIELDS_A/@COLUMN_TYPE" expr="string" replace_with="text"/>
+      <replace context="/FIELDS_A/@COLUMN_TYPE" expr="gint" replace_with="int"/>
+      <ignore context="/FKEY_S"/>
+      <ignore context="/FIELDS_A/@COLUMN_PKEY"/>
+    </provider>
+
+    <provider name="SQLite">
+      <replace context="/FIELDS_A/@COLUMN_TYPE" expr="gint" replace_with="int"/>
+    </provider>
+  </specifics>
+
+  <!-- actor table -->
+  <table name="actor"> <!-- possibly also schema attribute -->
+    <column name="actor_id" type="gint" pkey="TRUE" autoinc="TRUE"/>
+    <column name="first_name"/>
+    <column name="last_name"/>
+    <column name="last_update" type="timestamp">
+      <default symbolic="now"/>
+    </column>
+  </table>
+
+  <!-- film table -->
+  <table name="film">
+    <column name="film_id" type="gint" pkey="TRUE" autoinc="TRUE"/>
+    <column name="title"/>
+    <column name="description" type="date"/>
+    <column name="language_id" type="gint"/>
+    <column name="original_language_id" type="gint" nullok="TRUE"/>
+    <column name="rental_duration" type="smallint">
+      <extra context="COLUMN_DEFAULT">3</extra>
+    </column>
+    <column name="rental_rate" type="numeric(4,2)">
+      <extra context="COLUMN_DEFAULT">4.99</extra>
+    </column>
+    <column name="replacement_cost" type="numeric(5,2)">
+      <extra context="COLUMN_DEFAULT">19.99</extra>
+    </column>
+    <column name="rating" nullok="TRUE">
+      <extra context="COLUMN_DEFAULT">G</extra>
+    </column>
+    <column name="special_features" type="[string]"/>
+    <column name="last_update" type="timestamp">
+      <provider name="SQLite">
+	<extra context="COLUMN_DEFAULT">CURRENT_TIMESTAMP</extra>
+      </provider>
+      <provider name="PostgreSQL">
+	<extra context="COLUMN_DEFAULT">now()</extra>
+      </provider>
+    </column>
+
+    <check>((((rating = 'G') OR (rating = 'PG')) OR (rating = 'PG-13')) OR (rating = 'R')) OR (rating = 'NC-17')</check>
+
+    <fkey ref_table="language">
+      <part column="language_id" ref_column="language_id"/>
+    </fkey>
+
+    <fkey ref_table="language">
+      <part column="original_language_id" ref_column="language_id"/>
+    </fkey>
+  </table>
+
+  <!-- film_actor table -->
+  <table name="film_actor">
+    <column name="actor_id" type="gint"/>
+    <column name="film_id" type="gint"/>
+    <column name="last_update" type="timestamp">
+      <default symbolic="now"/>
+    </column>
+
+    <fkey ref_table="actor">
+      <part column="actor_id" ref_column="actor_id"/>
+    </fkey>
+
+    <fkey ref_table="film">
+      <part column="film_id" ref_column="film_id"/>
+    </fkey>
+  </table>
+
+  <!-- language table -->
+  <table name="language">
+    <column name="language_id" type="gint" pkey="TRUE" autoinc="TRUE"/>
+    <column name="name"/>
+    <column name="last_update" type="timestamp">
+      <default symbolic="now"/>
+    </column>
+  </table>
+
+  <!-- dummy table -->
+  <table name="dummy">
+    <column name="name"/>
+    <unique>
+      <column name="name"/>
+    </unique>
+  </table>
+
+  <!-- films_ordered view -->
+  <view name="films_ordered" descr="Ordered list of films">
+    <definition>SELECT * FROM films ORDER BY last_update</definition>
+  </view>
+
+</schema>

Added: trunk/tests/gda-ddl-creator.c
==============================================================================
--- (empty file)
+++ trunk/tests/gda-ddl-creator.c	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,736 @@
+/* gda-ddl-creator.c
+ *
+ * Copyright (C) 2008 Vivien Malerba
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <gda-ddl-creator.h>
+#include <libgda/gda-connection.h>
+#include <libgda/gda-server-provider.h>
+#include <libgda/gda-util.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libgda/gda-connection.h>
+#include <libgda/gda-meta-struct.h>
+#include <libgda/gda-meta-struct-private.h>
+#include <libgda/gda-config.h>
+
+#include <libgda/sql-parser/gda-statement-struct-util.h>
+
+/*
+ * Main static functions
+ */
+static void gda_ddl_creator_class_init (GdaDDLCreatorClass *klass);
+static void gda_ddl_creator_init (GdaDDLCreator *creator);
+static void gda_ddl_creator_dispose (GObject *object);
+static void gda_ddl_creator_finalize (GObject *object);
+
+static void gda_ddl_creator_set_property (GObject *object,
+					 guint param_id,
+					 const GValue *value,
+					 GParamSpec *pspec);
+static void gda_ddl_creator_get_property (GObject *object,
+					 guint param_id,
+					 GValue *value,
+					 GParamSpec *pspec);
+
+static gboolean load_customization (GdaDDLCreator *ddlc, const gchar *xml_spec_file, GError **error);
+static GdaServerOperation *prepare_dbo_server_operation (GdaDDLCreator *ddlc, GdaServerProvider *prov, GdaConnection *cnc, 
+							 GdaMetaDbObject *dbo, GError **error);
+static GStaticRecMutex init_mutex = G_STATIC_REC_MUTEX_INIT;
+
+typedef struct {
+	gchar  *prov;
+	gchar  *path;
+	gchar  *expr;
+} ProviderSpecificKey;
+
+typedef struct {
+	gchar  *repl;
+} ProviderSpecificValue;
+
+static guint ProviderSpecific_hash (gconstpointer key);
+static gboolean ProviderSpecific_equal (gconstpointer a, gconstpointer b);
+static void ProviderSpecific_key_free (ProviderSpecificKey *key);
+static void ProviderSpecific_value_free (ProviderSpecificValue *value);
+
+struct _GdaDDLCreatorPrivate {
+	GdaConnection *cnc;
+	GdaMetaStruct *mstruct;
+
+	GHashTable    *provider_specifics; /* key = a ProviderSpecificKey , value = a ProviderSpecificValue */
+	GValue *catalog;
+	GValue *schema;
+	gchar *quoted_catalog;
+	gchar *quoted_schema;
+};
+
+/* get a pointer to the parents to be able to call their destructor */
+static GObjectClass *parent_class = NULL;
+
+
+/* properties */
+enum {
+	PROP_0,
+	PROP_CNC_OBJECT,
+	PROP_CATALOG,
+	PROP_SCHEMA
+};
+
+/* module error */
+GQuark gda_ddl_creator_error_quark (void) {
+	static GQuark quark;
+	if (!quark)
+		quark = g_quark_from_static_string ("gda_ddl_creator_error");
+	return quark;
+}
+
+GType
+gda_ddl_creator_get_type (void) {
+	static GType type = 0;
+	
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo info = {
+			sizeof (GdaDDLCreatorClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) gda_ddl_creator_class_init,
+			NULL,
+			NULL,
+			sizeof (GdaDDLCreator),
+			0,
+			(GInstanceInitFunc) gda_ddl_creator_init
+		};
+		
+		g_static_rec_mutex_lock (&init_mutex);
+		if (type == 0)
+			type = g_type_register_static (G_TYPE_OBJECT, "GdaDDLCreator", &info, 0);
+		g_static_rec_mutex_unlock (&init_mutex);
+	}
+	return type;
+}
+
+static guint
+ProviderSpecific_hash (gconstpointer key)
+{
+	ProviderSpecificKey *pkey = (ProviderSpecificKey*) key;
+	return g_str_hash (pkey->path) + g_str_hash (pkey->prov) + 
+		(pkey->expr ? g_str_hash (pkey->expr) : 0);
+}
+
+static gboolean
+ProviderSpecific_equal (gconstpointer a, gconstpointer b)
+{
+	ProviderSpecificKey *pa, *pb;
+	pa = (ProviderSpecificKey*) a;
+	pb = (ProviderSpecificKey*) b;
+
+	if (strcmp (pa->prov, pb->prov) ||
+	    (pa->expr && !pb->expr) ||
+	    (pb->expr && !pa->expr) ||
+	    (pa->expr && pb->expr && strcmp (pa->expr, pb->expr)) ||
+	    strcmp (pa->path, pb->path))
+		return FALSE;
+	else
+		return TRUE;
+}
+
+static void
+ProviderSpecific_key_free (ProviderSpecificKey *key)
+{
+	g_free (key->prov);
+	g_free (key->path);
+	g_free (key->expr);
+	g_free (key);
+}
+
+static void
+ProviderSpecific_value_free (ProviderSpecificValue *value)
+{
+	g_free (value->repl);
+	g_free (value);
+}
+
+
+static void
+gda_ddl_creator_class_init (GdaDDLCreatorClass *klass) 
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	g_static_rec_mutex_lock (&init_mutex);
+	parent_class = g_type_class_peek_parent (klass);
+		
+	/* Properties */
+	object_class->set_property = gda_ddl_creator_set_property;
+	object_class->get_property = gda_ddl_creator_get_property;
+	g_object_class_install_property (object_class, PROP_CNC_OBJECT,
+		g_param_spec_object ("cnc", NULL, _ ("Connection object"), GDA_TYPE_CONNECTION,
+		(G_PARAM_READABLE | G_PARAM_WRITABLE)));
+	g_object_class_install_property (object_class, PROP_CATALOG,
+		g_param_spec_string ("catalog", NULL, _ ("Catalog in which the database objects will be created"), NULL,
+		(G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
+	g_object_class_install_property (object_class, PROP_SCHEMA,
+		g_param_spec_string ("schema", NULL, _ ("Schema in which the database objects will be created"), NULL,
+		(G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
+	
+	object_class->dispose = gda_ddl_creator_dispose;
+	object_class->finalize = gda_ddl_creator_finalize;
+	
+	g_static_rec_mutex_unlock (&init_mutex);
+}
+
+
+static void
+gda_ddl_creator_init (GdaDDLCreator *creator) 
+{
+	creator->priv = g_new0 (GdaDDLCreatorPrivate, 1);
+	creator->priv->cnc = NULL;
+	creator->priv->mstruct = (GdaMetaStruct*) g_object_new (GDA_TYPE_META_STRUCT, NULL);
+	creator->priv->provider_specifics = g_hash_table_new_full (ProviderSpecific_hash, ProviderSpecific_equal,
+								   (GDestroyNotify) ProviderSpecific_key_free,
+								   (GDestroyNotify) ProviderSpecific_value_free);
+	creator->priv->catalog = NULL;
+	creator->priv->schema = NULL;
+	creator->priv->quoted_catalog = NULL;
+	creator->priv->quoted_schema = NULL;
+}
+
+
+/**
+ * gda_ddl_creator_new_with_file
+ * @xml_spec_file: a file name
+ * @error: a place to store errors, or %NULL
+ *
+ * Create a new #GdaDDLCreator object using @xml_spec_file as the description
+ * of the database objects
+ *
+ * Returns: the newly created object, or %NULL if an error occurred
+ */
+GdaDDLCreator *
+gda_ddl_creator_new_with_file (const gchar *xml_spec_file, GError **error) 
+{
+	GdaDDLCreator *creator;
+	
+	g_return_val_if_fail (xml_spec_file && *xml_spec_file, NULL);
+	creator = (GdaDDLCreator *) g_object_new (GDA_TYPE_DDL_CREATOR, NULL);
+	
+	if (!gda_meta_struct_load_from_xml_file (creator->priv->mstruct, NULL, NULL, xml_spec_file, error) ||
+	    !load_customization (creator, xml_spec_file, error)) {
+		g_object_unref (creator);
+		creator = NULL;
+	}
+
+	return creator;
+}
+
+static void
+gda_ddl_creator_dispose (GObject *object) 
+{
+	GdaDDLCreator *creator;
+	
+	g_return_if_fail (GDA_IS_DDL_CREATOR (object));
+	
+	creator = GDA_DDL_CREATOR (object);
+	if (creator->priv) {
+		if (creator->priv->catalog)
+			gda_value_free (creator->priv->catalog);
+		if (creator->priv->schema)
+			gda_value_free (creator->priv->schema);
+		g_free (creator->priv->quoted_catalog);
+		g_free (creator->priv->quoted_schema);
+
+		if (creator->priv->cnc) {
+			g_object_unref (creator->priv->cnc);
+			creator->priv->cnc = NULL;
+		}
+
+		if (creator->priv->mstruct) {
+			g_object_unref (creator->priv->mstruct);
+			creator->priv->mstruct = NULL;
+		}
+	}
+	
+	/* parent class */
+	parent_class->dispose (object);
+}
+
+static void
+gda_ddl_creator_finalize (GObject *object)
+{
+	GdaDDLCreator *creator;
+	
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (GDA_IS_DDL_CREATOR (object));
+	
+	creator = GDA_DDL_CREATOR (object);
+	if (creator->priv) {
+		if (creator->priv->provider_specifics)
+			g_hash_table_destroy (creator->priv->provider_specifics);
+		g_free (creator->priv);
+		creator->priv = NULL;
+	}
+	
+	/* parent class */
+	parent_class->finalize (object);
+}
+
+static void
+gda_ddl_creator_set_property (GObject *object,
+			     guint param_id,
+			     const GValue *value,
+			     GParamSpec *pspec) 
+{
+	GdaDDLCreator *creator;
+	
+	creator = GDA_DDL_CREATOR (object);
+	if (creator->priv) {
+		switch (param_id) {
+		case PROP_CNC_OBJECT:
+			if (creator->priv->cnc)
+				g_object_unref (creator->priv->cnc);
+
+			creator->priv->cnc = g_value_get_object (value);
+			if (creator->priv->cnc)
+				g_object_ref (creator->priv->cnc);
+			break;
+		case PROP_CATALOG:
+			if (creator->priv->catalog)
+				gda_value_free (creator->priv->catalog);
+			creator->priv->catalog = NULL;
+			g_free (creator->priv->quoted_catalog);
+			creator->priv->quoted_catalog = NULL;
+			if (g_value_get_string (value) && *g_value_get_string (value)) {
+				creator->priv->catalog = gda_value_copy (value);
+				if (_identifier_needs_quotes (g_value_get_string (value))) 
+					creator->priv->quoted_catalog = _add_quotes (g_value_get_string (value));
+				else
+					creator->priv->quoted_catalog = g_value_dup_string (value);
+			}
+			break;
+		case PROP_SCHEMA:
+			if (creator->priv->schema)
+				gda_value_free (creator->priv->schema);
+			creator->priv->schema = NULL;
+			g_free (creator->priv->quoted_schema);
+			creator->priv->quoted_schema = NULL;
+			if (g_value_get_string (value) && *g_value_get_string (value)) {
+				creator->priv->schema = gda_value_copy (value);
+				if (_identifier_needs_quotes (g_value_get_string (value))) 
+					creator->priv->quoted_schema = _add_quotes (g_value_get_string (value));
+				else
+					creator->priv->quoted_schema = g_value_dup_string (value);
+			}
+			break;
+		}
+	}
+}
+
+static void
+gda_ddl_creator_get_property (GObject *object,
+			     guint param_id,
+			     GValue *value,
+			     GParamSpec *pspec) 
+{
+	GdaDDLCreator *creator;
+	creator = GDA_DDL_CREATOR (object);
+	
+	if (creator->priv) {
+		switch (param_id) {
+		case PROP_CNC_OBJECT:
+			g_value_set_object (value, (GObject *) creator->priv->cnc);
+			break;
+		case PROP_CATALOG:
+			if (creator->priv->catalog)
+				g_value_set_string (value, g_value_get_string (creator->priv->catalog));
+			else
+				g_value_set_string (value, NULL);
+			break;
+		case PROP_SCHEMA:
+			if (creator->priv->schema)
+				g_value_set_string (value, g_value_get_string (creator->priv->schema));
+			else
+				g_value_set_string (value, NULL);
+			break;
+		}
+	}
+}
+
+static gboolean
+load_customization (GdaDDLCreator *ddlc, const gchar *xml_spec_file, GError **error)
+{
+	xmlNodePtr node;
+	xmlDocPtr doc;
+
+	/* load information schema's structure XML file */
+	doc = xmlParseFile (xml_spec_file);
+	if (!doc) {
+		g_set_error (error, GDA_DDL_CREATOR_ERROR, GDA_DDL_CREATOR_SPECFILE_NOT_FOUND_ERROR,
+			     _("Could not load file '%s'"), xml_spec_file);
+		return FALSE;
+	}
+	
+	node = xmlDocGetRootElement (doc);
+	if (!node || strcmp ((gchar *) node->name, "schema")) {
+		g_set_error (error, GDA_DDL_CREATOR_ERROR, GDA_DDL_CREATOR_INCORRECT_SCHEMA_ERROR,
+			     _("Root node of file '%s' should be <schema>."), xml_spec_file);
+		xmlFreeDoc (doc);
+		return FALSE;
+	}
+	
+	/* walk through the xmlDoc */
+	for (node = node->children; node; node = node->next) {
+		/* <specifics> tag to allow for provider specific transformations */
+		if (!strcmp ((gchar *) node->name, "specifics")) {
+			xmlNodePtr snode;
+			for (snode = node->children; snode; snode = snode->next) {
+				if (strcmp ((gchar *) snode->name, "provider"))
+					continue;
+				xmlChar *pname;
+				pname = xmlGetProp (snode, BAD_CAST "name");
+				if (!pname) {
+					g_warning ("<provider> section ignored because no provider name specified");
+					continue; /* ignore this section */
+				}
+
+				xmlNodePtr rnode;
+				gboolean pname_used = FALSE;
+				for (rnode = snode->children; rnode; rnode = rnode->next) {
+					if (!strcmp ((gchar *) rnode->name, "replace") ||
+					    !strcmp ((gchar *) rnode->name, "ignore")) {
+						xmlChar *context;
+						context = xmlGetProp (rnode, BAD_CAST "context");
+						if (!context) {
+							g_warning ("<%s> section ignored because no context specified",
+								   snode->name);
+							continue;
+						}
+						ProviderSpecificKey *key = g_new0 (ProviderSpecificKey, 1);
+						ProviderSpecificValue *val = g_new0 (ProviderSpecificValue, 1);
+						key->prov = (gchar *) pname; 
+						pname_used = TRUE;
+						key->path = (gchar *) context;
+						key->expr = (gchar *) xmlGetProp (rnode, BAD_CAST "expr");
+						val->repl = (gchar *) xmlGetProp (rnode, BAD_CAST "replace_with");
+						g_hash_table_insert (ddlc->priv->provider_specifics, key, val);
+						/*g_print ("RULE: %s, %s, %s => %s\n", key->prov,
+						  key->path, key->expr, val->repl);*/
+					}
+				}
+				if (!pname_used)
+					xmlFree (pname);
+			}
+		}
+	}
+	xmlFreeDoc (doc);
+
+	return TRUE;
+}
+
+static GdaServerOperation *create_server_operation_for_table (GdaDDLCreator *ddlc, GdaServerProvider *prov, GdaConnection *cnc, 
+							      GdaMetaDbObject *dbobj, GError **error);
+static GdaServerOperation *create_server_operation_for_view (GdaDDLCreator *ddlc, GdaServerProvider *prov, GdaConnection *cnc, 
+							     GdaMetaDbObject *dbobj, GError **error);
+
+static GdaServerOperation *
+prepare_dbo_server_operation (GdaDDLCreator *ddlc, GdaServerProvider *prov, GdaConnection *cnc, GdaMetaDbObject *dbo, GError **error)
+{
+	GdaServerOperation *op = NULL;
+	switch (dbo->obj_type) {
+	case GDA_META_DB_UNKNOWN:
+		g_set_error (error, GDA_DDL_CREATOR_ERROR, GDA_DDL_CREATOR_INCORRECT_SCHEMA_ERROR,
+			     _("Unknown database object '%s'"), dbo->obj_full_name);
+		break;
+
+	case GDA_META_DB_TABLE:
+		op = create_server_operation_for_table (ddlc, prov, cnc, dbo, error);
+		break;
+
+	case GDA_META_DB_VIEW:
+		op = create_server_operation_for_view (ddlc, prov, cnc, dbo, error);
+		break;
+	default:
+		TO_IMPLEMENT;
+		break;
+	}
+
+	return op;
+}
+
+static const gchar *
+provider_specific_match (GHashTable *specific_hash, GdaServerProvider *prov, const gchar *expr, const gchar *path)
+{
+	ProviderSpecificKey spec;
+	ProviderSpecificValue *val;
+
+	spec.prov = (gchar *) gda_server_provider_get_name (prov);
+	spec.path = (gchar *) path;
+	spec.expr = (gchar *) expr;
+	val = g_hash_table_lookup (specific_hash, &spec);
+	/*g_print ("RULESEARCH %s, %s, %s => %s\n", spec.prov, spec.path, spec.expr, val ? val->repl : "-no rule found-");*/
+	if (val) 
+		return val->repl;
+	else
+		return expr;
+}
+
+static GdaServerOperation *
+create_server_operation_for_table (GdaDDLCreator *ddlc, GdaServerProvider *prov, GdaConnection *cnc, 
+				   GdaMetaDbObject *dbobj, GError **error)
+{
+	GdaServerOperation *op;
+	GSList *list;
+	gint index;
+	const gchar *repl;
+
+	op = gda_server_provider_create_operation (prov, cnc, GDA_SERVER_OPERATION_CREATE_TABLE, NULL, error);
+	if (!op)
+		return NULL;
+	if (! gda_server_operation_set_value_at (op, dbobj->obj_name, error, "/TABLE_DEF_P/TABLE_NAME"))
+		goto onerror;
+
+	/* columns */
+	for (index = 0, list = GDA_META_TABLE (dbobj)->columns; list; list = list->next, index++) {
+		GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data);
+		if (! gda_server_operation_set_value_at (op, tcol->column_name, error,
+							 "/FIELDS_A/@COLUMN_NAME/%d", index))
+			goto onerror;
+		repl = provider_specific_match (ddlc->priv->provider_specifics, prov, tcol->column_type ? tcol->column_type : "string",
+						"/FIELDS_A/@COLUMN_TYPE");
+		if (! gda_server_operation_set_value_at (op, repl ? repl : "string", error,
+							 "/FIELDS_A/@COLUMN_TYPE/%d", index))
+			goto onerror;
+		if (! gda_server_operation_set_value_at (op, NULL, error,
+							 "/FIELDS_A/@COLUMN_SIZE/%d", index))
+			goto onerror;
+		if (! gda_server_operation_set_value_at (op, tcol->nullok ? "FALSE" : "TRUE", error,
+							 "/FIELDS_A/@COLUMN_NNUL/%d", index))
+			goto onerror;
+		if (! gda_server_operation_set_value_at (op, "FALSE", error,
+							 "/FIELDS_A/@COLUMN_AUTOINC/%d", index))
+			goto onerror;
+		repl = provider_specific_match (ddlc->priv->provider_specifics, prov, "dummy", "/FIELDS_A/@COLUMN_PKEY");
+		if (repl) {
+			if (! gda_server_operation_set_value_at (op, tcol->pkey ? "TRUE" : "FALSE", error,
+								 "/FIELDS_A/@COLUMN_PKEY/%d", index))
+				goto onerror;
+		}
+		else {
+			if (! gda_server_operation_set_value_at (op, "FALSE", error, "/FIELDS_A/@COLUMN_PKEY/%d", index))
+				goto onerror;
+		}
+	}
+
+	/* foreign keys */
+	gint fkindex;
+	for (fkindex = 0, list = GDA_META_TABLE (dbobj)->fk_list; list; fkindex++, list = list->next) {
+		GdaMetaTableForeignKey *mfkey = GDA_META_TABLE_FOREIGN_KEY (list->data);
+		gint col;
+		if (! gda_server_operation_set_value_at (op, mfkey->depend_on->obj_full_name, error, "/FKEY_S/%d/FKEY_REF_TABLE", 
+							 fkindex))
+			goto onerror;
+		for (col = 0; col < mfkey->cols_nb; col++) {
+			if (! gda_server_operation_set_value_at (op, mfkey->fk_names_array[col], error, 
+								 "/FKEY_S/%d/FKEY_FIELDS_A/@FK_FIELD/%d", 
+								 fkindex, col))
+				goto onerror;
+			if (! gda_server_operation_set_value_at (op, mfkey->ref_pk_names_array[col], error, 
+								 "/FKEY_S/%d/FKEY_FIELDS_A/@FK_REF_PK_FIELD/%d", 
+								 fkindex, col))
+				goto onerror;
+		}
+	}
+
+	if (0) {
+		xmlNodePtr node;
+		xmlBufferPtr buffer;
+		node = gda_server_operation_save_data_to_xml (op, NULL);
+		buffer = xmlBufferCreate ();
+		xmlNodeDump (buffer, NULL, node, 5, 1);
+		xmlFreeNode (node);
+		xmlBufferDump (stdout, buffer);
+		xmlBufferFree (buffer);
+	}
+
+	return op;
+ onerror:
+	g_object_unref (op);
+	return NULL;
+}
+
+static GdaServerOperation *
+create_server_operation_for_view (GdaDDLCreator *ddlc, GdaServerProvider *prov, GdaConnection *cnc, 
+				  GdaMetaDbObject *dbobj, GError **error)
+{
+	GdaServerOperation *op;
+
+	op = gda_server_provider_create_operation (prov, cnc, dbobj->obj_type, NULL, error);
+	if (!op)
+		return NULL;
+	if (! gda_server_operation_set_value_at (op, dbobj->obj_name, error, "/VIEW_DEF_P/VIEW_NAME"))
+		goto onerror;
+	if (! gda_server_operation_set_value_at (op, GDA_META_VIEW (dbobj)->view_def, error, "/VIEW_DEF_P/VIEW_DEF"))
+		goto onerror;
+
+	return op;
+ onerror:
+	g_object_unref (op);
+	return NULL;
+}
+
+/**
+ * gda_ddl_creator_set_connection
+ * @ddlc: a #GdaDDLCreator object
+ * @cnc: a #GdaConnection object or %NULL
+ *
+ *
+ */
+void
+gda_ddl_creator_set_connection (GdaDDLCreator *ddlc, GdaConnection *cnc)
+{
+	g_return_if_fail (GDA_IS_DDL_CREATOR (ddlc));
+	g_return_if_fail (!cnc || GDA_IS_CONNECTION (cnc));
+
+	g_object_set (G_OBJECT (ddlc), "cnc", cnc, NULL);
+}
+
+/**
+ * gda_ddl_creator_get_sql_for_create_objects
+ * @ddlc: a #GdaDDLCreator object
+ * @error: a place to store errors, or %NULL
+ *
+ * Get the SQL code which would be executed to create the database objects
+ *
+ * Returns: a new string if no error occurred, or %NULL
+ */
+gchar *
+gda_ddl_creator_get_sql_for_create_objects (GdaDDLCreator *ddlc, GError **error)
+{
+	GString *string;
+	gchar *sql;
+	g_return_val_if_fail (GDA_IS_DDL_CREATOR (ddlc), NULL);
+	g_return_val_if_fail (ddlc->priv, NULL);
+	if (!ddlc->priv->cnc) {
+		g_set_error (error, GDA_DDL_CREATOR_ERROR, GDA_DDL_CREATOR_NO_CONNECTION_ERROR,
+			     _("No connection specified"));
+		return NULL;
+	}
+
+	/* render operations to SQL */
+	GdaServerProvider *prov = gda_connection_get_provider_obj (ddlc->priv->cnc);
+	GSList *objlist, *list;
+	objlist = gda_meta_struct_get_all_db_objects (ddlc->priv->mstruct);
+
+	string = g_string_new ("");
+	for (list = objlist; list; list = list->next) {
+		GdaServerOperation *op;
+		op = prepare_dbo_server_operation (ddlc, prov, NULL, GDA_META_DB_OBJECT (list->data), error);
+		if (!op) {
+			g_string_free (string, TRUE);
+			return NULL;
+		}
+		else {
+			sql = gda_server_provider_render_operation (prov, ddlc->priv->cnc, op, error);
+			if (!sql) {
+				g_string_free (string, TRUE);
+				return NULL;
+			}
+			else {
+				g_string_append_printf (string, "--\n-- Database object: %s\n--\n", 
+							GDA_META_DB_OBJECT (list->data)->obj_full_name);
+				g_string_append (string, sql);
+				g_string_append (string, ";\n\n");
+				g_free (sql);
+			}
+		}
+		g_object_unref (op);
+	}
+
+	sql = string->str;
+	g_string_free (string, FALSE);
+	return sql;
+}
+
+/**
+ * gda_ddl_creator_create_objects
+ * @ddlc: a #GdaDDLCreator object
+ * @error: a place to store errors, or %NULL
+ *
+ * 
+ */
+gboolean
+gda_ddl_creator_create_objects (GdaDDLCreator *ddlc, GError **error)
+{
+	g_return_val_if_fail (GDA_IS_DDL_CREATOR (ddlc), FALSE);
+	g_return_val_if_fail (ddlc->priv, FALSE);
+	if (!ddlc->priv->cnc) {
+		g_set_error (error, GDA_DDL_CREATOR_ERROR, GDA_DDL_CREATOR_NO_CONNECTION_ERROR,
+			     _("No connection specified"));
+		return FALSE;
+	}
+
+	/* begin transaction */
+	if (!gda_connection_begin_transaction (ddlc->priv->cnc, NULL, GDA_TRANSACTION_ISOLATION_UNKNOWN,
+					       error))
+		return FALSE;
+
+	/* execute operations */
+	GdaServerProvider *prov = gda_connection_get_provider_obj (ddlc->priv->cnc);
+	GSList *objlist, *list;
+	objlist = gda_meta_struct_get_all_db_objects (ddlc->priv->mstruct);
+	for (list = objlist; list; list = list->next) {
+		GdaServerOperation *op;
+		op = prepare_dbo_server_operation (ddlc, prov, NULL, GDA_META_DB_OBJECT (list->data), error);
+		if (!op) 
+			goto onerror;
+		else {
+			if (!gda_server_provider_perform_operation (prov, ddlc->priv->cnc, op, error)) {
+				g_object_unref (op);
+				goto onerror;
+			}
+		}
+		g_object_unref (op);
+	}
+
+	if (!gda_connection_commit_transaction (ddlc->priv->cnc, NULL, error))
+		goto onerror;
+
+	return TRUE;
+
+ onerror:
+	gda_connection_rollback_transaction (ddlc->priv->cnc, NULL, NULL);
+	return FALSE;
+}
+
+/**
+ * gda_ddl_creator_delete_objects
+ */
+gboolean
+gda_ddl_creator_delete_objects (GdaDDLCreator *ddlc, GError **error)
+{
+	g_return_val_if_fail (GDA_IS_DDL_CREATOR (ddlc), FALSE);
+	g_return_val_if_fail (ddlc->priv, FALSE);
+	if (!ddlc->priv->cnc) {
+		g_set_error (error, GDA_DDL_CREATOR_ERROR, GDA_DDL_CREATOR_NO_CONNECTION_ERROR,
+			     _("No connection specified"));
+		return FALSE;
+	}
+
+	TO_IMPLEMENT;
+	return FALSE;
+}

Added: trunk/tests/gda-ddl-creator.h
==============================================================================
--- (empty file)
+++ trunk/tests/gda-ddl-creator.h	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,96 @@
+/* gda-ddl-creator.h
+ *
+ * Copyright (C) 2008 Vivien Malerba
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GDA_DDL_CREATOR_H_
+#define __GDA_DDL_CREATOR_H_
+
+#include <glib-object.h>
+#include <libgda/gda-enums.h>
+#include <libgda/gda-data-model.h>
+#include <libgda/gda-decl.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GdaDDLCreator        GdaDDLCreator;
+typedef struct _GdaDDLCreatorClass   GdaDDLCreatorClass;
+typedef struct _GdaDDLCreatorPrivate GdaDDLCreatorPrivate;
+typedef struct _GdaDDLCreatorClassPrivate GdaDDLCreatorClassPrivate;
+
+#define GDA_TYPE_DDL_CREATOR          (gda_ddl_creator_get_type())
+#define GDA_DDL_CREATOR(obj)          G_TYPE_CHECK_INSTANCE_CAST (obj, gda_ddl_creator_get_type(), GdaDDLCreator)
+#define GDA_DDL_CREATOR_CLASS(klass)  G_TYPE_CHECK_CLASS_CAST (klass, gda_ddl_creator_get_type (), GdaDDLCreatorClass)
+#define GDA_IS_DDL_CREATOR(obj)       G_TYPE_CHECK_INSTANCE_TYPE (obj, gda_ddl_creator_get_type ())
+
+/* error reporting */
+extern GQuark gda_ddl_creator_error_quark (void);
+#define GDA_DDL_CREATOR_ERROR gda_ddl_creator_error_quark ()
+
+typedef enum {
+	GDA_DDL_CREATOR_SPECFILE_NOT_FOUND_ERROR,
+	GDA_DDL_CREATOR_INCORRECT_SCHEMA_ERROR,
+	GDA_DDL_CREATOR_NO_CONNECTION_ERROR,
+	GDA_DDL_CREATOR_INTERNAL_ERROR, 
+
+	GDA_DDL_CREATOR_UNSUPPORTED_PROVIDER_ERROR,
+	GDA_DDL_CREATOR_DDL_CONTEXT_ERROR,
+	GDA_DDL_CREATOR_MODIFY_CONTENTS_ERROR,
+	GDA_DDL_CREATOR_EXTRACT_SQL_ERROR,
+	GDA_DDL_CREATOR_ATTRIBUTE_NOT_FOUND_ERROR,
+	GDA_DDL_CREATOR_ATTRIBUTE_ERROR,
+	GDA_DDL_CREATOR_SCHEMA_OBJECT_NOT_FOUND_ERROR,
+	GDA_DDL_CREATOR_SCHEMA_OBJECT_CONFLICT_ERROR,
+	GDA_DDL_CREATOR_SCHEMA_OBJECT_DESCR_ERROR,
+	GDA_DDL_CREATOR_TRANSACTION_ALREADY_STARTED_ERROR
+} GdaDDLCreatorError;
+
+
+/* struct for the object's data */
+struct _GdaDDLCreator
+{
+	GObject               object;
+	GdaDDLCreatorPrivate  *priv;
+};
+
+/* struct for the object's class */
+struct _GdaDDLCreatorClass
+{
+	GObjectClass              parent_class;
+};
+
+GType             gda_ddl_creator_get_type             (void) G_GNUC_CONST;
+GdaDDLCreator    *gda_ddl_creator_new_with_file        (const gchar *xml_spec_file, GError **error);
+
+void              gda_ddl_creator_set_connection       (GdaDDLCreator *ddlc, GdaConnection *cnc);
+gchar            *gda_ddl_creator_get_sql_for_create_objects (GdaDDLCreator *ddlc, GError **error);
+
+/* must use a transaction, fails if it cannot start one */
+gboolean          gda_ddl_creator_create_objects       (GdaDDLCreator *ddlc, GError **error);
+gboolean          gda_ddl_creator_delete_objects       (GdaDDLCreator *ddlc, GError **error);
+
+
+/* ideas:
+GdaDDLCreator    *gda_ddl_creator_new_with_meta_struct (GdaMetaStruct *mstruct);
+
+gboolean          gda_ddl_creator_update_objects       (GdaDDLCreator ddlc, GError **error);
+*/
+
+G_END_DECLS
+
+#endif

Added: trunk/tests/multi-threading/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/tests/multi-threading/Makefile.am	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,26 @@
+AM_CPPFLAGS = \
+	-I$(top_srcdir) \
+	-I$(top_srcdir)/libgda \
+	-I$(top_builddir) \
+	$(LIBGDA_CFLAGS) \
+	-DROOT_DIR=\""$(top_srcdir)"\"
+
+TESTS = check_mutex check_parser check_cnc_lock
+check_PROGRAMS = check_mutex check_parser check_cnc_lock
+
+check_mutex_SOURCES = check_mutex.c
+check_mutex_LDADD = \
+	$(top_builddir)/libgda/libgda-4.0.la \
+	$(LIBGDA_LIBS)
+
+check_parser_SOURCES = check_parser.c
+check_parser_LDADD = \
+	$(top_builddir)/libgda/libgda-4.0.la \
+	$(LIBGDA_LIBS)
+
+check_cnc_lock_SOURCES = check_cnc_lock.c common.c common.h
+check_cnc_lock_LDADD = \
+	$(top_builddir)/libgda/libgda-4.0.la \
+	$(LIBGDA_LIBS)
+
+DISTCLEANFILES = testdb.db

Added: trunk/tests/multi-threading/check_cnc_lock.c
==============================================================================
--- (empty file)
+++ trunk/tests/multi-threading/check_cnc_lock.c	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,211 @@
+#include <libgda/libgda.h>
+#include <string.h>
+#include <unistd.h>
+#include "common.h"
+
+#define NTHREADS 10
+#define DBNAME "testdb"
+#define DBDIR "."
+
+#define DEBUG_PRINT
+#undef DEBUG_PRINT
+
+/* 
+ * tests
+ */
+typedef gboolean (*TestFunc) (GError **);
+static gboolean test1 (GError **error);
+
+TestFunc tests[] = {
+	test1,
+};
+
+int 
+main (int argc, char** argv)
+{
+	gchar *fname;
+	GError *error = NULL;
+
+	g_type_init ();
+	gda_init ();
+
+	/* set up the test database */
+	fname = g_build_filename (ROOT_DIR, "tests", "multi-threading", "testdb.sql", NULL);
+	if (!create_sqlite_db (DBDIR, DBNAME, fname, &error)) {
+		g_print ("Cannot create test database: %s\n", error && error->message ? 
+			 error->message : "no detail");
+		return 1;
+	}
+	g_free (fname);
+
+	gint failures = 0;
+	gint j, ntests = 0;;
+	for (j = 0; j < 500; j++) {
+		gint i;
+		
+#ifdef DEBUG_PRINT
+		g_print ("================================================== test %d\n", j);
+#else
+		g_print (".");
+		fflush (stdout);
+#endif
+		for (i = 0; i < sizeof (tests) / sizeof (TestFunc); i++) {
+			GError *error = NULL;
+			if (! tests[i] (&error)) {
+				g_print ("Test %d failed: %s\n", i+1, 
+					 error && error->message ? error->message : "No detail");
+				if (error)
+					g_error_free (error);
+				failures ++;
+			}
+			ntests ++;
+		}
+	}
+
+	g_print ("\nTESTS COUNT: %d\n", ntests);
+	g_print ("FAILURES: %d\n", failures);
+
+	return failures != 0 ? 1 : 0;
+}
+
+typedef struct _ThData {
+	GMutex        *start_lock;
+	GThread       *thread;
+	GdaConnection *cnc;
+	gint           th_id;
+	gboolean       error;
+} ThData;
+
+static gboolean
+test_multiple_threads (GThreadFunc func, GError **error)
+{
+	ThData data[NTHREADS];
+	gint i;
+	GdaConnection *cnc = NULL;
+
+	/* open cnc */
+	gchar *cnc_string;
+	gchar *edir, *edbname;
+	
+	edir = gda_rfc1738_encode (DBDIR);
+	edbname = gda_rfc1738_encode (DBNAME);
+	cnc_string = g_strdup_printf ("DB_DIR=%s;DB_NAME=%s", edir, edbname);
+	g_free (edir);
+	g_free (edbname);
+	cnc = gda_connection_open_from_string ("SQLite", cnc_string, NULL, 
+					       GDA_CONNECTION_OPTIONS_NONE, NULL);
+	g_free (cnc_string);
+	
+	if (!cnc) 
+		return FALSE;
+	g_object_set (G_OBJECT (cnc), "thread-owner", g_thread_self (), NULL);
+
+	/* prepare threads data */
+	for (i = 0; i < NTHREADS; i++) {
+		ThData *d = &(data[i]);
+		d->start_lock = g_mutex_new ();
+		g_mutex_lock (d->start_lock);
+		d->thread = NULL;
+		d->cnc = cnc;
+		d->th_id = i;
+		d->error = FALSE;
+	}
+
+	/* start all the threads, they will lock on d->start_lock */
+	for (i = 0; i < NTHREADS; i++) {
+		ThData *d = &(data[i]);
+#ifdef DEBUG_PRINT
+		g_print ("Running thread %d\n", d->th_id);
+#endif
+		d->thread = g_thread_create (func, d, TRUE, NULL);
+	}
+
+	/* unlock all the threads */
+	for (i = 0; i < NTHREADS; i++) {
+		ThData *d = &(data[i]);
+		g_mutex_unlock (d->start_lock);
+	}
+
+	gboolean retval = TRUE;
+	for (i = 0; i < NTHREADS; i++) {
+		ThData *d = &(data[i]);
+		g_object_set (G_OBJECT (cnc), "thread-owner", d->thread, NULL);
+		g_thread_join (d->thread);
+		if (d->error)
+			retval = FALSE;
+	}
+
+	for (i = 0; i < NTHREADS; i++) {
+		ThData *d = &(data[i]);
+		g_mutex_free (d->start_lock);
+	}
+	
+	g_object_unref (cnc);
+
+	return retval;
+}
+
+/*
+ * Run SELECT on the same connection
+ */
+gpointer
+test1_start_thread (ThData *data)
+{
+	/* initially start locked */
+	g_mutex_lock (data->start_lock);
+	g_mutex_unlock (data->start_lock);
+
+	/* threads use @cnc */
+	if (gda_lockable_trylock ((GdaLockable*) data->cnc)) {
+#ifdef DEBUG_PRINT
+		g_print ("Th %d has tried to lock cnc and succeeded\n", data->th_id);
+#endif
+	}
+	else {
+#ifdef DEBUG_PRINT
+		g_print ("Th %d has tried to lock cnc and failed, locking it (may block)...\n", data->th_id);
+#endif
+		gda_lockable_lock ((GdaLockable*) data->cnc);
+	}
+	gda_lockable_unlock ((GdaLockable*) data->cnc);
+#ifdef DEBUG_PRINT
+	g_print ("Th %d has unlocked cnc\n", data->th_id);
+#endif
+
+	gda_lockable_lock ((GdaLockable*) data->cnc);
+#ifdef DEBUG_PRINT
+	g_print ("Th %d has locked cnc\n", data->th_id);
+#endif
+		
+	g_thread_yield ();
+	
+	gda_lockable_lock ((GdaLockable*) data->cnc);
+#ifdef DEBUG_PRINT
+	g_print ("Th %d has re-locked cnc\n", data->th_id);
+#endif
+	g_thread_yield ();
+	
+	gda_lockable_unlock ((GdaLockable*) data->cnc);
+#ifdef DEBUG_PRINT
+	g_print ("Th %d has unlocked cnc\n", data->th_id);
+#endif
+	g_thread_yield ();
+	
+	gda_lockable_unlock ((GdaLockable*) data->cnc);
+#ifdef DEBUG_PRINT
+	g_print ("Th %d has re-unlocked cnc\n", data->th_id);
+#endif
+	g_thread_yield ();
+	
+	
+#ifdef DEBUG_PRINT
+	g_print ("Th %d finished\n", data->th_id);
+#endif
+	return NULL;
+}
+
+static gboolean
+test1 (GError **error)
+{
+	return test_multiple_threads ((GThreadFunc) test1_start_thread, error);
+}

Added: trunk/tests/multi-threading/check_mutex.c
==============================================================================
--- (empty file)
+++ trunk/tests/multi-threading/check_mutex.c	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,184 @@
+#include <libgda/libgda.h>
+#include <string.h>
+#include <unistd.h>
+
+#define NTHREADS 3
+#define DEBUG_PRINT
+#undef DEBUG_PRINT
+
+
+/* 
+ * tests
+ */
+typedef gboolean (*TestFunc) (GError **);
+static gboolean test1 (GError **error);
+static gboolean test2 (GError **error);
+static gboolean test3 (GError **error);
+
+TestFunc tests[] = {
+	test1,
+	test2,
+	test3
+};
+
+int 
+main (int argc, char** argv)
+{
+	g_type_init ();
+	gda_init ();
+
+	gint failures = 0;
+	gint j, ntests = 0;;
+	for (j = 0; j < 10; j++) {
+		gint i;
+		
+		for (i = 0; i < sizeof (tests) / sizeof (TestFunc); i++) {
+			GError *error = NULL;
+			if (! tests[i] (&error)) {
+				g_print ("Test %d failed: %s\n", i+1, 
+					 error && error->message ? error->message : "No detail");
+				if (error)
+					g_error_free (error);
+				failures ++;
+			}
+			ntests ++;
+		}
+	}
+
+	g_print ("TESTS COUNT: %d\n", ntests);
+	g_print ("FAILURES: %d\n", failures);
+
+	return failures != 0 ? 1 : 0;
+}
+
+typedef struct {
+	GThread  *thread;
+	gint      th_id;
+	gboolean  finished;
+	GdaMutex *mutex;
+} ThData;
+
+static gboolean
+test_multiple_threads (GThreadFunc func, GError **error)
+{
+	GdaMutex *mutex;
+	ThData data[NTHREADS];
+	gint i;
+
+	mutex = gda_mutex_new ();
+
+	for (i = 0; i < NTHREADS; i++) {
+		ThData *d = &(data[i]);
+		d->th_id = i;
+		d->mutex = mutex;
+		d->finished = FALSE;
+	}
+
+	for (i = 0; i < NTHREADS; i++) {
+		ThData *d = &(data[i]);
+#ifdef DEBUG_PRINT
+		g_print ("Running thread %d\n", d->th_id);
+#endif
+		d->thread = g_thread_create (func, d, TRUE, NULL);
+	}
+
+	/* wait a bit */
+	usleep (100000);
+
+	for (i = 0; i < NTHREADS; i++) {
+		ThData *d = &(data[i]);
+		if (!d->finished) {
+			/* there are some threads locked somethere */
+			exit (EXIT_FAILURE);
+		}
+		else
+			g_thread_join (d->thread);
+	}
+	
+	gda_mutex_free (mutex);
+
+	return TRUE;
+}
+
+/*
+ * Creation and destruction test
+ */
+static gboolean
+test1 (GError **error)
+{
+	GdaMutex *mutex;
+
+	mutex = gda_mutex_new ();
+	gda_mutex_free (mutex);
+
+	return TRUE;
+}
+
+/*
+ * Twice locking
+ */
+gpointer
+test2_start_thread (ThData *data)
+{
+	gda_mutex_lock (data->mutex);
+#ifdef DEBUG_PRINT
+	g_print ("Mutex locked for %d\n", data->th_id);
+#endif
+	g_thread_yield ();
+	gda_mutex_lock (data->mutex);
+#ifdef DEBUG_PRINT
+	g_print ("Mutex re-locked for %d\n", data->th_id);
+#endif
+	gda_mutex_unlock (data->mutex);
+#ifdef DEBUG_PRINT
+	g_print ("Mutex unlocked for %d\n", data->th_id);
+	g_print ("Mutex unlocked for %d\n", data->th_id);
+#endif
+	gda_mutex_unlock (data->mutex);
+	data->finished = TRUE;
+	return NULL;
+}
+
+static gboolean
+test2 (GError **error)
+{
+	return test_multiple_threads ((GThreadFunc) test2_start_thread, error);
+}
+
+/*
+ * Try lock
+ */
+gpointer
+test3_start_thread (ThData *data)
+{
+	gboolean tried = FALSE;
+	while (!tried) {
+		tried = gda_mutex_trylock (data->mutex);
+#ifdef DEBUG_PRINT
+		g_print ("TRY for %d: %s\n", data->th_id, tried ? "got it" : "no luck");
+#endif
+		g_thread_yield ();
+	}
+#ifdef DEBUG_PRINT
+	g_print ("Mutex locked for %d\n", data->th_id);
+#endif
+	g_thread_yield ();
+	gda_mutex_lock (data->mutex);
+#ifdef DEBUG_PRINT
+	g_print ("Mutex re-locked for %d\n", data->th_id);
+#endif
+	gda_mutex_unlock (data->mutex);
+#ifdef DEBUG_PRINT
+	g_print ("Mutex unlocked for %d\n", data->th_id);
+	g_print ("Mutex unlocked for %d\n", data->th_id);
+#endif
+	gda_mutex_unlock (data->mutex);
+	data->finished = TRUE;
+	return NULL;
+}
+
+static gboolean
+test3 (GError **error)
+{
+	return test_multiple_threads ((GThreadFunc) test3_start_thread, error);
+}

Added: trunk/tests/multi-threading/check_parser.c
==============================================================================
--- (empty file)
+++ trunk/tests/multi-threading/check_parser.c	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,345 @@
+#include <stdio.h>
+#include <glib.h>
+#include <glib-object.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <gmodule.h>
+#include <libgda/libgda.h>
+#include <sql-parser/gda-sql-parser.h>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+#define NTHREADS 3
+
+typedef struct {
+	GMutex            *mutex;
+	GPrivate          *thread_priv;
+	xmlDocPtr          doc;
+	xmlNodePtr         node;
+	gboolean           all_done;
+	GHashTable        *parsers_hash;
+	GdaSqlParserMode   current_tested_mode;
+} ThData;
+
+typedef struct {
+	gint ntests;
+	gint nfailures;
+} ThPrivate;
+
+static GdaSqlParser *create_parser_for_provider (const gchar *prov_name);
+static gint do_test (GdaSqlParser *parser, const xmlChar *id, const xmlChar *sql, const xmlChar *expected, 
+		     const xmlChar *error_line, const xmlChar *error_col);
+
+static void set_mode_foreach (gpointer key, gpointer value, gpointer pmode);
+static gpointer start_thread (ThData *data);
+
+
+int 
+main (int argc, char** argv)
+{
+	xmlDocPtr doc;
+	GdaSqlParser *parser;
+	gint failures = 0;
+	gint ntests = 0;
+	gchar *fname;
+	GHashTable *parsers_hash;
+	GdaDataModel *providers_model;
+	gint i;
+
+	gda_init ();
+
+	/* load file */
+	fname = g_build_filename (ROOT_DIR, "tests", "parser", "testdata.xml", NULL);
+	if (! g_file_test (fname, G_FILE_TEST_EXISTS)) {
+                g_print ("File '%s' does not exist\n", fname);
+                exit (1);
+        }
+
+	/* create parsers */
+	parsers_hash = g_hash_table_new (g_str_hash, g_str_equal);
+	providers_model = gda_config_list_providers ();
+	for (i = 0; i < gda_data_model_get_n_rows (providers_model); i++) {
+		const GValue *pname;
+		pname = gda_data_model_get_value_at (providers_model, 0, i);
+		parser = create_parser_for_provider (g_value_get_string (pname));
+		g_hash_table_insert (parsers_hash, g_strdup (g_value_get_string (pname)), parser);
+		g_print ("Created parser for provider %s\n", g_value_get_string (pname));
+	}
+	g_object_unref (providers_model);
+	g_hash_table_insert (parsers_hash, "", gda_sql_parser_new ());
+	
+
+	/* use test data */
+	ThData data;
+	doc = xmlParseFile (fname);
+	g_free (fname);
+	g_assert (doc);
+
+	GdaSqlParserMode pmode;
+	for (pmode = GDA_SQL_PARSER_MODE_PARSE; pmode <= GDA_SQL_PARSER_MODE_DELIMIT; pmode++) {
+		gint j;
+		g_hash_table_foreach (parsers_hash, (GHFunc) set_mode_foreach, GINT_TO_POINTER (pmode));
+		for (j = 0; j < 20; j++) {
+			gint i;
+			GThread *threads[NTHREADS];
+			
+			data.mutex = g_mutex_new ();
+			data.thread_priv = g_private_new (g_free);
+			data.doc = doc;
+			data.node = NULL;
+			data.all_done = FALSE;
+			data.parsers_hash = parsers_hash;
+			data.current_tested_mode = pmode;
+			
+			for (i = 0; i < NTHREADS; i++) {
+				//g_print ("Starting thread %d\n", i);
+				threads [i] = g_thread_create ((GThreadFunc) start_thread, &data, TRUE, NULL);
+			}
+			
+			for (i = 0; i < NTHREADS; i++) {
+				ThPrivate *priv;
+				//g_print ("Joining thread %d... ", i);
+				priv = g_thread_join (threads [i]);
+				ntests += priv->ntests;
+				failures += priv->nfailures;
+				//g_print ("%d tests and %d failures\n", priv->ntests, priv->nfailures);
+				g_free (priv);
+			}
+			
+			g_mutex_free (data.mutex);
+		}
+	}
+	xmlFreeDoc (doc);
+
+	g_print ("TESTS COUNT: %d\n", ntests);
+	g_print ("FAILURES: %d\n", failures);
+  
+	return failures != 0 ? 1 : 0;
+}
+
+static void
+set_mode_foreach (gpointer key, gpointer value, gpointer pmode)
+{
+	g_object_set (G_OBJECT (value), "mode", GPOINTER_TO_INT (pmode), NULL);
+}
+
+static gpointer
+start_thread (ThData *data)
+{
+	while (1) {
+		xmlNodePtr node; /* node to test */
+
+		/* thread's private data */
+		ThPrivate *thpriv = g_private_get (data->thread_priv);
+		if (!thpriv) {
+			thpriv = g_new (ThPrivate, 1);
+			thpriv->ntests = 0;
+			thpriv->nfailures = 0;
+			g_private_set (data->thread_priv, thpriv);
+		}
+
+		/* grep next test to perform, and parser to use */
+		xmlChar *prov_name;
+		GdaSqlParser *parser;
+
+		g_mutex_lock (data->mutex);
+			
+		if (data->all_done) {
+			ThPrivate *copy = g_new (ThPrivate, 1);
+			g_mutex_unlock (data->mutex);
+			*copy = *thpriv;
+			return copy;
+		}
+		if (data->node)
+			data->node = data->node->next;
+		else {
+			xmlNodePtr root = xmlDocGetRootElement (data->doc);
+			g_assert (!strcmp ((gchar*) root->name, "testdata"));
+			data->node = root->children;
+		}
+		if (!data->node) {
+			ThPrivate *copy = g_new (ThPrivate, 1);
+			data->all_done = TRUE;
+			g_mutex_unlock (data->mutex);
+			*copy = *thpriv;
+			return copy;
+		}
+		node = data->node;
+
+		prov_name = xmlGetProp (node, BAD_CAST "provider");
+		if (prov_name) {
+			parser = g_hash_table_lookup (data->parsers_hash, (gchar *) prov_name);
+			xmlFree (prov_name);
+		}
+		else
+			parser = g_hash_table_lookup (data->parsers_hash, "");
+
+		g_mutex_unlock (data->mutex);
+		g_thread_yield ();
+
+		/* test elected node */
+		if (strcmp ((gchar*) node->name, "test"))
+			continue;
+		if (!parser)
+			continue;
+
+		xmlNodePtr snode;
+		xmlChar *sql = NULL;
+		xmlChar *id;
+		
+	
+		id = xmlGetProp (node, BAD_CAST "id");
+		for (snode = node->children; snode; snode = snode->next) {
+			if (!strcmp ((gchar*) snode->name, "sql"))
+				sql = xmlNodeGetContent (snode);
+			else if (!strcmp ((gchar*) snode->name, "expected")) {
+				xmlChar *expected;
+				xmlChar *mode;
+
+				expected = xmlNodeGetContent (snode);
+				mode = xmlGetProp (snode, BAD_CAST "mode");
+				if ((mode && !strcmp (mode, "delim") && 
+				     (data->current_tested_mode == GDA_SQL_PARSER_MODE_DELIMIT)) ||
+				    ((!mode || strcmp (mode, "delim")) &&
+				     (data->current_tested_mode == GDA_SQL_PARSER_MODE_PARSE))) {
+					if (sql) {
+						thpriv->nfailures += do_test (parser, id, sql, expected, NULL, NULL);
+						thpriv->ntests +=1;
+					}
+					else
+						g_print ("===== Test '%s' doe not have any <sql> tag!\n", id);
+				}
+				if (expected) xmlFree (expected);
+				if (mode) xmlFree (mode);
+			}
+			else if (!strcmp ((gchar*) snode->name, "error")) {
+				xmlChar *error_line, *error_col;
+				xmlChar *mode;
+				mode = xmlGetProp (snode, BAD_CAST "mode");
+				error_line = xmlGetProp (snode, BAD_CAST "line");
+				error_col = xmlGetProp (snode, BAD_CAST "col");
+				if ((mode && !strcmp (mode, "delim") && 
+				     (data->current_tested_mode == GDA_SQL_PARSER_MODE_DELIMIT)) ||
+				    ((!mode || strcmp (mode, "delim")) &&
+				     (data->current_tested_mode == GDA_SQL_PARSER_MODE_PARSE))) {
+					if (sql) {
+						thpriv->nfailures += do_test (parser, id, sql, NULL, error_line, error_col);
+						thpriv->ntests += 1;
+					}
+					else
+						g_print ("===== Test '%s' doe not have any <sql> tag!\n", id);
+				}
+				
+				if (mode) xmlFree (mode);
+				if (error_line)	xmlFree (error_line);
+				if (error_col) xmlFree (error_col);
+			}
+		}
+
+		/* mem free */
+		if (sql) xmlFree (sql);
+		if (id)	xmlFree (id);
+	}
+}
+
+/*
+ * Returns: the number of failures. This function is called from several threads at the same time
+ */
+static gint
+do_test (GdaSqlParser *parser, const xmlChar *id, const xmlChar *sql, const xmlChar *expected, 
+	 const xmlChar *error_line, const xmlChar *error_col)
+{
+	gboolean failures = 0;
+#ifdef GDA_DEBUG_NO
+	GdaSqlParserMode mode;
+	g_object_get (G_OBJECT (parser), "mode", &mode, NULL);
+	g_print ("===== TEST %s (%s mode) SQL: @%s \n", id, 
+		 mode == GDA_SQL_PARSER_MODE_PARSE ? "PARSE" : "DELIMIT", sql);
+#endif
+	if (expected) {
+		GdaBatch *batch;
+		GError *error = NULL;
+		
+		batch = gda_sql_parser_parse_string_as_batch (parser, (gchar *) sql, NULL, &error);
+		if (batch) {
+			gchar *ser;
+			ser = gda_batch_serialize (batch);
+			if (strcmp (ser, (gchar *) expected)) {
+				g_print ("ERROR for test '%s':\n   *exp: %s\n   *got: %s\n",
+					 id, expected, ser);
+				failures ++;
+			}
+			g_free (ser);
+			g_object_unref (batch);
+		}
+		else {
+			if (error && (error->domain == GDA_SQL_PARSER_ERROR) &&
+			    (error->code == GDA_SQL_PARSER_EMPTY_SQL_ERROR) && 
+			    (*expected == 0))
+				/* OK */;
+			else {
+				g_print ("ERROR for test '%s':\n   *got error: %s\n", id,
+					 error && error->message ? error->message: "No detail");
+				if (error)
+					g_error_free (error);
+				failures ++;
+			}
+		}
+	}
+	else if (error_line && error_col) {
+		GdaBatch *batch;
+		GError *error = NULL;
+		
+		/* rem: we need to use a mutex here because we actually perform 2 calls to the parser
+		 * and we don't want them interrupted by a thread context change */
+		gda_lockable_lock ((GdaLockable*) parser);
+		batch = gda_sql_parser_parse_string_as_batch (parser, (gchar *) sql, NULL, &error);
+		if (batch) {
+			gchar *ser;
+			ser = gda_batch_serialize (batch);
+			g_print ("ERROR for test '%s':\n   *got: %s\n",
+				 id, ser);
+			g_free (ser);
+			g_object_unref (batch);
+			failures ++;
+		}
+		else {
+			/* FIXME: test error line and col */
+			gint line, col;
+			g_object_get (parser, "line-error", &line, "column-error", &col, NULL);
+			if ((atoi ((gchar*) error_line) != line) || (atoi ((gchar *) error_col) != col)) {
+				g_print ("ERROR for test '%s':\n   *exp line=%s, col=%s\n   *got line=%d, col=%d\n",
+					 id, error_line, error_col, line, col);
+				failures ++;
+			}
+			if (error)
+				g_error_free (error);
+		}
+		gda_lockable_unlock ((GdaLockable*) parser);
+	}
+	else
+		g_print ("Missing or incomplete expected result for test '%s'!\n", id);	
+	
+	return failures;
+}
+
+static GdaSqlParser *
+create_parser_for_provider (const gchar *prov_name)
+{
+	GdaServerProvider *prov;
+	GdaSqlParser *parser;
+	GError *error = NULL;
+
+	prov = gda_config_get_provider_object (prov_name, &error);
+	if (!prov) 
+		g_error ("Could not create provider for '%s': %s\n", prov_name,
+			 error && error->message ? error->message : "No detail");
+
+	parser = gda_server_provider_create_parser (prov, NULL);
+	if (!parser)
+		parser = gda_sql_parser_new ();
+
+	return parser;
+}

Added: trunk/tests/multi-threading/common.c
==============================================================================
--- (empty file)
+++ trunk/tests/multi-threading/common.c	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,112 @@
+#include "common.h"
+#include <string.h>
+#include <sql-parser/gda-sql-parser.h>
+#include <glib/gstdio.h>
+
+/*
+ * Creates an SQLite .db file from the definitions in @sqlfile
+ */
+gboolean
+create_sqlite_db (const gchar *dir, const gchar *dbname, const gchar *sqlfile, GError **error)
+{
+	GdaBatch *batch;
+	GdaSqlParser *parser;
+	GdaServerProvider *prov;
+	GdaConnection *cnc;
+
+	/* create batch */
+	prov = gda_config_get_provider_object ("SQLite", NULL);
+	if (!prov) {
+		g_set_error (error, 0, 0,
+			     "Cannot find the SQLite provider");
+		return FALSE;
+	}
+	parser = gda_server_provider_create_parser (prov, NULL);
+	if (!parser)
+		parser = gda_sql_parser_new ();
+	
+	batch = gda_sql_parser_parse_file_as_batch (parser, sqlfile, error);
+	g_object_unref (parser);
+	if (!batch)
+		return FALSE;
+
+	/* clean any previous DB file */
+	gchar *fname, *tmp;
+	tmp = g_strdup_printf ("%s.db", dbname);
+	fname = g_build_filename (dir, tmp, NULL);
+	g_free (tmp);
+	g_unlink (fname);
+	g_free (fname);
+
+	/* open a connection */
+	gchar *cnc_string;
+	gchar *edir, *edbname;
+
+	edir = gda_rfc1738_encode (dir);
+	edbname = gda_rfc1738_encode (dbname);
+	cnc_string = g_strdup_printf ("DB_DIR=%s;DB_NAME=%s", edir, edbname);
+	g_free (edir);
+	g_free (edbname);
+	cnc = gda_connection_open_from_string ("SQLite", cnc_string, NULL, 
+					       GDA_CONNECTION_OPTIONS_NONE, error);
+	g_free (cnc_string);
+	if (!cnc) {
+		g_object_unref (batch);
+		return FALSE;
+	}
+
+	/* execute batch */
+	GSList *list;
+	const GSList *stmt_list;
+	gboolean retval = TRUE;
+	list = gda_connection_batch_execute (cnc, batch, NULL, GDA_STATEMENT_MODEL_RANDOM_ACCESS, error);
+	stmt_list = gda_batch_get_statements (batch);
+	if (g_slist_length (list) != g_slist_length ((GSList *) stmt_list))
+		retval = FALSE;
+
+	g_slist_foreach (list, (GFunc) g_object_unref, NULL);
+	g_slist_free (list);
+
+	gda_connection_close (cnc);
+	g_object_unref (cnc);
+	g_object_unref (batch);
+	return retval;
+}
+
+void
+run_sql_non_select (GdaConnection *cnc, const gchar *sql)
+{
+        GdaStatement *stmt;
+        GError *error = NULL;
+        gint nrows;
+        GdaSqlParser *parser;
+
+        parser = gda_connection_create_parser (cnc);
+        stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL);
+        g_object_unref (parser);
+
+        nrows = gda_connection_statement_execute_non_select (cnc, stmt, NULL, NULL, &error);
+        g_object_unref (stmt);
+        if (nrows == -1)
+                g_print ("NON SELECT error: %s\n", error && error->message ? error->message : "no detail");
+}
+
+GdaDataModel *
+run_sql_select (GdaConnection *cnc, const gchar *sql)
+{
+        GdaStatement *stmt;
+        GError *error = NULL;
+        GdaDataModel *res;
+        GdaSqlParser *parser;
+
+        parser = gda_connection_create_parser (cnc);
+        stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL);
+        g_object_unref (parser);
+
+        res = gda_connection_statement_execute_select (cnc, stmt, NULL, &error);
+        g_object_unref (stmt);
+        if (!res)
+                g_print ("Could not execute query: %s\n",
+                         error && error->message ? error->message : "no detail");
+        return res;
+}

Added: trunk/tests/multi-threading/common.h
==============================================================================
--- (empty file)
+++ trunk/tests/multi-threading/common.h	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,10 @@
+#include <libgda/libgda.h>
+
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+gboolean create_sqlite_db (const gchar *dir, const gchar *dbname, const gchar *sqlfile, GError **error);
+GdaDataModel *run_sql_select (GdaConnection *cnc, const gchar *sql);
+void run_sql_non_select (GdaConnection *cnc, const gchar *sql);
+
+#endif

Added: trunk/tests/multi-threading/testdb.sql
==============================================================================
--- (empty file)
+++ trunk/tests/multi-threading/testdb.sql	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,6 @@
+CREATE TABLE person (name string, age int);
+
+INSERT INTO person (name, age) VALUES ('Bob', 23);
+INSERT INTO person (name, age) VALUES ('Grat', 24);
+INSERT INTO person (name, age) VALUES ('Bill', 25);
+INSERT INTO person (name, age) VALUES ('Emmett', 26);

Modified: trunk/tests/providers/Makefile.am
==============================================================================
--- trunk/tests/providers/Makefile.am	(original)
+++ trunk/tests/providers/Makefile.am	Thu Jul 17 20:25:20 2008
@@ -84,6 +84,7 @@
 check_sqlite_CFLAGS = 
 check_sqlite_LDADD =  \
 	$(top_builddir)/libgda/libgda-4.0.la \
+	$(top_builddir)/tests/libgda-test-4.0.la \
 	$(LIBGDA_LIBS)
 
 check_bdb_SOURCES = $(common_sources) check_bdb.c

Modified: trunk/tests/providers/TYPES_SCHEMA_SQLite.xml
==============================================================================
--- trunk/tests/providers/TYPES_SCHEMA_SQLite.xml	(original)
+++ trunk/tests/providers/TYPES_SCHEMA_SQLite.xml	Thu Jul 17 20:25:20 2008
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <gda_array id="EXPORT" name="Exported Data">
   <gda_array_field id="FI0" name="short_type_name" title="short_type_name" gdatype="gchararray" size="-1" scale="-1"/>
-  <gda_array_field id="FI1" name="gtype" title="gtype" gdatype="gchararray" size="-1" scale="-1" nullok="TRUE"/>
+  <gda_array_field id="FI1" name="gtype" title="gtype" gdatype="gchararray" size="-1" scale="-1"/>
   <gda_array_field id="FI2" name="comments" title="comments" gdatype="gchararray" size="-1" scale="-1" nullok="TRUE"/>
   <gda_array_field id="FI3" name="synonyms" title="synonyms" gdatype="gchararray" size="-1" scale="-1" nullok="TRUE"/>
   <gda_array_data>

Added: trunk/tests/test-ddl-creator.c
==============================================================================
--- (empty file)
+++ trunk/tests/test-ddl-creator.c	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,72 @@
+/* GDA - Information schema documentation extractor
+ * 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 <gda-ddl-creator.h>
+
+int
+main (int argc, char** argv)
+{
+	GdaDDLCreator *ddl;
+	GError *error = NULL;
+	GdaConnection *cnc;
+	gchar *str;
+
+	gda_init ();
+	
+	ddl = gda_ddl_creator_new_with_file ("dbstruct.xml", &error);
+	if (!ddl) {
+		g_print ("Error creating GdaDDLCreator: %s\n", error && error->message ? error->message : "No detail");
+		g_error_free (error);
+		return EXIT_FAILURE;
+	}
+	
+	/* open a connection */
+	cnc = gda_connection_open_from_string ("SQLite", "DB_DIR=.;DB_NAME=creator", NULL, GDA_CONNECTION_OPTIONS_NONE, &error);
+	if (!cnc) {
+		g_print ("Error opening connection: %s\n", error && error->message ? error->message : "No detail");
+		g_error_free (error);
+		return EXIT_FAILURE;
+	}
+	gda_ddl_creator_set_connection (ddl, cnc);
+	g_object_unref (cnc);
+
+	/* get SQL */
+	str = gda_ddl_creator_get_sql_for_create_objects (ddl, &error);
+	if (!str) {
+		g_print ("Error getting SQL: %s\n", error && error->message ? error->message : "No detail");
+		g_error_free (error);
+		return EXIT_FAILURE;
+	}
+	g_print ("%s\n", str);
+	g_free (str);
+
+	/* execute */
+	if (!gda_ddl_creator_create_objects (ddl, &error)) {
+		g_print ("Error creating database objects: %s\n", error && error->message ? error->message : "No detail");
+		g_error_free (error);
+		return EXIT_FAILURE;
+	}
+
+	g_object_unref (ddl);
+
+	return EXIT_SUCCESS;
+}

Modified: trunk/tools/Makefile.am
==============================================================================
--- trunk/tools/Makefile.am	(original)
+++ trunk/tools/Makefile.am	Thu Jul 17 20:25:20 2008
@@ -39,8 +39,15 @@
 # setenv() is in libiberty in mingw
 if PLATFORM_WIN32
 gda_sql_4_0_LDADD += -liberty
+gda_sql_4_0_SOURCES += gda-sql-res.rc
 endif
 
+.rc.o:
+	$(WINDRES) $^ -o $@
+
+gda-sql-res.o: gda-sql-res.rc
+	$(WINDRES) $^ -o $@
+
 gda_list_server_op_4_0_SOURCES = \
         gda-list-server-op.c
 
@@ -54,4 +61,4 @@
 
 information_schema_doc_LDADD = \
         $(top_builddir)/libgda/libgda-4.0.la \
-        $(LIBGDA_LIBS)
\ No newline at end of file
+        $(LIBGDA_LIBS)

Added: trunk/tools/gda-sql-res.rc
==============================================================================
--- (empty file)
+++ trunk/tools/gda-sql-res.rc	Thu Jul 17 20:25:20 2008
@@ -0,0 +1,2 @@
+AppIcon ICON "gda-sql.ico"
+

Added: trunk/tools/gda-sql.ico
==============================================================================
Binary file. No diff available.



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