libgda r3067 - in branches/V4-branch: . doc/C doc/C/tmpl libgda libgda/providers-support libgda/sql-parser libgda/sqlite providers/postgres providers/skel-implementation/capi tools



Author: vivien
Date: Wed Mar  5 17:44:37 2008
New Revision: 3067
URL: http://svn.gnome.org/viewvc/libgda?rev=3067&view=rev

Log:
2008-03-05  Vivien Malerba <malerba gnome-db org>

	* doc/C: providers writing improvements and generate PDF file, and doc. update
	* libgda/gda-util.c: applied patch to change the default string escape for a
	single-quote char from backslash single-quote (\') to single-quote
	single-quote ('') so that SQLite will accept it (thanks to Phil Longstaff)
	* misc: removed debug info.
	* providers/postgres/parser.y:
	* sql-parser/parser.y: recognize "<>" as the DIFF operator
	* libgda/sqlite/gda-sqlite-provider.c: bind the variables using the SQLITE_TRANSIENT flag
	because the bound data depends on a GdaSet object which may be destroyed (or changed) afterwards
	which leads to uncorrect results
	* providers/skel-implementation/capi/gda-capi-provider.c:
	* providers/postgres/gda-postgres-provider.c:
	* libgda/sqlite/gda-sqlite-provider.c:
	* libgda/gda-connection.c:
	* libgda/gda-connection-private.h: removed gda_connection_internal_sql_executed() and altered
	gda_connection_internal_statement_executed() to add the statement execution parameters for
	future usage
	* providers/postgres/gda-postgres-provider.c:
	* providers/postgres/gda-postgres-meta.[ch]: more methods implemented
	* libgda/information_schema.xml: GdaMetaStore internal schema improvements
	* tools/gda-sql.c:
	* tools/command-exec.[ch]: several improvements (new \dn and \graph commands, improved
	tables' details report)
	* libgda/Makefile.am:
	* libgda/libgda.h.in:
	* libgda/gda-meta-struct.[ch]: new structure to easily handle database objects defined in
	a GdaMetaStore


Added:
   branches/V4-branch/doc/C/tmpl/gda-meta-struct.sgml
   branches/V4-branch/libgda/gda-meta-struct.c
   branches/V4-branch/libgda/gda-meta-struct.h
Modified:
   branches/V4-branch/ChangeLog
   branches/V4-branch/doc/C/Makefile.am
   branches/V4-branch/doc/C/libgda-4.0-docs.sgml
   branches/V4-branch/doc/C/libgda-4.0-sections.txt
   branches/V4-branch/doc/C/prov-writing.xml
   branches/V4-branch/doc/C/tmpl/gda-meta-store.sgml
   branches/V4-branch/doc/C/tmpl/gda-server-provider.sgml
   branches/V4-branch/doc/C/tmpl/gda-set.sgml
   branches/V4-branch/doc/C/tmpl/gda-sql-statement.sgml
   branches/V4-branch/doc/C/tmpl/provider-support.sgml
   branches/V4-branch/libgda/Makefile.am
   branches/V4-branch/libgda/gda-connection-private.h
   branches/V4-branch/libgda/gda-connection.c
   branches/V4-branch/libgda/gda-data-proxy.c
   branches/V4-branch/libgda/gda-meta-store.c
   branches/V4-branch/libgda/gda-server-provider.h
   branches/V4-branch/libgda/gda-util.c
   branches/V4-branch/libgda/information_schema.xml
   branches/V4-branch/libgda/libgda.h.in
   branches/V4-branch/libgda/providers-support/gda-pmodel.c
   branches/V4-branch/libgda/sql-parser/parser.y
   branches/V4-branch/libgda/sqlite/gda-sqlite-meta.c
   branches/V4-branch/libgda/sqlite/gda-sqlite-meta.h
   branches/V4-branch/libgda/sqlite/gda-sqlite-provider.c
   branches/V4-branch/libgda/sqlite/gda-sqlite-recordset.c
   branches/V4-branch/providers/postgres/gda-postgres-meta.c
   branches/V4-branch/providers/postgres/gda-postgres-meta.h
   branches/V4-branch/providers/postgres/gda-postgres-provider.c
   branches/V4-branch/providers/postgres/gda-postgres-recordset.c
   branches/V4-branch/providers/postgres/parser.y
   branches/V4-branch/providers/skel-implementation/capi/gda-capi-provider.c
   branches/V4-branch/tools/command-exec.c
   branches/V4-branch/tools/command-exec.h
   branches/V4-branch/tools/gda-sql.c

Modified: branches/V4-branch/doc/C/Makefile.am
==============================================================================
--- branches/V4-branch/doc/C/Makefile.am	(original)
+++ branches/V4-branch/doc/C/Makefile.am	Wed Mar  5 17:44:37 2008
@@ -61,3 +61,18 @@
 	architecture.svg parts.svg stmt-unknown.svg stmt-select.svg stmt-insert1.svg stmt-insert2.svg \
 	stmt-update.svg stmt-compound.svg information_schema.svg
 
+# Files not to distribute
+# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
+# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
+DISTCLEANFILES = $(DOC_MODULE)-docs.sgml.pdf
+
+DOC_STAMPS += pdf-build.stamp
+CLEANFILES += $(DOC_STAMPS)
+
+# Create the PDF
+PDF: pdf-build.stamp
+pdf-build.stamp:
+	if test -f $(srcdir)/$(DOC_MAIN_SGML_FILE); then \
+		dblatex $(srcdir)/$(DOC_MAIN_SGML_FILE); \
+	fi
+	touch pdf-build.stamp

Modified: branches/V4-branch/doc/C/libgda-4.0-docs.sgml
==============================================================================
--- branches/V4-branch/doc/C/libgda-4.0-docs.sgml	(original)
+++ branches/V4-branch/doc/C/libgda-4.0-docs.sgml	Wed Mar  5 17:44:37 2008
@@ -97,6 +97,7 @@
 <!ENTITY libgda-GdaBatch SYSTEM "xml/gda-batch.xml">
 <!ENTITY libgda-GdaSqlParser SYSTEM "xml/gda-sql-parser.xml">
 <!ENTITY libgda-GdaMetaStore SYSTEM "xml/gda-meta-store.xml">
+<!ENTITY libgda-GdaMetaStruct SYSTEM "xml/gda-meta-struct.xml">
 <!ENTITY libgda-PRow SYSTEM "xml/gda-prow.xml">
 <!ENTITY libgda-PModel SYSTEM "xml/gda-pmodel.xml">
 <!ENTITY libgda-PStmt SYSTEM "xml/gda-pstmt.xml">
@@ -385,9 +386,6 @@
 	libraries.
       </para>
       <mediaobject>
-	<imageobject role="fo">
-          <imagedata fileref="architecture.svg" format="SVG"/>
-	</imageobject>
 	<imageobject role="html">
           <imagedata fileref="architecture.png" format="PNG"/>
 	</imageobject>
@@ -608,18 +606,11 @@
 	need to unref() it after usage, data handler objects are stateless), and so to obtain such a pointer one can:
 	<itemizedlist>
 	  <listitem>
-	    <para>Ask a <link linkend="GdaDict">GdaDict</link> object for one using the 
-	      <link linkend="gda-dict-get-default-handler">gda_dict_get_default_handler()</link>: the returned data handler
+	    <para>Use the <link linkend="gda-get-default-handler">gda_get_default_handler()</link>: the returned data handler
 	      is a generic one and should not be used to convert data to use with any connection, but only to have
 	      a portable way of storing and loading data in a locale independant fashion (for serialization purposes).</para>
 	  </listitem>
 	  <listitem>
-	    <para>Ask a <link linkend="GdaDict">GdaDict</link> object for one using the 
-	      <link linkend="gda-dict-get-handler">gda_dict_get_handler()</link>: the returned data handler can safely be used
-	      to convert data to use with the connection assigned to the dictionary (see this method's documentation
-	      for more information)</para>
-	  </listitem>
-	  <listitem>
 	    <para>Ask a <link linkend="GdaServerProvider">GdaServerProvider</link> object for one using the
 	    <link linkend="gda-server-provider-get-data-handler-gtype">gda_server_provider_get_data_handler_gtype()</link>
 	    or <link linkend="gda-server-provider-get-data-handler-dbms">gda_server_provider_get_data_handler_dbms()</link>:
@@ -638,7 +629,7 @@
     </chapter>
 
     <chapter>
-      <title>Dictionary</title>
+      <title>Dictionary - metadata</title>
       <para>
 	Each connection has a dictionary object (a <link linkend="GdaMetaStore">GdaMetaStore</link>) attached to it. That
 	dictionary is either created by the connection when it needs it, or is set by the user (to be able to re-use
@@ -650,7 +641,13 @@
 	"information schema" schema (as defined in the SQL standard and adapted to add more information). The user
 	is then free to add more tables to contain his own data in the dictionary.
       </para>
+      <para>
+	Extracting information about database objects can easily be done using a 
+	<link linkend="GdaMetaStruct">GdaMetaStruct</link> structure which creates an easy to use in-memory representation
+	of some database objects.
+      </para>
       &libgda-GdaMetaStore;
+      &libgda-GdaMetaStruct;
     </chapter>
 
     <chapter>
@@ -746,6 +743,18 @@
  9 | Greg Popoff |                 2 | SP      | MDR 
 c0> ]]>
       </programlisting>
+      <para>
+	The &gda-sql; tool uses the following environment variables, when set:
+	<itemizedlist>
+	  <listitem><para>GDA_SQL_CNC: may contain an all-in-one connection string to open upon startup</para></listitem>
+	  <listitem><para>GDA_NO_PAGER: if set, then no pager will be used</para></listitem>
+	  <listitem><para>PAGER: if set, indicates which pager program to use (the "more" program is used if not set)</para></listitem>
+	  <listitem><para>GDA_SQL_EDITOR, EDITOR, VISUAL (by precedence order): if set specifies which editor is used (the "notepad.exe" editor is used on Windows
+	      platforms or the "vi" on others if not set)</para></listitem>
+	  <listitem><para>GDA_SQL_VIEWER_PNG: specifies the viewer to use to display graphs (as PNG files)</para></listitem>
+	  <listitem><para>GDA_SQL_VIEWER_PDF: specifies the viewer to use to display graphs (as PDF files)</para></listitem>
+	</itemizedlist>
+      </para>
     </chapter>
 
     <chapter id="libgda-tools-list-config">

Modified: branches/V4-branch/doc/C/libgda-4.0-sections.txt
==============================================================================
--- branches/V4-branch/doc/C/libgda-4.0-sections.txt	(original)
+++ branches/V4-branch/doc/C/libgda-4.0-sections.txt	Wed Mar  5 17:44:37 2008
@@ -1378,6 +1378,26 @@
 </SECTION>
 
 <SECTION>
+<FILE>gda-meta-struct</FILE>
+<TITLE>GdaMetaStruct</TITLE>
+GdaMetaStruct
+GdaMetaStructError
+GDA_META_STRUCT_ERROR
+GdaMetaDbObjectType
+GdaMetaDbObject
+GdaMetaTable
+GdaMetaView
+GdaMetaTableColumn
+GdaMetaTableForeignKey
+gda_meta_struct_new
+gda_meta_struct_complement
+gda_meta_struct_order_db_objects
+gda_meta_struct_get_db_object
+gda_meta_struct_get_table_column
+gda_meta_struct_free
+</SECTION>
+
+<SECTION>
 <FILE>gda-prow</FILE>
 <TITLE>GdaPRow</TITLE>
 <INCLUDE>providers-support/gda-prow.h</INCLUDE>

Modified: branches/V4-branch/doc/C/prov-writing.xml
==============================================================================
--- branches/V4-branch/doc/C/prov-writing.xml	(original)
+++ branches/V4-branch/doc/C/prov-writing.xml	Wed Mar  5 17:44:37 2008
@@ -282,6 +282,117 @@
     </sect2>
   </sect1>
 
+  <sect1 id="prov-metadata">
+    <title>Methods - metadata</title>
+    <para>
+      The <fieldsynopsis>meta_funcs</fieldsynopsis> is composed of several functions which are listed in the
+      <link linkend="GdaServerProviderMeta">GdaServerProviderMeta</link> structure, used internally by
+      the <link linkend="GdaConnection">GdaConnection</link> object when one calls the
+      <link linkend="gda-connection-update-meta-store">gda_connection_update_meta_store()</link> method. 
+      Each method must update the contents of one table in the connection's associated metadata
+      (in its associated <link linkend="GdaMetaStore">GdaMetaStore</link> object), each has the same
+      "base" arguments and some have extra arguments further specifying what needs to be updated. The methods
+      are listed here with a brief explanation for each.
+    </para>
+    <sect2>
+      <title>info()</title>
+      <para>
+	This method must update the contents of the "_information_schema_catalog_name" table, which must contain exactly
+	one row describing the catalog name for the connection.
+      </para>
+    </sect2>
+    <sect2>
+      <title>schemata()</title>
+      <para>
+	This method must update the contents of the "_schemata" table, which lists all the schemas (namespaces).
+	There is one specific <parameter>schema_name</parameter> argument which, if not NULL specifies that only the
+	information regarding that schema must be updated.
+      </para>
+    </sect2>
+    <sect2>
+      <title>btypes()</title>
+      <para>
+	This method must update the contents of the "_builtin_data_types" table which lists all the
+	database's built in data types. There is no specific parameter.
+      </para>
+    </sect2>
+    <sect2>
+      <title>tables_views()</title>
+      <para>
+	This method must update the contents of the "_tables" and "_views" tables which list all the
+	tables and views. There is no specific parameter.
+      </para>
+    </sect2>
+    <sect2>
+      <title>tables_views_s()</title>
+      <para>
+	This method must update the contents of the "_tables" and "_views" tables which list all the
+	tables and views, but only for the schema named by the <parameter>table_schema</parameter> argument (which
+	is never NULL), and (if	not NULL) only for the table or view named by 
+	the <parameter>table_name</parameter> argument.
+      </para>
+    </sect2>
+    <sect2>
+      <title>columns()</title>
+      <para>
+	This method must update the contents of the "_columns" table which lists all the
+	columns of all the tables and views. There is no specific parameter.
+      </para>
+    </sect2>
+    <sect2>
+      <title>columns_t()</title>
+      <para>
+	This method must update the contents of the "_columns" table which lists all the
+	columns of all the tables and views but only for the tables and views which are in the schema named
+	by the <parameter>table_schema</parameter> argument (which
+	is never NULL), and  (if not NULL) only for the table or view named by 
+	the <parameter>table_name</parameter> argument.
+      </para>
+    </sect2>
+    <sect2>
+      <title>columns_c()</title>
+      <para>
+	This method must update the contents of the "_columns" table which lists all the
+	columns of all the tables and views but only for the tables and views which are in the schema named
+	by the <parameter>table_schema</parameter> argument (which
+	is never NULL), (if not NULL) only for the table or view named by 
+	the <parameter>table_name</parameter> argument, and for the column named by 
+	the <parameter>column_name</parameter> argument.
+      </para>
+    </sect2>
+    <sect2>
+      <title>constraints_tab()</title>
+      <para>
+	This method must update the contents of the "_table_constraints" table which lists all the
+	constraints for each table. There is no specific parameter.
+      </para>
+    </sect2>
+    <sect2>
+      <title>constraints_tab_s()</title>
+      <para>
+	This method must update the contents of the "_table_constraints" table which lists all the
+	constraints for the table which is in the schema named by the <parameter>table_schema</parameter> argument (which
+	is never NULL), and which is named by the <parameter>table_name</parameter> argument (which is also never NULL).
+      </para>
+    </sect2>
+<sect2>
+      <title>constraints_ref()</title>
+      <para>
+	This method must update the contents of the "_referential_constraints" table which lists all the
+	refetential constraints (which are also listed in the "_table_constraints" table). There is no specific parameter.
+      </para>
+    </sect2>
+    <sect2>
+      <title>constraints_ref_s()</title>
+      <para>
+	This method must update the contents of the "_referential_constraints" table which lists all the
+	refetential constraints (which are also listed in the "_table_constraints" table) for the constraint which is 
+	in the schema named by the <parameter>constraint_schema</parameter> argument (which
+	is never NULL), and which is named by the <parameter>constraint_name</parameter> argument (which is also never NULL).
+      </para>
+    </sect2>
+  </sect1>
+
   <sect1>
     <title>Methods - misc.</title>
     <sect2>
@@ -297,11 +408,9 @@
       </para>
     </sect2>
     <sect2>
-      <title>meta_funcs</title>
+      <title>is_busy()</title>
       <para>
-	The <fieldsynopsis>meta_funcs</fieldsynopsis> is composed of several functions which are listed in the
-	<link linkend="GdaServerProviderMeta">GdaServerProviderMeta</link> structure.
-	Related to <link linkend="GdaMetaStore">GdaMetaStore</link>.
+	This method tests if a connection is already busy in a, asynchronous task.
       </para>
     </sect2>
   </sect1>

Modified: branches/V4-branch/doc/C/tmpl/gda-meta-store.sgml
==============================================================================
--- branches/V4-branch/doc/C/tmpl/gda-meta-store.sgml	(original)
+++ branches/V4-branch/doc/C/tmpl/gda-meta-store.sgml	Wed Mar  5 17:44:37 2008
@@ -22,9 +22,6 @@
   but a user can also add its own tables or other database objects. The following diagram shows the tables and
   views initially defined by &LIBGDA; for its internal needs:
   <mediaobject>
-    <imageobject role="fo">
-      <imagedata fileref="information_schema.svg" format="SVG"/>
-    </imageobject>
     <imageobject role="html">
       <imagedata fileref="information_schema.png" format="PNG"/>
     </imageobject>

Added: branches/V4-branch/doc/C/tmpl/gda-meta-struct.sgml
==============================================================================
--- (empty file)
+++ branches/V4-branch/doc/C/tmpl/gda-meta-struct.sgml	Wed Mar  5 17:44:37 2008
@@ -0,0 +1,192 @@
+<!-- ##### SECTION Title ##### -->
+GdaMetaStruct
+
+<!-- ##### SECTION Short_Description ##### -->
+In memory representation of some database objects
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+  The #GdaMetaStruct structure reads data from a #GdaMetaStore object and
+  creates an easy to use in memory representation for some database objects. For example one can easily
+  analyse the columns of a table (or its foreign keys) using a #GdaMetaStruct.
+</para>
+<para>
+  It is not permitted to modify a #GdaMetaStruct structure, one should only use the public API
+  to add information about database objects (using gda_meta_struct_complement()).
+</para>
+<para>
+  In the following code sample, one prints the columns names and types of a table:
+  <programlisting>
+GdaMetaStruct *mstruct;
+GdaMetaDbObject *dbo;
+GValue *catalog, *schema, *name;
+
+/* Define catalog, schema and name */
+[...]
+
+mstruct = gda_meta_struct_new ();
+gda_meta_struct_complement (mstruct, store, GDA_META_DB_TABLE, catalog, schema, name, NULL);
+dbo = gda_meta_struct_get_db_object (mstruct, catalog, schema, name);
+if (!dbo)
+        g_print ("Table not found\n");
+else {
+        GSList *list;
+        for (list = GDA_META_DB_OBJECT_GET_TABLE (dbo)->columns; list; list = list->next) {
+                GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data);
+                g_print ("COLUMN: %s (%s)\n", tcol->column_name, tcol->column_type);
+        }
+}
+gda_meta_struct_free (mstruct);
+  </programlisting>
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### STRUCT GdaMetaStruct ##### -->
+<para>
+
+</para>
+
+ db_objects: 
+ index: 
+
+<!-- ##### ENUM GdaMetaStructError ##### -->
+<para>
+
+</para>
+
+ GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR: 
+ GDA_META_STRUCT_DUPLICATE_OBJECT_ERROR: 
+ GDA_META_STRUCT_INCOHERENCE_ERROR: 
+
+<!-- ##### MACRO GDA_META_STRUCT_ERROR ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### ENUM GdaMetaDbObjectType ##### -->
+<para>
+
+</para>
+
+ GDA_META_DB_UNKNOWN: 
+ GDA_META_DB_TABLE: 
+ GDA_META_DB_VIEW: 
+
+<!-- ##### STRUCT GdaMetaTable ##### -->
+<para>
+
+</para>
+
+ columns: 
+ pk_cols_array: 
+ pk_cols_nb: 
+ reverse_fk_list: 
+ fk_list: 
+
+<!-- ##### STRUCT GdaMetaView ##### -->
+<para>
+
+</para>
+
+ table: 
+ view_def: 
+ is_updatable: 
+
+<!-- ##### STRUCT GdaMetaTableColumn ##### -->
+<para>
+
+</para>
+
+ column_name: 
+ column_type: 
+ gtype: 
+ pkey: 
+ nullok: 
+ default_value: 
+
+<!-- ##### STRUCT GdaMetaTableForeignKey ##### -->
+<para>
+
+</para>
+
+ meta_table: 
+ depend_on: 
+ cols_nb: 
+ fk_cols_array: 
+ fk_names_array: 
+ ref_pk_cols_array: 
+ ref_pk_names_array: 
+
+<!-- ##### FUNCTION gda_meta_struct_new ##### -->
+<para>
+
+</para>
+
+ Returns: 
+
+
+<!-- ##### FUNCTION gda_meta_struct_complement ##### -->
+<para>
+
+</para>
+
+ mstruct: 
+ store: 
+ type: 
+ catalog: 
+ schema: 
+ name: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION gda_meta_struct_order_db_objects ##### -->
+<para>
+
+</para>
+
+ mstruct: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION gda_meta_struct_get_db_object ##### -->
+<para>
+
+</para>
+
+ mstruct: 
+ catalog: 
+ schema: 
+ name: 
+ Returns: 
+
+
+<!-- ##### FUNCTION gda_meta_struct_get_table_column ##### -->
+<para>
+
+</para>
+
+ mstruct: 
+ table: 
+ col_name: 
+ Returns: 
+
+
+<!-- ##### FUNCTION gda_meta_struct_free ##### -->
+<para>
+
+</para>
+
+ mstruct: 
+
+

Modified: branches/V4-branch/doc/C/tmpl/gda-server-provider.sgml
==============================================================================
--- branches/V4-branch/doc/C/tmpl/gda-server-provider.sgml	(original)
+++ branches/V4-branch/doc/C/tmpl/gda-server-provider.sgml	Wed Mar  5 17:44:37 2008
@@ -86,7 +86,9 @@
 
 <!-- ##### STRUCT GdaServerProviderMeta ##### -->
 <para>
-
+These methods must be implemented by providers to update a connection's associated metadata (in a 
+#GdaMetaStore object), see the <link linkend="prov-metadata">Virtual methods for providers/Methods - metadata</link>
+for more information.
 </para>
 
 @info: 
@@ -97,6 +99,10 @@
 @columns: 
 @columns_t: 
 @columns_c: 
+ constraints_tab: 
+ constraints_tab_s: 
+ constraints_ref: 
+ constraints_ref_c: 
 
 <!-- ##### USER_FUNCTION GdaServerProviderAsyncCallback ##### -->
 <para>

Modified: branches/V4-branch/doc/C/tmpl/gda-set.sgml
==============================================================================
--- branches/V4-branch/doc/C/tmpl/gda-set.sgml	(original)
+++ branches/V4-branch/doc/C/tmpl/gda-set.sgml	Wed Mar  5 17:44:37 2008
@@ -122,6 +122,15 @@
 @Returns: 
 
 
+<!-- ##### FUNCTION gda_set_copy ##### -->
+<para>
+
+</para>
+
+ set: 
+ Returns: 
+
+
 <!-- ##### FUNCTION gda_set_new_inline ##### -->
 <para>
 

Modified: branches/V4-branch/doc/C/tmpl/gda-sql-statement.sgml
==============================================================================
--- branches/V4-branch/doc/C/tmpl/gda-sql-statement.sgml	(original)
+++ branches/V4-branch/doc/C/tmpl/gda-sql-statement.sgml	Wed Mar  5 17:44:37 2008
@@ -10,9 +10,6 @@
 which can be manipulated directly. The structure is a tree composed of several key structures which are show in the following diagram
 (even though it does not show, all structures "inherit" the #GdaSqlAnyPart structure which holds some basic information).
 <mediaobject>
-  <imageobject role="fo">
-    <imagedata fileref="parts.svg" format="SVG"/>
-  </imageobject>
   <imageobject role="html">
     <imagedata fileref="parts.png" format="PNG"/>
   </imageobject>
@@ -223,9 +220,6 @@
   when it cannot parse the SQL string, or when operating in delimiter mode (it only tries to delimit statements if there are several
   ones in the same SQL string).
 <mediaobject>
-  <imageobject role="fo">
-    <imagedata fileref="stmt-unknown.svg" format="SVG"/>
-  </imageobject>
   <imageobject role="html">
     <imagedata fileref="stmt-unknown.png" format="PNG"/>
   </imageobject>
@@ -298,9 +292,6 @@
   (if this is not the case
   then report a bug).
   <mediaobject>
-    <imageobject role="fo">
-      <imagedata fileref="stmt-select.svg" format="SVG"/>
-    </imageobject>
     <imageobject role="html">
       <imagedata fileref="stmt-select.png" format="PNG"/>
     </imageobject>
@@ -404,9 +395,6 @@
   (if this is not the case
   then report a bug).
   <mediaobject>
-    <imageobject role="fo">
-      <imagedata fileref="stmt-insert1.svg" format="SVG"/>
-    </imageobject>
     <imageobject role="html">
       <imagedata fileref="stmt-insert1.png" format="PNG"/>
     </imageobject>
@@ -418,9 +406,6 @@
     </caption>
   </mediaobject>
   <mediaobject>
-    <imageobject role="fo">
-      <imagedata fileref="stmt-insert2.svg" format="SVG"/>
-    </imageobject>
     <imageobject role="html">
       <imagedata fileref="stmt-insert2.png" format="PNG"/>
     </imageobject>
@@ -529,9 +514,6 @@
   (if this is not the case
   then report a bug).
   <mediaobject>
-    <imageobject role="fo">
-      <imagedata fileref="stmt-update.svg" format="SVG"/>
-    </imageobject>
     <imageobject role="html">
       <imagedata fileref="stmt-update.png" format="PNG"/>
     </imageobject>
@@ -594,9 +576,6 @@
   (if this is not the case
   then report a bug).
   <mediaobject>
-    <imageobject role="fo">
-      <imagedata fileref="stmt-compound.svg" format="SVG"/>
-    </imageobject>
     <imageobject role="html">
       <imagedata fileref="stmt-compound.png" format="PNG"/>
     </imageobject>
@@ -984,6 +963,7 @@
 @GDA_SQL_OPERATOR_ISNOTNULL: 
 @GDA_SQL_OPERATOR_NOT: 
 @GDA_SQL_OPERATOR_IN: 
+ GDA_SQL_OPERATOR_NOTIN: 
 @GDA_SQL_OPERATOR_CONCAT: 
 @GDA_SQL_OPERATOR_PLUS: 
 @GDA_SQL_OPERATOR_MINUS: 

Modified: branches/V4-branch/doc/C/tmpl/provider-support.sgml
==============================================================================
--- branches/V4-branch/doc/C/tmpl/provider-support.sgml	(original)
+++ branches/V4-branch/doc/C/tmpl/provider-support.sgml	Wed Mar  5 17:44:37 2008
@@ -199,6 +199,7 @@
 
 @cnc: 
 @stmt: 
+ params: 
 @error: 
 
 

Modified: branches/V4-branch/libgda/Makefile.am
==============================================================================
--- branches/V4-branch/libgda/Makefile.am	(original)
+++ branches/V4-branch/libgda/Makefile.am	Wed Mar  5 17:44:37 2008
@@ -56,6 +56,7 @@
 	gda-log.h \
 	gda-marshal.h \
 	gda-meta-store.h \
+	gda-meta-struct.h \
 	gda-quark-list.h \
 	gda-set.h \
 	gda-row.h \
@@ -105,6 +106,7 @@
 	gda-log.c \
 	gda-marshal.c \
 	gda-meta-store.c \
+	gda-meta-struct.c \
 	gda-quark-list.c \
 	gda-set.c \
 	gda-row.c \

Modified: branches/V4-branch/libgda/gda-connection-private.h
==============================================================================
--- branches/V4-branch/libgda/gda-connection-private.h	(original)
+++ branches/V4-branch/libgda/gda-connection-private.h	Wed Mar  5 17:44:37 2008
@@ -41,8 +41,7 @@
 void gda_connection_internal_transaction_rolledback (GdaConnection *cnc, const gchar *trans_name);
 void gda_connection_internal_transaction_committed (GdaConnection *cnc, const gchar *trans_name);
 
-void gda_connection_internal_sql_executed (GdaConnection *cnc, const gchar *sql, GdaConnectionEvent *error); /* REMOVE */
-void gda_connection_internal_statement_executed (GdaConnection *cnc, GdaStatement *stmt, GdaConnectionEvent *error);
+void gda_connection_internal_statement_executed (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params, GdaConnectionEvent *error);
 
 void gda_connection_internal_savepoint_added (GdaConnection *cnc, const gchar *parent_trans, const gchar *svp_name);
 void gda_connection_internal_savepoint_rolledback (GdaConnection *cnc, const gchar *svp_name);

Modified: branches/V4-branch/libgda/gda-connection.c
==============================================================================
--- branches/V4-branch/libgda/gda-connection.c	(original)
+++ branches/V4-branch/libgda/gda-connection.c	Wed Mar  5 17:44:37 2008
@@ -1489,12 +1489,12 @@
 /**
  * gda_connection_begin_transaction
  * @cnc: a #GdaConnection object.
- * @name: the name of the transation to start
+ * @name: the name of the transation to start, or %NULL
  * @level:
  * @error: a place to store errors, or %NULL
  *
  * Starts a transaction on the data source, identified by the
- * @xaction parameter.
+ * @name parameter.
  *
  * Before starting a transaction, you can check whether the underlying
  * provider does support transactions or not by using the
@@ -1520,7 +1520,7 @@
 /**
  * gda_connection_commit_transaction
  * @cnc: a #GdaConnection object.
- * @name: the name of the transation to commit
+ * @name: the name of the transation to commit, or %NULL
  * @error: a place to store errors, or %NULL
  *
  * Commits the given transaction to the backend database. You need to call
@@ -1545,7 +1545,7 @@
 /**
  * gda_connection_rollback_transaction
  * @cnc: a #GdaConnection object.
- * @name: the name of the transation to commit
+ * @name: the name of the transation to commit, or %NULL
  * @error: a place to store errors, or %NULL
  *
  * Rollbacks the given transaction. This means that all changes
@@ -1744,7 +1744,7 @@
 		g_set_error (error, 0, 0,
 			     _("Missing and/or wrong arguments"));
 
-	g_print ("Check context => %d\n", retval);
+	/*g_print ("Check arguments context => found %d\n", retval);*/
 	return retval;
 }
 
@@ -1752,9 +1752,11 @@
 local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaContext *context, GError **error)
 {
 #ifdef GDA_DEBUG
-#define ASSERT_TABLE_NAME(x,y) g_assert (!strcmp ((x), (y)));
+#define ASSERT_TABLE_NAME(x,y) g_assert (!strcmp ((x), (y)))
+#define WARN_METHOD_NOT_IMPLEMENTED(prov,method) g_warning ("Provider '%s' does not implement the META method '%s()', please report the error to bugzilla.gnome.org", gda_server_provider_get_name (prov), (method))
 #else
 #define ASSERT_TABLE_NAME(x,y)
+#define WARN_METHOD_NOT_IMPLEMENTED(prov,method)
 #endif
 	const gchar *tname = context->table_name;
 	GdaMetaStore *store;
@@ -1765,14 +1767,109 @@
 	
 	store = gda_connection_get_meta_store (cnc);
 	switch (*tname) {
+	case 'b': {
+		/* _builtin_data_types, params: 
+		 *  - none
+		 */
+		ASSERT_TABLE_NAME (tname, "builtin_data_types");
+		if (!PROV_CLASS (provider)->meta_funcs.btypes) {
+			WARN_METHOD_NOT_IMPLEMENTED (provider, "btypes");
+			break;
+		}
+		return PROV_CLASS (provider)->meta_funcs.btypes (provider, cnc, store, context, error);
+	}
 	case 'i':
 		/* _information_schema_catalog_name, params: 
 		 *  - none
 		 */
-		ASSERT_TABLE_NAME (tname, "information_schema_catalog_name")
-		if (!PROV_CLASS (provider)->meta_funcs.info)
+		ASSERT_TABLE_NAME (tname, "information_schema_catalog_name");
+		if (!PROV_CLASS (provider)->meta_funcs.info) {
+			WARN_METHOD_NOT_IMPLEMENTED (provider, "info");
 			break;
+		}
 		return PROV_CLASS (provider)->meta_funcs.info (provider, cnc, store, context, error);
+	case 'c': 
+		if ((tname[1] == 'o') && (tname[2] == 'l') && (tname[3] == 'u')) {
+			/* _columns,  params: 
+			 *  - none
+			 *  - @table_schema AND @table_name
+			 *  - @table_schema AND @table_name AND @column_name
+			 */
+			const GValue *p_table_schema = NULL;
+			const GValue *p_table_name = NULL;
+			const GValue *p_column_name = NULL;
+			
+			if (check_parameters (context, error, 3,
+					      &p_table_schema, G_TYPE_STRING,
+					      &p_table_name, G_TYPE_STRING,
+					      &p_column_name, G_TYPE_STRING, NULL,
+					      "table_schema", &p_table_schema, "table_name", &p_table_name, "column_name", &p_column_name, NULL,
+					      "table_schema", &p_table_schema, "table_name", &p_table_name, NULL,
+					      NULL) < 0)
+				return FALSE;
+			
+			ASSERT_TABLE_NAME (tname, "columns");
+			if (p_table_schema) {
+				if (p_column_name) {
+					if (!PROV_CLASS (provider)->meta_funcs.columns_c) {
+						WARN_METHOD_NOT_IMPLEMENTED (provider, "columns_c");
+						break;
+					}
+					return PROV_CLASS (provider)->meta_funcs.columns_c (provider, cnc, store, context, error, 
+											    p_table_schema, p_table_name, p_column_name);
+				}
+				else {
+					if (!PROV_CLASS (provider)->meta_funcs.columns_t) {
+						WARN_METHOD_NOT_IMPLEMENTED (provider, "columns_t");
+						break;
+					}
+					return PROV_CLASS (provider)->meta_funcs.columns_t (provider, cnc, store, context, error, 
+											    p_table_schema, p_table_name);
+				}
+			}
+			else {
+				if (!PROV_CLASS (provider)->meta_funcs.columns) {
+					WARN_METHOD_NOT_IMPLEMENTED (provider, "columns");
+					break;
+				}
+				return PROV_CLASS (provider)->meta_funcs.columns (provider, cnc, store, context, error);
+			}
+		}
+		break;
+
+	case 'r': 
+		if ((tname[1] == 'e') && (tname[2] == 'f')) {
+			/* _referential_constraints, params: 
+			 *  - none
+			 *  - @constraint_schema AND @constraint_name
+			 */
+			const GValue *p_constraint_schema = NULL;
+			const GValue *p_constraint_name = NULL;
+			if (check_parameters (context, error, 3,
+					      &p_constraint_schema, G_TYPE_STRING,
+					      &p_constraint_name, G_TYPE_STRING, NULL,
+					      "constraint_schema", &p_constraint_schema, "constraint_name", &p_constraint_name, NULL,
+					      NULL) < 0)
+				return FALSE;
+			
+			ASSERT_TABLE_NAME (tname, "referential_constraints");
+			if (p_constraint_schema) {
+				if (!PROV_CLASS (provider)->meta_funcs.constraints_ref_c) {
+					WARN_METHOD_NOT_IMPLEMENTED (provider, "constraints_ref_c");
+					break;
+				}
+				return PROV_CLASS (provider)->meta_funcs.constraints_ref_c (provider, cnc, store, context, error, 
+											    p_constraint_schema, p_constraint_name);
+			}
+			else {
+				if (!PROV_CLASS (provider)->meta_funcs.constraints_ref) {
+					WARN_METHOD_NOT_IMPLEMENTED (provider, "constraints_ref");
+					break;
+				}
+				return PROV_CLASS (provider)->meta_funcs.constraints_ref (provider, cnc, store, context, error);
+			}
+		}
+		break;
 
 	case 's': {
 		/* _schemata, params: 
@@ -1785,9 +1882,11 @@
 				      "schema_name", &p_schema_name, NULL,
 				      NULL) < 0)
 			return FALSE;
-		ASSERT_TABLE_NAME (tname, "schemata")
-		if (!PROV_CLASS (provider)->meta_funcs.schemata)
+		ASSERT_TABLE_NAME (tname, "schemata");
+		if (!PROV_CLASS (provider)->meta_funcs.schemata) {
+			WARN_METHOD_NOT_IMPLEMENTED (provider, "schemata");
 			break;
+		}
 		return PROV_CLASS (provider)->meta_funcs.schemata (provider, cnc, store, context, error, p_schema_name);
 	}
 	case 't': 
@@ -1807,73 +1906,56 @@
 					      NULL) < 0)
 				return FALSE;
 			
-			ASSERT_TABLE_NAME (tname, "tables")
-				if (p_table_schema) {
-					if (!PROV_CLASS (provider)->meta_funcs.tables_views_s)
-						break;
-					return PROV_CLASS (provider)->meta_funcs.tables_views_s (provider, cnc, store, context, error, 
-												 p_table_schema, p_table_name);
+			ASSERT_TABLE_NAME (tname, "tables");
+			if (p_table_schema) {
+				if (!PROV_CLASS (provider)->meta_funcs.tables_views_s) {
+					WARN_METHOD_NOT_IMPLEMENTED (provider, "tables_views_s");
+					break;
 				}
-				else {
-					if (!PROV_CLASS (provider)->meta_funcs.tables_views)
-						break;
-					return PROV_CLASS (provider)->meta_funcs.tables_views (provider, cnc, store, context, error);
+				return PROV_CLASS (provider)->meta_funcs.tables_views_s (provider, cnc, store, context, error, 
+											 p_table_schema, p_table_name);
+			}
+			else {
+				if (!PROV_CLASS (provider)->meta_funcs.tables_views) {
+					WARN_METHOD_NOT_IMPLEMENTED (provider, "tables_views");
+					break;
 				}
+				return PROV_CLASS (provider)->meta_funcs.tables_views (provider, cnc, store, context, error);
+			}
 		}
-		break;
-
-	case 'c': 
-		if ((tname[1] == 'o') && (tname[2] == 'l') && (tname[2] == 'u')) {
-			/* _columns,  params: 
+		else if ((tname[1] == 'a') && (tname[2] == 'b') && (tname[3] == 'l') && (tname[4] == 'e') && 
+			 (tname[5] == '_') && (tname[6] == 'c')) {
+			/* _tables_constraints, params: 
 			 *  - none
 			 *  - @table_schema AND @table_name
-			 *  - @table_schema AND @table_name AND @column_name
 			 */
 			const GValue *p_table_schema = NULL;
 			const GValue *p_table_name = NULL;
-			const GValue *p_column_name = NULL;
-			
 			if (check_parameters (context, error, 3,
 					      &p_table_schema, G_TYPE_STRING,
-					      &p_table_name, G_TYPE_STRING,
-					      &p_column_name, G_TYPE_STRING, NULL,
-					      "table_schema", &p_table_schema, "table_name", &p_table_name, "column_name", &p_column_name, NULL,
+					      &p_table_name, G_TYPE_STRING, NULL,
 					      "table_schema", &p_table_schema, "table_name", &p_table_name, NULL,
 					      NULL) < 0)
 				return FALSE;
 			
-			ASSERT_TABLE_NAME (tname, "columns")
+			ASSERT_TABLE_NAME (tname, "table_constraints");
 			if (p_table_schema) {
-				if (p_column_name) {
-					if (!PROV_CLASS (provider)->meta_funcs.columns_c)
-						return FALSE;
-					return PROV_CLASS (provider)->meta_funcs.columns_c (provider, cnc, store, context, error, 
-											    p_table_schema, p_table_name, p_column_name);
+				if (!PROV_CLASS (provider)->meta_funcs.constraints_tab_s) {
+					WARN_METHOD_NOT_IMPLEMENTED (provider, "constraints_tab_s");
+					break;
 				}
-				else {
-					if (!PROV_CLASS (provider)->meta_funcs.columns_t)
-						return FALSE;
-					return PROV_CLASS (provider)->meta_funcs.columns_t (provider, cnc, store, context, error, 
+				return PROV_CLASS (provider)->meta_funcs.constraints_tab_s (provider, cnc, store, context, error, 
 											    p_table_schema, p_table_name);
-				}
 			}
 			else {
-				if (!PROV_CLASS (provider)->meta_funcs.columns)
-					return FALSE;
-				return PROV_CLASS (provider)->meta_funcs.columns (provider, cnc, store, context, error);
+				if (!PROV_CLASS (provider)->meta_funcs.constraints_tab) {
+					WARN_METHOD_NOT_IMPLEMENTED (provider, "constraints_tab");
+					break;
+				}
+				return PROV_CLASS (provider)->meta_funcs.constraints_tab (provider, cnc, store, context, error);
 			}
 		}
 		break;
-	
-	case 'b': {
-		/* _builtin_data_types, params: 
-		 *  - none
-		 */
-		ASSERT_TABLE_NAME (tname, "builtin_data_types")
-		if (!PROV_CLASS (provider)->meta_funcs.btypes)
-			break;
-		return PROV_CLASS (provider)->meta_funcs.btypes (provider, cnc, store, context, error);
-	}
 	default:
 		break;
 	}
@@ -1959,8 +2041,10 @@
 		retval = local_meta_update (cnc->priv->provider_obj, cnc, &lcontext, error);
 		
 		g_signal_handler_disconnect (store, signal_id);
-		if (cbd.error_set)
+		if (cbd.error_set) {
 			g_propagate_error (error, lerror);
+			retval = FALSE;
+		}
 	}
 
 	return retval;
@@ -2334,28 +2418,6 @@
 }
 
 void
-gda_connection_internal_sql_executed (GdaConnection *cnc, const gchar *sql, GdaConnectionEvent *error)
-{
-	GdaTransactionStatus *st = NULL;
-	
-	if (cnc->priv->trans_status)
-		st = gda_transaction_status_find_current (cnc->priv->trans_status, NULL, FALSE);
-	if (st)
-		gda_transaction_status_add_event_sql (st, sql, error);
-#ifdef GDA_DEBUG_signal
-		g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
-#endif
-		g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0);
-#ifdef GDA_DEBUG_signal
-		g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
-#endif
-#ifdef GDA_DEBUG_NO
-	if (cnc->priv->trans_status)
-		gda_transaction_status_dump (cnc->priv->trans_status, 5);
-#endif
-}
-
-void
 gda_connection_internal_savepoint_added (GdaConnection *cnc, const gchar *parent_trans, const gchar *svp_name)
 {
 	GdaTransactionStatus *st;
@@ -2430,7 +2492,7 @@
 }
 
 void 
-gda_connection_internal_statement_executed (GdaConnection *cnc, GdaStatement *stmt, GdaConnectionEvent *error)
+gda_connection_internal_statement_executed (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params, GdaConnectionEvent *error)
 {
 	if (!error || (error && (gda_connection_event_get_event_type (error) != GDA_CONNECTION_EVENT_ERROR))) {
 		GdaSqlStatement *sqlst;
@@ -2459,10 +2521,37 @@
 		case GDA_SQL_STATEMENT_DELETE_SAVEPOINT:
 			gda_connection_internal_savepoint_removed (cnc, trans->trans_name);
 			break;
-		default:
-			gda_connection_internal_sql_executed (cnc, sqlst->sql, error);
+		default: {
+			GdaTransactionStatus *st = NULL;
+			
+			if (cnc->priv->trans_status)
+				st = gda_transaction_status_find_current (cnc->priv->trans_status, NULL, FALSE);
+			if (st) {
+				if (sqlst->sql)
+					gda_transaction_status_add_event_sql (st, sqlst->sql, error);
+				else {
+					gchar *sql;
+					sql = gda_statement_to_sql_extended (stmt, cnc, NULL, 
+									     GDA_STATEMENT_SQL_PARAMS_SHORT,
+									     NULL, NULL);
+					gda_transaction_status_add_event_sql (st, sql, error);
+					g_free (sql);
+				}
+			}
+#ifdef GDA_DEBUG_signal
+			g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
+#endif
+			g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0);
+#ifdef GDA_DEBUG_signal
+			g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
+#endif
+#ifdef GDA_DEBUG_NO
+			if (cnc->priv->trans_status)
+				gda_transaction_status_dump (cnc->priv->trans_status, 5);
+#endif
 			break;
 		}
+		}
 		gda_sql_statement_free (sqlst);
 	}
 }

Modified: branches/V4-branch/libgda/gda-data-proxy.c
==============================================================================
--- branches/V4-branch/libgda/gda-data-proxy.c	(original)
+++ branches/V4-branch/libgda/gda-data-proxy.c	Wed Mar  5 17:44:37 2008
@@ -79,7 +79,7 @@
 static void                 gda_data_proxy_send_hint       (GdaDataModel *model, GdaDataModelHint hint, 
 							    const GValue *hint_value);
 #define DEBUG_SYNC
-/*#undef DEBUG_SYNC*/
+#undef DEBUG_SYNC
 
 /* get a pointer to the parents to be able to call their destructor */
 static GObjectClass  *parent_class = NULL;

Modified: branches/V4-branch/libgda/gda-meta-store.c
==============================================================================
--- branches/V4-branch/libgda/gda-meta-store.c	(original)
+++ branches/V4-branch/libgda/gda-meta-store.c	Wed Mar  5 17:44:37 2008
@@ -164,7 +164,7 @@
 struct _GdaMetaStoreClassPrivate {
 	GdaSqlParser  *parser;;
 	GdaStatement **prep_stmts; /* Simple prepared statements, of size STMT_LAST, general usage */
-	
+
 	/* Internal database's schema information */
 	GSList        *db_objects; /* list of DbObject structures */
 	GHashTable    *db_objects_hash; /* key = table name, value = a DbObject structure */
@@ -374,7 +374,7 @@
 		if (lerror)
 			g_error_free (lerror);
 	}
-	
+	g_string_free (string, TRUE);
 #endif
 }
 
@@ -1710,6 +1710,7 @@
 	if (params) {
 		va_list ap;
 		gchar *pname;
+		GSList *list, *params_set = NULL;
 		va_start (ap, error);
 		for (pname = va_arg (ap, gchar *); pname; pname = va_arg (ap, gchar *)) {
 			GValue *value;
@@ -1725,11 +1726,20 @@
 					g_object_unref (stmt);
 					g_object_unref (params);
 					va_end (ap);
+					g_slist_free (params_set);
 					return NULL;
 				}
+				params_set = g_slist_prepend (params_set, h);
 			}
 		}
 		va_end (ap);
+
+		for (list = params->holders; list; list = list->next) {
+			if (!g_slist_find (params_set, list->data))
+				g_warning (_("No value set for parameter '%s'"), 
+					   gda_holder_get_id (GDA_HOLDER (list->data)));
+		}
+		g_slist_free (params_set);
 	}
 
 	/* execution */
@@ -1858,7 +1868,8 @@
 	gboolean prep, with_cond;
 	gboolean retval = TRUE;
 	GSList *all_changes = NULL;
-	
+	gboolean started_transaction;
+
 	g_return_val_if_fail (GDA_IS_META_STORE (store), FALSE);
 	g_return_val_if_fail (store->priv, FALSE);
 	g_return_val_if_fail (store->priv->cnc, FALSE);
@@ -1893,6 +1904,14 @@
 	gda_data_model_dump (current, stdout);
 #endif
 	
+	/* start a transaction if possible */
+	if (! gda_connection_get_transaction_status (store->priv->cnc)) {
+		started_transaction = gda_connection_begin_transaction (store->priv->cnc, NULL,
+									GDA_TRANSACTION_ISOLATION_UNKNOWN,
+									NULL);
+		g_print ("------- BEGIN\n");
+	}
+
 	/* treat rows to insert / update */
 	if (new_data) {
 		gint new_n_rows, new_n_cols;
@@ -2006,7 +2025,16 @@
 				for (k = 0; k < tfk->cols_nb; k++) 
 					context.column_values [k] = (GValue*) gda_data_model_get_value_at (new_data, 
 													   tfk->ref_pk_cols_array[k], i);
-				g_print ("Suggest update data into table '%s'...\n", tfk->table_info->obj_name);
+#ifdef GDA_DEBUG
+				g_print ("Suggest update data into table '%s':", tfk->table_info->obj_name);
+				for (k = 0; k < tfk->cols_nb; k++) {
+					gchar *str;
+					str = gda_value_stringify (context.column_values [k]);
+					g_print (" [%s => %s]", context.column_names[k], str);
+					g_free (str);
+				}
+				g_print ("\n");
+#endif
 				g_signal_emit (store, gda_meta_store_signals[SUGGEST_UPDATE], 0, &context);
 				g_free (context.column_values);
 			}
@@ -2075,7 +2103,11 @@
 		}
 	}
 
-	if (all_changes) 
+	if (retval && started_transaction) {
+		retval = gda_connection_commit_transaction (store->priv->cnc, NULL, NULL);
+		g_print ("------- COMMIT\n");
+	}
+	if (retval && all_changes) 
 		g_signal_emit (store, gda_meta_store_signals[META_CHANGED], 0, all_changes);
 	
 out:
@@ -2086,6 +2118,10 @@
 	g_free (rows_to_del);
 	if (current)
 		g_object_unref (current);
+	if (!retval && started_transaction) {
+		gda_connection_rollback_transaction (store->priv->cnc, NULL, NULL);
+		g_print ("------- ROLLBACK\n");
+	}
 	return retval;
 }
 
@@ -2111,7 +2147,7 @@
 	if (erow >= 0) {
 		gint ncols;
 		ncols = gda_data_model_get_n_columns (find_in);
-		if (ncols != gda_data_model_get_n_columns (data)) {
+		if (ncols > gda_data_model_get_n_columns (data)) {
 			g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_MODIFY_CONTENTS_ERROR,
 				_("Data models should have the same number of columns"));
 			erow = -2;

Added: branches/V4-branch/libgda/gda-meta-struct.c
==============================================================================
--- (empty file)
+++ branches/V4-branch/libgda/gda-meta-struct.c	Wed Mar  5 17:44:37 2008
@@ -0,0 +1,608 @@
+/* gda-meta-struct.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-meta-store.h>
+#include <libgda/gda-meta-struct.h>
+#include <libgda/gda-util.h>
+#include <sql-parser/gda-sql-parser.h>
+#include <sql-parser/gda-sql-statement.h>
+
+/* module error */
+GQuark gda_meta_struct_error_quark (void) {
+        static GQuark quark;
+        if (!quark)
+                quark = g_quark_from_static_string ("gda_meta_struct_error");
+        return quark;
+}
+
+static void gda_meta_db_object_free (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);
+static void gda_meta_table_foreign_key_free (GdaMetaTableForeignKey *tfk);
+
+/**
+ * gda_meta_struct_new
+ *
+ * Creates a new initialized #GdaMetaStruct structure
+ */
+GdaMetaStruct *
+gda_meta_struct_new (void)
+{
+	GdaMetaStruct *mstruct;
+	mstruct = g_new0 (GdaMetaStruct, 1);
+	mstruct->db_objects = NULL;
+	mstruct->index = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+	return mstruct;
+}
+
+static void
+compute_view_dependencies (GdaMetaStruct *mstruct, GdaMetaDbObject *view_dbobj, GdaSqlStatement *sqlst) {	
+	if (sqlst->stmt_type == GDA_SQL_STATEMENT_SELECT) {
+		GdaSqlStatementSelect *selst;
+		selst = (GdaSqlStatementSelect*) (sqlst->contents);
+		GSList *targets;
+		for (targets = selst->from->targets; targets; targets = targets->next) {
+			GdaSqlSelectTarget *t = (GdaSqlSelectTarget *) targets->data;
+			GValue *catalog, *schema, *name;
+			GdaMetaDbObject *ref_obj;
+
+			if (!t->table_name)
+				continue;
+			/* FIXME: compute catalog, schema, name using t->table_name */
+			/*
+			ref_obj = gda_meta_struct_get_db_object (mstruct, catalog, schema, name);
+			if (!ref_obj) {
+				gchar *str;
+				ref_obj = g_new0 (GdaMetaDbObject, 1);
+				ref_obj->obj_type = GDA_META_DB_UNKNOWN;
+				ref_obj->obj_catalog = g_strdup (g_value_get_string (fk_catalog));
+				ref_obj->obj_schema = g_strdup (g_value_get_string (fk_schema));
+				ref_obj->obj_name = g_strdup (g_value_get_string (fk_name));
+				mstruct->db_objects = g_slist_append (mstruct->db_objects, ref_obj);
+				str = g_strdup_printf ("%s.%s.%s", g_value_get_string (fk_catalog), 
+						       g_value_get_string (fk_schema), 
+						       g_value_get_string (fk_name));
+				g_hash_table_insert (mstruct->index, str, ref_obj);
+			}
+			view_dbobj->depend_list = g_slist_append (view_dbobj->depend_list, ref_obj);
+			*/
+		}
+	}
+	else if (sqlst->stmt_type == GDA_SQL_STATEMENT_COMPOUND) {
+		GdaSqlStatementCompound *cst;
+		GSList *list;
+		cst = (GdaSqlStatementCompound*) (sqlst->contents);
+		for (list = cst->stmt_list; list; list = list->next)
+			compute_view_dependencies (mstruct, view_dbobj, (GdaSqlStatement*) list->data);
+	}
+	else
+		g_assert_not_reached ();
+}
+
+/**
+ * gda_meta_struct_complement
+ * @mstruct: a #GdaMetaStruct structure
+ * @store: the #GdaMetaStore to use
+ * @type: the type of object to add
+ * @catalog: the catalog the object belongs to (as a G_TYPE_STRING GValue)
+ * @schema: the schema the object belongs to (as a G_TYPE_STRING GValue)
+ * @name: the object's name (as a G_TYPE_STRING GValue)
+ * @error: a place to store errors, or %NULL
+ *
+ * Creates a new #GdaMetaDbObject structure in @mstruct to represent the database object (of type @type)
+ * which can be uniquely identified as @catalog  schema @name.
+ *
+ * Returns: the #GdaMetaDbObject corresponding to the database object if no error occurred, or %NULL
+ */
+GdaMetaDbObject *
+gda_meta_struct_complement (GdaMetaStruct *mstruct, GdaMetaStore *store, GdaMetaDbObjectType type,
+			    const GValue *catalog, const GValue *schema, const GValue *name, 
+			    GError **error)
+{
+	GdaMetaDbObject *dbo = NULL;
+
+	g_return_val_if_fail (GDA_IS_META_STORE (store), NULL);
+	g_return_val_if_fail (mstruct, NULL);
+	g_return_val_if_fail (catalog && (G_VALUE_TYPE (catalog) == G_TYPE_STRING), NULL);
+	g_return_val_if_fail (schema && (G_VALUE_TYPE (schema) == G_TYPE_STRING), NULL);
+	g_return_val_if_fail (name && (G_VALUE_TYPE (name) == G_TYPE_STRING), NULL);
+	
+	/* create new GdaMetaDbObject or get already existing one */
+	dbo = gda_meta_struct_get_db_object (mstruct, catalog, schema, name);
+	if (!dbo) {
+		dbo = g_new0 (GdaMetaDbObject, 1);
+		dbo->obj_catalog = g_strdup (g_value_get_string (catalog));
+		dbo->obj_schema = g_strdup (g_value_get_string (schema));
+		dbo->obj_name = g_strdup (g_value_get_string (name));
+		dbo->obj_short_name = NULL;
+		dbo->obj_full_name = NULL;
+	}
+	else if (dbo->obj_type == type)
+		return dbo; /* nothing to do */
+	else if (dbo->obj_type != GDA_META_DB_UNKNOWN) {
+		/* DB Object already exists, return an error */
+		g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_DUPLICATE_OBJECT_ERROR,
+			     _("Object %s.%s.%s already exists in GdaMetaStruct and has a different object type"), 
+			     g_value_get_string (catalog), g_value_get_string (schema), 
+			     g_value_get_string (name));
+		dbo = NULL;
+		goto onerror;
+	}
+	dbo->obj_type = type;
+
+	switch (type) {
+	case GDA_META_DB_VIEW: {
+		gchar *sql = "SELECT view_definition, is_updatable FROM _views "
+			"WHERE table_catalog = ##tc::string "
+			"AND table_schema = ##ts::string AND table_name = ##tname::string";
+		GdaDataModel *model;
+		gint nrows;
+		GdaMetaView *mv;
+
+		model = gda_meta_store_extract (store, sql, error, "tc", catalog, "ts", schema, "tname", name, NULL);
+		if (!model) 
+			goto onerror;
+		nrows = gda_data_model_get_n_rows (model);
+		if (nrows < 1) {
+			g_object_unref (model);
+			g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR,
+				     _("View %s.%s.%s not found in meta store object"), 
+				     g_value_get_string (catalog), g_value_get_string (schema), 
+				     g_value_get_string (name));
+			goto onerror;
+		}
+		
+		mv = GDA_META_DB_OBJECT_GET_VIEW (dbo);
+		mv->view_def = g_strdup (g_value_get_string (gda_data_model_get_value_at (model, 0, 0)));
+		mv->is_updatable = g_value_get_boolean (gda_data_model_get_value_at (model, 1, 0));
+
+		/* view's dependencies, from its definition */
+		if (mv->view_def && *mv->view_def) {
+			static GdaSqlParser *parser = NULL;
+			GdaStatement *stmt;
+			const gchar *remain;
+			if (!parser)
+				parser = gda_sql_parser_new ();
+			stmt = gda_sql_parser_parse_string (parser, mv->view_def, &remain, NULL);
+			if (stmt &&
+			    ((gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT) ||
+			     (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_COMPOUND))) {
+				GdaSqlStatement *sqlst;
+				g_object_get (G_OBJECT (stmt), "structure", &sqlst, NULL);
+				compute_view_dependencies (mstruct, dbo, sqlst);
+				gda_sql_statement_free (sqlst);
+				g_object_unref (stmt);
+				
+#ifdef GDA_DEBUG_NO
+				g_print ("View %s depends on: ", dbo->obj_name);
+				GSList *list;
+				for (list = dbo->depend_list; list; list = list->next) 
+					g_print ("%s ", GDA_META_DB_OBJECT (list->data)->obj_name);
+				g_print ("\n");
+#endif
+			}
+		}
+	}
+	case GDA_META_DB_TABLE: {
+		/* columns */
+		gchar *sql = "SELECT c.column_name, c.data_type, c.gtype, c.is_nullable, t.table_short_name, t.table_full_name, "
+			"c.column_default FROM _columns as c NATURAL JOIN _tables as t WHERE table_catalog = ##tc::string "
+			"AND table_schema = ##ts::string AND table_name = ##tname::string "
+			"ORDER BY ordinal_position";
+		GdaMetaTable *mt;
+		GdaDataModel *model;
+		gint i, nrows;
+
+		model = gda_meta_store_extract (store, sql, error, "tc", catalog, "ts", schema, "tname", name, NULL);
+		if (!model) 
+			goto onerror;
+
+		nrows = gda_data_model_get_n_rows (model);
+		if (nrows < 1) {
+			g_object_unref (model);
+			g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR,
+				     _("Table %s.%s.%s not found in meta store object"), 
+				     g_value_get_string (catalog), g_value_get_string (schema), 
+				     g_value_get_string (name));
+			goto onerror;
+		}
+
+		mt = GDA_META_DB_OBJECT_GET_TABLE (dbo);
+		for (i = 0; i < nrows; i++) {
+			GdaMetaTableColumn *tcol;
+			const GValue *val;
+			tcol = g_new0 (GdaMetaTableColumn, 1);
+			tcol->column_name = g_strdup (g_value_get_string (gda_data_model_get_value_at (model, 0, i)));
+			tcol->column_type = g_strdup (g_value_get_string (gda_data_model_get_value_at (model, 1, i)));
+			tcol->gtype = gda_g_type_from_string (g_value_get_string (gda_data_model_get_value_at (model, 2, i)));
+			tcol->nullok = g_value_get_boolean (gda_data_model_get_value_at (model, 3, i));
+			val = gda_data_model_get_value_at (model, 1, 6);
+			if (val && !gda_value_is_null (val))
+				tcol->default_value = g_strdup (g_value_get_string (val));
+
+			/* Note: tcol->pkey is not determined here */
+			mt->columns = g_slist_prepend (mt->columns, tcol);
+
+			if (i == 0) {
+				dbo->obj_short_name = g_strdup (g_value_get_string (gda_data_model_get_value_at (model, 4, i)));
+				dbo->obj_full_name = g_strdup (g_value_get_string (gda_data_model_get_value_at (model, 5, i)));
+			}
+		}
+		mt->columns = g_slist_reverse (mt->columns);
+		g_object_unref (model);
+
+		/* primary key */
+		sql = "SELECT constraint_catalog, constraint_schema, constraint_name FROM _table_constraints WHERE constraint_type='PRIMARY KEY' AND table_catalog = ##tc::string AND table_schema = ##ts::string AND table_name = ##tname::string";
+		model = gda_meta_store_extract (store, sql, error, "tc", catalog, "ts", schema, "tname", name, NULL);
+		if (!model) 
+			goto onerror;
+
+		nrows = gda_data_model_get_n_rows (model);
+		if (nrows >= 1) {
+			GdaDataModel *pkmodel;
+			sql = "SELECT column_name FROM _key_column_usage WHERE constraint_catalog = ##cc::string AND constraint_schema = ##cs::string AND constraint_name = ##cname::string ORDER BY ordinal_position";
+			pkmodel = gda_meta_store_extract (store, sql, error, 
+							  "cc", gda_data_model_get_value_at (model, 0, 0),
+							  "cs", gda_data_model_get_value_at (model, 1, 0),
+							  "cname", gda_data_model_get_value_at (model, 2, 0), NULL);
+			if (!pkmodel) {
+				g_object_unref (model);
+				goto onerror;
+			}
+			nrows = gda_data_model_get_n_rows (pkmodel);
+			mt->pk_cols_nb = nrows;
+			mt->pk_cols_array = g_new0 (gint, mt->pk_cols_nb);
+			for (i = 0; i < nrows; i++) {
+				GdaMetaTableColumn *tcol;
+				tcol = gda_meta_struct_get_table_column (mstruct, mt, 
+									 gda_data_model_get_value_at (model, 0, i));
+				if (!tcol) {
+					mt->pk_cols_array [i] = -1;
+					g_warning (_("Internal GdaMetaStore error: column %s not found"),
+						   g_value_get_string (gda_data_model_get_value_at (model, 0, i)));
+				}
+				else {
+					mt->pk_cols_array [i] = g_slist_index (mt->columns, tcol);
+					tcol->pkey = TRUE;
+				}
+			}
+
+			g_object_unref (pkmodel);
+		}
+		g_object_unref (model);
+
+		/* foreign keys */
+		sql = "SELECT t.table_catalog, t.table_schema, t.table_name FROM _tables as f INNER JOIN _table_constraints as tc ON (tc.table_catalog=f.table_catalog AND tc.table_schema=f.table_schema AND tc.table_name=f.table_name) INNER JOIN _referential_constraints as rc ON (rc.constraint_catalog = tc.constraint_catalog AND rc.constraint_schema=tc.constraint_schema AND rc.constraint_name=tc.constraint_name) INNER JOIN _table_constraints as tc2 ON (rc.unique_constraint_catalog = tc2.constraint_catalog AND rc.unique_constraint_schema=tc2.constraint_schema AND rc.unique_constraint_name=tc2.constraint_name) INNER JOIN _tables as t ON (tc2.table_catalog=t.table_catalog AND tc2.table_schema=t.table_schema AND tc2.table_name=t.table_name) WHERE f.table_catalog = ##tc::string AND f.table_schema = ##ts::string AND f.table_name = ##tname::string";
+		model = gda_meta_store_extract (store, sql, error, "tc", catalog, "ts", schema, "tname", name, NULL);
+		if (!model) 
+			goto onerror;
+
+		nrows = gda_data_model_get_n_rows (model);
+		for (i = 0; i < nrows; i++) {
+			GdaMetaTableForeignKey *tfk;
+			const GValue *fk_catalog, *fk_schema, *fk_name;
+
+			fk_catalog = gda_data_model_get_value_at (model, 0, i);
+			fk_schema = gda_data_model_get_value_at (model, 1, i);
+			fk_name = gda_data_model_get_value_at (model, 2, i);
+			tfk = g_new0 (GdaMetaTableForeignKey, 1);
+			tfk->meta_table = dbo;
+			tfk->depend_on = gda_meta_struct_get_db_object (mstruct, fk_catalog, fk_schema, fk_name);
+			if (!tfk->depend_on) {
+				gchar *str;
+				tfk->depend_on = g_new0 (GdaMetaDbObject, 1);
+				tfk->depend_on->obj_type = GDA_META_DB_UNKNOWN;
+				tfk->depend_on->obj_catalog = g_strdup (g_value_get_string (fk_catalog));
+				tfk->depend_on->obj_schema = g_strdup (g_value_get_string (fk_schema));
+				tfk->depend_on->obj_name = g_strdup (g_value_get_string (fk_name));
+				mstruct->db_objects = g_slist_append (mstruct->db_objects, tfk->depend_on);
+				str = g_strdup_printf ("%s.%s.%s", g_value_get_string (fk_catalog), 
+						       g_value_get_string (fk_schema), 
+						       g_value_get_string (fk_name));
+				g_hash_table_insert (mstruct->index, str, tfk->depend_on);
+			}
+			dbo->depend_list = g_slist_append (dbo->depend_list, tfk->depend_on);
+
+			/* FIXME: compute @cols_nb, and all the @*_array members (ref_pk_cols_array must be
+			 * initialized with -1 values everywhere */
+
+			mt->fk_list = g_slist_prepend (mt->fk_list, tfk);
+		}
+		mt->fk_list = g_slist_reverse (mt->fk_list);
+		g_object_unref (model);
+		/* Note: mt->reverse_fk_list is not determined here */
+		
+		break;
+	}
+	default:
+		TO_IMPLEMENT;
+	}
+
+	if (dbo && !g_slist_find (mstruct->db_objects, dbo)) {
+		gchar *str;
+		mstruct->db_objects = g_slist_append (mstruct->db_objects, dbo);
+		str = g_strdup_printf ("%s.%s.%s", g_value_get_string (catalog), 
+				       g_value_get_string (schema), 
+				       g_value_get_string (name));
+		g_hash_table_insert (mstruct->index, str, dbo);
+	}
+	if (dbo) {
+		/* compute GdaMetaTableForeignKey's @ref_pk_cols_array arrays and GdaMetaTable' @reverse_fk_list lists*/
+		GSList *list;
+		for (list = mstruct->db_objects; list; list = list->next) {
+			GdaMetaDbObject *tmpdbo;
+			tmpdbo = GDA_META_DB_OBJECT (list->data);
+			if (tmpdbo->obj_type != GDA_META_DB_TABLE)
+				continue;
+			GdaMetaTable *mt = GDA_META_DB_OBJECT_GET_TABLE (tmpdbo);
+			GSList *klist;
+			for (klist = mt->fk_list; klist; klist = klist->next) {
+				GdaMetaTableForeignKey *tfk = GDA_META_TABLE_FOREIGN_KEY (klist->data);
+				GdaMetaTable *ref_mt = GDA_META_DB_OBJECT_GET_TABLE (tfk->depend_on);
+				gint i;
+				for (i = 0; i < tfk->cols_nb; i++) {
+					gint col;
+					GdaMetaTableColumn *r_tcol;
+					GValue *r_val;
+
+					if (tfk->ref_pk_cols_array[i] != -1) /* already correctly set */
+						continue;
+
+					if (tfk->depend_on->obj_type != GDA_META_DB_TABLE)
+						continue; /* can't be set now */
+
+					g_value_set_string ((r_val = gda_value_new (G_TYPE_STRING)), tfk->ref_pk_names_array[i]);
+					r_tcol = gda_meta_struct_get_table_column (mstruct, ref_mt, r_val);
+					gda_value_free (r_val);
+					col = g_slist_index (ref_mt->columns, r_tcol);
+					if (!r_tcol || (col < 0)) {
+						g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_INCOHERENCE_ERROR,
+							     _("Foreign key column '%s' not found in table '%s'"),
+							     tfk->ref_pk_names_array[i], tfk->depend_on->obj_name);
+						dbo = NULL;
+						goto onerror;
+					}
+					tfk->ref_pk_cols_array[i] = col;
+				}
+				ref_mt->reverse_fk_list = g_slist_append (ref_mt->reverse_fk_list, tmpdbo);
+			}
+		}
+	}
+	return dbo;
+
+ onerror:
+	if (dbo)
+		gda_meta_db_object_free (dbo);
+	return NULL;
+}
+
+/*
+ * Makes a list of all the GdaMetaDbObject structures listed in @objects
+ * which are not present in @ordered_list and for which no dependency is in @ordered_list
+ */
+static GSList *
+build_pass (GSList *objects, GSList *ordered_list)
+{
+	GSList *retlist = NULL, *list;
+
+	for (list = objects; list; list = list->next) {
+		gboolean has_dep = FALSE;
+		GSList *dep_list;
+		if (g_slist_find (ordered_list, list->data))
+			continue;
+		for (dep_list = GDA_META_DB_OBJECT (list->data)->depend_list; dep_list; dep_list = dep_list->next) {
+			if (!g_slist_find (ordered_list, dep_list->data)) {
+				has_dep = TRUE;
+				break;
+			}
+		}
+		if (has_dep)
+			continue;
+		retlist = g_slist_prepend (retlist, list->data);
+	}
+
+#ifdef GDA_DEBUG_NO
+	g_print (">> PASS\n");
+	for (list = retlist; list; list = list->next) 
+		g_print ("--> %s\n", GDA_META_DB_OBJECT (list->data)->obj_name);
+	g_print ("<<\n");
+#endif
+
+	return retlist;
+}
+
+/**
+ * gda_meta_struct_order_db_objects
+ * @mstruct: a #GdaMetaStruct structure
+ * @error: a place to store errors, or %NULL
+ *
+ * Reorders the list of database objects within @mstruct in a way that for any given GdaMetaDbObject in the list, 
+ * all the dependencies are _before_ it in the list.
+ *
+ * Returns: TRUE if no error occurred
+ */ 
+gboolean
+gda_meta_struct_order_db_objects (GdaMetaStruct *mstruct, GError **error)
+{
+	GSList *pass_list;
+	GSList *ordered_list = NULL;
+
+	g_return_val_if_fail (mstruct, FALSE);
+	for (pass_list = build_pass (mstruct->db_objects, ordered_list); 
+	     pass_list; 
+	     pass_list = build_pass (mstruct->db_objects, ordered_list)) 
+		ordered_list = g_slist_concat (ordered_list, pass_list);
+
+#ifdef GDA_DEBUG_NO
+	GSList *list;
+	for (list = ordered_list; list; list = list->next) 
+		g_print ("--> %s\n", GDA_META_DB_OBJECT (list->data)->obj_name);
+#endif
+
+	g_slist_free (mstruct->db_objects);
+	mstruct->db_objects = ordered_list;
+	return TRUE;
+}
+
+/**
+ * gda_meta_struct_get_db_object
+ * @mstruct: a #GdaMetaStruct structure
+ * @catalog: the catalog the object belongs to (as a G_TYPE_STRING GValue)
+ * @schema: the schema the object belongs to (as a G_TYPE_STRING GValue)
+ * @name: the object's name (as a G_TYPE_STRING GValue)
+ *
+ * Tries to locate the #GdaMetaDbObject structure representing the database object named after
+ * @catalog, @schema and @name.
+ *
+ * Returns: the #GdaMetaDbObject or %NULL if not found
+ */
+GdaMetaDbObject *
+gda_meta_struct_get_db_object (GdaMetaStruct *mstruct, const GValue *catalog, const GValue *schema, const GValue *name)
+{
+	gchar *key;
+	GdaMetaDbObject *dbo;
+
+	g_return_val_if_fail (mstruct, NULL);
+	g_return_val_if_fail (catalog && (G_VALUE_TYPE (catalog) == G_TYPE_STRING), NULL);
+	g_return_val_if_fail (schema && (G_VALUE_TYPE (schema) == G_TYPE_STRING), NULL);
+	g_return_val_if_fail (name && (G_VALUE_TYPE (name) == G_TYPE_STRING), NULL);
+
+	key = g_strdup_printf ("%s.%s.%s", g_value_get_string (catalog), g_value_get_string (schema), 
+			       g_value_get_string (name));
+	dbo = g_hash_table_lookup (mstruct->index, key);
+	g_free (key);
+	return dbo;
+}
+
+/**
+ * gda_meta_struct_get_table_column
+ * @mstruct: a #GdaMetaStruct structure
+ * @table: the #GdaMetaTable structure to find the column for
+ * @col_name: the name of the column to find (as a G_TYPE_STRING GValue)
+ *
+ * Tries to find the #GdaMetaTableColumn representing the column named @col_name in @table.
+ *
+ * Returns: the #GdaMetaTableColumn or %NULL if not found
+ */
+GdaMetaTableColumn *
+gda_meta_struct_get_table_column (GdaMetaStruct *mstruct, GdaMetaTable *table, const GValue *col_name)
+{
+	GSList *list;
+	const gchar *cname;
+	g_return_val_if_fail (mstruct, NULL);
+	g_return_val_if_fail (table, NULL);
+	g_return_val_if_fail (col_name && (G_VALUE_TYPE (col_name) == G_TYPE_STRING), NULL);
+	cname = g_value_get_string (col_name);
+
+	for (list = table->columns; list; list = list->next) {
+		GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data);
+		if (!strcmp (tcol->column_name, cname))
+			return tcol;
+	}
+	return NULL;
+}
+
+/**
+ * gda_meta_struct_free
+ * @mstruct: a #GdaMetaStruct structure
+ * 
+ * Releases any memory associated to @mstruct.
+ */
+void
+gda_meta_struct_free (GdaMetaStruct *mstruct)
+{
+	if (!mstruct)
+		return;
+
+	g_slist_foreach (mstruct->db_objects, (GFunc) gda_meta_db_object_free, NULL);
+	g_slist_free (mstruct->db_objects);
+	g_hash_table_destroy (mstruct->index);
+	g_free (mstruct);
+}
+
+
+static void
+gda_meta_db_object_free (GdaMetaDbObject *dbo)
+{
+	g_free (dbo->obj_catalog);
+	g_free (dbo->obj_schema);
+	g_free (dbo->obj_name);
+	g_free (dbo->obj_short_name);
+	g_free (dbo->obj_full_name);
+	switch (dbo->obj_type) {
+	case GDA_META_DB_UNKNOWN:
+		break;
+	case GDA_META_DB_TABLE:
+		gda_meta_table_free_contents (GDA_META_DB_OBJECT_GET_TABLE (dbo));
+		break;
+	case GDA_META_DB_VIEW:
+		gda_meta_view_free_contents (GDA_META_DB_OBJECT_GET_VIEW (dbo));
+		break;
+	default:
+		TO_IMPLEMENT;
+	}
+	g_slist_free (dbo->depend_list);
+}
+
+static void
+gda_meta_table_free_contents (GdaMetaTable *table)
+{
+	g_slist_foreach (table->columns, (GFunc) gda_meta_table_column_free, NULL);
+	g_slist_free (table->columns);
+	g_free (table->pk_cols_array);
+	g_slist_foreach (table->fk_list, (GFunc) gda_meta_table_foreign_key_free, NULL);
+	g_slist_free (table->fk_list);
+	g_slist_free (table->reverse_fk_list);
+}
+
+static void
+gda_meta_view_free_contents (GdaMetaView *view)
+{
+	gda_meta_table_free_contents ((GdaMetaTable*) view);
+	g_free (view->view_def);
+}
+
+static void
+gda_meta_table_column_free (GdaMetaTableColumn *tcol)
+{
+	g_free (tcol->column_name);
+	g_free (tcol->column_type);
+	g_free (tcol->default_value);
+	g_free (tcol);
+}
+
+static void
+gda_meta_table_foreign_key_free (GdaMetaTableForeignKey *tfk)
+{
+	gint i;
+	for (i = 0; i < tfk->cols_nb; i++) {
+		g_free (tfk->fk_names_array[i]);
+		g_free (tfk->ref_pk_names_array[i]);
+	}
+	g_free (tfk->fk_cols_array);
+	g_free (tfk->fk_names_array);
+	g_free (tfk->ref_pk_cols_array);
+	g_free (tfk->ref_pk_names_array);
+	g_free (tfk);
+}

Added: branches/V4-branch/libgda/gda-meta-struct.h
==============================================================================
--- (empty file)
+++ branches/V4-branch/libgda/gda-meta-struct.h	Wed Mar  5 17:44:37 2008
@@ -0,0 +1,137 @@
+/* gda-meta-struct.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_META_STRUCT_H_
+#define __GDA_META_STRUCT_H_
+
+#include <glib-object.h>
+#include <libgda/gda-enums.h>
+#include <libgda/gda-data-model.h>
+
+G_BEGIN_DECLS
+
+/* error reporting */
+extern GQuark gda_meta_struct_error_quark (void);
+#define GDA_META_STRUCT_ERROR gda_meta_struct_error_quark ()
+
+typedef enum {
+        GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR,
+	GDA_META_STRUCT_DUPLICATE_OBJECT_ERROR,
+	GDA_META_STRUCT_INCOHERENCE_ERROR
+} GdaMetaStructError;
+
+
+typedef enum {
+	GDA_META_DB_UNKNOWN,
+	GDA_META_DB_TABLE,
+	GDA_META_DB_VIEW
+} GdaMetaDbObjectType;
+
+/*
+ * Complements the GdaMetaDbObject structure, for tables only
+ * contains predefined statements for data selection and modifications
+ */
+typedef struct {
+	GSList       *columns; /* list of GdaMetaTableColumn */
+	
+	/* PK fields index */
+	gint         *pk_cols_array;
+	gint          pk_cols_nb;
+
+	/* Foreign keys */
+	GSList       *reverse_fk_list; /* list of GdaMetaTableForeignKey where @depend_on == this GdaMetaDbObject */
+	GSList       *fk_list; /* list of GdaMetaTableForeignKey where @gda_meta_table == this GdaMetaDbObject */
+} GdaMetaTable;
+
+/*
+ * Complements the GdaMetaDbObject structure, for views only
+ * contains more information than for tables
+ */
+typedef struct {
+	GdaMetaTable  table;
+	gchar        *view_def;
+	gboolean      is_updatable;
+} 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, ...
+ */
+typedef struct {
+	GdaMetaDbObjectType     obj_type;
+	gchar                  *obj_catalog;
+	gchar                  *obj_schema;
+	gchar                  *obj_name;
+	gchar                  *obj_short_name;
+	gchar                  *obj_full_name;
+
+	union {
+		GdaMetaTable    meta_table;
+		GdaMetaView     meta_view;
+	}                       extra;
+
+	GSList                 *depend_list; /* list of GdaMetaDbObject pointers on which this object depends */
+} GdaMetaDbObject;
+#define GDA_META_DB_OBJECT(x) ((GdaMetaDbObject*)(x))
+#define GDA_META_DB_OBJECT_GET_TABLE(dbobj) (&((dbobj)->extra.meta_table))
+#define GDA_META_DB_OBJECT_GET_VIEW(dbobj) (&((dbobj)->extra.meta_view))
+
+typedef struct {
+	gchar        *column_name;
+	gchar        *column_type;
+	GType         gtype;
+	gboolean      pkey;
+        gboolean      nullok;
+	gchar        *default_value;
+} GdaMetaTableColumn;
+#define GDA_META_TABLE_COLUMN(x) ((GdaMetaTableColumn*)(x))
+
+typedef struct {
+	GdaMetaDbObject  *meta_table;
+	GdaMetaDbObject  *depend_on;
+
+	gint              cols_nb;	
+	gint             *fk_cols_array; /* FK fields index */
+	gchar           **fk_names_array; /* FK fields names */
+	gint             *ref_pk_cols_array; /* Ref PK fields index */
+	gchar           **ref_pk_names_array; /* Ref PK fields names */
+} GdaMetaTableForeignKey;
+#define GDA_META_TABLE_FOREIGN_KEY(x) ((GdaMetaTableForeignKey*)(x))
+
+typedef struct {
+	GSList *db_objects; /* list of GdaMetaDbObject structures */
+	GHashTable *index; /* key = [catalog].[schema].[name], value = a GdaMetaDbObject */
+} GdaMetaStruct;
+
+GdaMetaStruct      *gda_meta_struct_new              (void);
+GdaMetaDbObject    *gda_meta_struct_complement       (GdaMetaStruct *mstruct, GdaMetaStore *store, GdaMetaDbObjectType type,
+						      const GValue *catalog, const GValue *schema, const GValue *name, 
+						      GError **error);
+gboolean            gda_meta_struct_order_db_objects (GdaMetaStruct *mstruct, GError **error);
+GdaMetaDbObject    *gda_meta_struct_get_db_object    (GdaMetaStruct *mstruct, 
+						      const GValue *catalog, const GValue *schema, const GValue *name);
+GdaMetaTableColumn *gda_meta_struct_get_table_column (GdaMetaStruct *mstruct, GdaMetaTable *table, 
+						      const GValue *col_name);
+void                gda_meta_struct_free             (GdaMetaStruct *mstruct);
+
+G_END_DECLS
+
+#endif

Modified: branches/V4-branch/libgda/gda-server-provider.h
==============================================================================
--- branches/V4-branch/libgda/gda-server-provider.h	(original)
+++ branches/V4-branch/libgda/gda-server-provider.h	Wed Mar  5 17:44:37 2008
@@ -75,6 +75,12 @@
 				   const GValue *table_schema, const GValue *table_name);
 	gboolean (*columns_c)     (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **, 
 				   const GValue *table_schema, const GValue *table_name, const GValue *column_name);
+	gboolean (*constraints_tab)(GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **);
+	gboolean (*constraints_tab_s)(GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **, 
+				      const GValue *table_schema, const GValue *table_name);
+	gboolean (*constraints_ref)(GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **);
+	gboolean (*constraints_ref_c)(GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **, 
+				      const GValue *constraint_schema, const GValue *constraint_name);
 } GdaServerProviderMeta;
 
 typedef void (*GdaServerProviderAsyncCallback) (GdaServerProvider *provider, GdaConnection *cnc, guint task_id, 

Modified: branches/V4-branch/libgda/gda-util.c
==============================================================================
--- branches/V4-branch/libgda/gda-util.c	(original)
+++ branches/V4-branch/libgda/gda-util.c	Wed Mar  5 17:44:37 2008
@@ -93,7 +93,7 @@
  * @string: string to escape
  *
  * Escapes @string to make it understandable by a DBMS. The escape method is very common and replaces any
- * occurence of "'" with "\'" and "\" with "\\".
+ * occurence of "'" with "''" and "\" with "\\"
  */
 gchar *
 gda_default_escape_string (const gchar *string)
@@ -119,7 +119,12 @@
 	ret = g_new0 (gchar, size);
 	retptr = ret;
 	while (*ptr) {
-		if ((*ptr == '\'') || (*ptr == '\\')) {
+		if (*ptr == '\'') {
+			*retptr = '\'';
+			*(retptr+1) = *ptr;
+			retptr += 2;
+		}
+		else if (*ptr == '\\') {
 			*retptr = '\\';
 			*(retptr+1) = *ptr;
 			retptr += 2;

Modified: branches/V4-branch/libgda/information_schema.xml
==============================================================================
--- branches/V4-branch/libgda/information_schema.xml	(original)
+++ branches/V4-branch/libgda/information_schema.xml	Wed Mar  5 17:44:37 2008
@@ -37,7 +37,7 @@
     <column name="catalog_name" pkey="TRUE"/>
   </table>
 
-  <table name="_schemata">
+  <table name="_schemata" descr="List of schemas">
     <column name="catalog_name" pkey="TRUE"/>
     <column name="schema_name" pkey="TRUE"/>
     <column name="schema_owner" nullok="TRUE"/>
@@ -47,7 +47,7 @@
     </fkey>
   </table>
 
-  <table name="_builtin_data_types">
+  <table name="_builtin_data_types" descr="List of built-in data types such as varchar, int, ...">
     <column name="short_type_name"/>
     <column name="full_type_name" pkey="TRUE"/>
     <column name="gtype" nullok="TRUE"/>
@@ -59,7 +59,7 @@
     </unique>
   </table>
 
-  <table name="_udt">
+  <table name="_udt" descr="User defined data types">
     <column name="udt_catalog" pkey="TRUE"/>
     <column name="udt_schema" pkey="TRUE"/>
     <column name="udt_name" pkey="TRUE"/>
@@ -74,12 +74,12 @@
     </unique>
   </table>
 
-  <table name="_udt_columns">
+  <table name="_udt_columns" descr="List of components for a user defined data type">
     <column name="udt_catalog" pkey="TRUE"/>
     <column name="udt_schema" pkey="TRUE"/>
     <column name="udt_name" pkey="TRUE"/>
     <column name="udt_column" pkey="TRUE"/>
-    <column name="data_type"/>
+    <column name="data_type" descr="References _all_types.full_type_name or _element_types.specific_name"/>
     <column name="character_maximum_length" type="gint" nullok="TRUE"/>
     <column name="character_octet_length" type="gint" nullok="TRUE"/>
     <column name="numeric_precision" type="gint" nullok="TRUE"/>
@@ -98,11 +98,12 @@
     </fkey>
   </table>
 
-  <table name="_enums">
+  <table name="_enums" descr="List of possible enumeration labels for enumerations">
     <column name="udt_catalog" pkey="TRUE"/>
     <column name="udt_schema" pkey="TRUE"/>
     <column name="udt_name" pkey="TRUE"/>
     <column name="label" pkey="TRUE"/>
+    <column name="ordinal_position" type="gint" descr="Position, starts at 1"/>
     <fkey ref_table="_udt">
       <part column="udt_catalog"/>
       <part column="udt_schema"/>
@@ -110,7 +111,7 @@
     </fkey>
   </table>
 
-  <table name="_element_types">
+  <table name="_element_types" descr="">
     <column name="specific_name" pkey="TRUE"/>
     <column name="object_catalog"/>
     <column name="object_schema"/>
@@ -122,7 +123,7 @@
     <column name="max_cardinality" type="gint"/>
   </table>
 
-  <table name="_domains">
+  <table name="_domains" descr="List of domains">
     <column name="domain_catalog" pkey="TRUE"/>
     <column name="domain_schema" pkey="TRUE"/>
     <column name="domain_name" pkey="TRUE"/>
@@ -177,7 +178,7 @@
     <column name="table_schema" pkey="TRUE"/>
     <column name="table_name" pkey="TRUE"/>
     <column name="view_definition" nullok="TRUE"/>
-    <column name="check_option" nullok="TRUE" note="CASCADE if the statement used to create the view included the WITH CHECK OPTION; otherwise, NONE"/>
+    <column name="check_option" nullok="TRUE" descr="CASCADE if the statement used to create the view included the WITH CHECK OPTION; otherwise, NONE"/>
     <column name="is_updatable" type="boolean" nullok="TRUE"/>
     <fkey ref_table="_tables">
       <part column="table_catalog"/>
@@ -290,10 +291,12 @@
     <column name="table_schema" pkey="TRUE"/>
     <column name="table_name" pkey="TRUE"/>
     <column name="column_name" pkey="TRUE"/>
-    <column name="ordinal_position" type="gint" note="Column position, starts at 1"/>
+    <column name="ordinal_position" type="gint" descr="Column position, starts at 1"/>
     <column name="column_default" nullok="TRUE"/>
     <column name="is_nullable" type="boolean"/>
-    <column name="data_type" note="References a _all_types.full_type_name or _element_types.specific_name"/>
+    <column name="data_type" descr="References _all_types.full_type_name"/>
+    <column name="array_dimension" type="gint"/>
+    <column name="element_type" nullok="TRUE" descr="References _element_types.specific_name, for arrays of @data_type base type"/>
     <column name="gtype"/>
     <column name="character_maximum_length" type="gint" nullok="TRUE"/>
     <column name="character_octet_length" type="gint" nullok="TRUE"/>
@@ -306,7 +309,7 @@
     <column name="collation_catalog" nullok="TRUE"/>
     <column name="collation_schema" nullok="TRUE"/>
     <column name="collation_name" nullok="TRUE"/>
-    <column name="extra" nullok="TRUE" note="CSV string with: AUTO_INCREMENT"/>
+    <column name="extra" nullok="TRUE" descr="CSV string with: AUTO_INCREMENT"/>
     <column name="is_updatable" type="boolean" nullok="TRUE"/>
     <column name="column_comments" nullok="TRUE"/>
     <fkey ref_table="_tables">
@@ -333,7 +336,7 @@
     <column name="table_catalog"/>
     <column name="table_schema"/>
     <column name="table_name"/>
-    <column name="constraint_type"/>
+    <column name="constraint_type" descr="CHECK, FOREIGN KEY, PRIMARY KEY or UNIQUE"/>
     <column name="check_clause" nullok="TRUE"/>
     <column name="is_deferrable" type="boolean" nullok="TRUE"/>
     <column name="initially_deferred" type="boolean" nullok="TRUE"/>

Modified: branches/V4-branch/libgda/libgda.h.in
==============================================================================
--- branches/V4-branch/libgda/libgda.h.in	(original)
+++ branches/V4-branch/libgda/libgda.h.in	Wed Mar  5 17:44:37 2008
@@ -64,6 +64,7 @@
 #include <libgda/handlers/gda-handler-time.h>
 #include <libgda/handlers/gda-handler-type.h>
 #include <libgda/gda-meta-store.h>
+#include <libgda/gda-meta-struct.h>
 
 #include <libgda/gda-statement.h>
 #include <libgda/gda-batch.h>

Modified: branches/V4-branch/libgda/providers-support/gda-pmodel.c
==============================================================================
--- branches/V4-branch/libgda/providers-support/gda-pmodel.c	(original)
+++ branches/V4-branch/libgda/providers-support/gda-pmodel.c	Wed Mar  5 17:44:37 2008
@@ -588,7 +588,7 @@
 	imodel = (GdaPModel *) model;
 	g_return_val_if_fail (imodel->priv, 0);
 	
-	TO_IMPLEMENT;
+	/*FIXME: depending on modification queries being set or not */
 	flags = GDA_VALUE_ATTR_NO_MODIF;
 	
 	return flags;

Modified: branches/V4-branch/libgda/sql-parser/parser.y
==============================================================================
--- branches/V4-branch/libgda/sql-parser/parser.y	(original)
+++ branches/V4-branch/libgda/sql-parser/parser.y	Wed Mar  5 17:44:37 2008
@@ -103,6 +103,8 @@
 	case '<':
 		if (op[1] == '=')
 			return GDA_SQL_OPERATOR_LEQ;
+		else if (op[1] == '>')
+			return GDA_SQL_OPERATOR_DIFF;
 		else if (op[1] == 0)
 			return GDA_SQL_OPERATOR_LT;
 		break;

Modified: branches/V4-branch/libgda/sqlite/gda-sqlite-meta.c
==============================================================================
--- branches/V4-branch/libgda/sqlite/gda-sqlite-meta.c	(original)
+++ branches/V4-branch/libgda/sqlite/gda-sqlite-meta.c	Wed Mar  5 17:44:37 2008
@@ -67,6 +67,7 @@
 static GValue       *view_type_value;
 static GValue       *view_check_option;
 static GValue       *false_value;
+static GValue       *zero_value;
 static GdaSet       *pragma_set;
 
 /*
@@ -100,6 +101,7 @@
 	g_value_set_string ((view_type_value = gda_value_new (G_TYPE_STRING)), "VIEW");
 	g_value_set_string ((view_check_option = gda_value_new (G_TYPE_STRING)), "NONE");
 	g_value_set_boolean ((false_value = gda_value_new (G_TYPE_BOOLEAN)), FALSE);
+	g_value_set_int ((zero_value = gda_value_new (G_TYPE_INT)), 0);
 
 	pragma_set = gda_set_new_inline (1, "tblname", G_TYPE_STRING, "");
 }
@@ -475,7 +477,7 @@
 		}
 		else
 			g_value_set_string ((v6 = gda_value_new (G_TYPE_STRING)), g_type_name (gtype));
-		if (! append_a_row (mod_model, error, 23, 
+		if (! append_a_row (mod_model, error, 25, 
 				    FALSE, catalog_value,
 				    FALSE, p_table_schema,
 				    FALSE, p_table_name,
@@ -484,6 +486,8 @@
 				    FALSE, gda_data_model_get_value_at (tmpmodel, 4, i), /* column default */
 				    TRUE, v3, /* is_nullable */
 				    TRUE, v2, /* data_type */
+				    FALSE, zero_value, /* array_dimension */
+				    FALSE, NULL, /* element_type */
 				    TRUE, v6, /* gtype */
 				    FALSE, NULL, /* character_maximum_length */
 				    FALSE, NULL, /* character_octet_length */
@@ -579,6 +583,40 @@
 	return retval;
 }
 
+gboolean
+_gda_sqlite_meta_constraints_tab (GdaServerProvider *prov, GdaConnection *cnc, 
+				  GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean 
+_gda_sqlite_meta_constraints_tab_s (GdaServerProvider *prov, GdaConnection *cnc, 
+				    GdaMetaStore *store, GdaMetaContext *context, GError **error,
+				    const GValue *table_schema, const GValue *table_name)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_sqlite_meta_constraints_ref (GdaServerProvider *prov, GdaConnection *cnc, 
+				  GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_sqlite_meta_constraints_ref_c (GdaServerProvider *prov, GdaConnection *cnc, 
+				    GdaMetaStore *store, GdaMetaContext *context, GError **error,
+				    const GValue *table_schema, const GValue *table_name)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
 /*
  * @...: a list of TRUE/FALSE, GValue*  -- if TRUE then the following GValue must be freed
  */

Modified: branches/V4-branch/libgda/sqlite/gda-sqlite-meta.h
==============================================================================
--- branches/V4-branch/libgda/sqlite/gda-sqlite-meta.h	(original)
+++ branches/V4-branch/libgda/sqlite/gda-sqlite-meta.h	Wed Mar  5 17:44:37 2008
@@ -26,28 +26,34 @@
 
 G_BEGIN_DECLS
 
-void     _gda_sqlite_provider_meta_init (GdaServerProvider *provider);
-gboolean _gda_sqlite_meta_info          (GdaServerProvider *prov, GdaConnection *cnc, 
-					 GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_sqlite_meta_btypes        (GdaServerProvider *prov, GdaConnection *cnc, 
-					 GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_sqlite_meta_schemata      (GdaServerProvider *prov, GdaConnection *cnc, 
-					 GdaMetaStore *store, GdaMetaContext *context, GError **error, 
-					 const GValue *schema_name);
-gboolean _gda_sqlite_meta_tables_views  (GdaServerProvider *prov, GdaConnection *cnc, 
-					 GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_sqlite_meta_tables_views_s(GdaServerProvider *prov, GdaConnection *cnc, 
-					 GdaMetaStore *store, GdaMetaContext *context, GError **error, 
-					 const GValue *table_schema, const GValue *table_name);
-gboolean _gda_sqlite_meta_columns        (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_sqlite_meta_columns_t      (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error, 
-					  const GValue *table_schema, const GValue *table_name);
-gboolean _gda_sqlite_meta_columns_c      (GdaServerProvider *prov, GdaConnection *cnc, 
-					  GdaMetaStore *store, GdaMetaContext *context, GError **error, 
-					  const GValue *table_schema, const GValue *table_name, const GValue *column_name);
+void     _gda_sqlite_provider_meta_init    (GdaServerProvider *provider);
+gboolean _gda_sqlite_meta_info             (GdaServerProvider *prov, GdaConnection *cnc, 
+					    GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_sqlite_meta_btypes           (GdaServerProvider *prov, GdaConnection *cnc, 
+					    GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_sqlite_meta_schemata         (GdaServerProvider *prov, GdaConnection *cnc, 
+					    GdaMetaStore *store, GdaMetaContext *context, GError **error, 
+					    const GValue *schema_name);
+gboolean _gda_sqlite_meta_tables_views     (GdaServerProvider *prov, GdaConnection *cnc, 
+					    GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_sqlite_meta_tables_views_s   (GdaServerProvider *prov, GdaConnection *cnc, 
+					    GdaMetaStore *store, GdaMetaContext *context, GError **error, 
+					    const GValue *table_schema, const GValue *table_name);
+gboolean _gda_sqlite_meta_columns           (GdaServerProvider *prov, GdaConnection *cnc, 
+					     GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_sqlite_meta_columns_t         (GdaServerProvider *prov, GdaConnection *cnc, 
+					     GdaMetaStore *store, GdaMetaContext *context, GError **error, 
+					     const GValue *table_schema, const GValue *table_name);
+gboolean _gda_sqlite_meta_columns_c         (GdaServerProvider *prov, GdaConnection *cnc, 
+					     GdaMetaStore *store, GdaMetaContext *context, GError **error, 
+					     const GValue *table_schema, const GValue *table_name, const GValue *column_name);
+gboolean _gda_sqlite_meta_constraints_tab   (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **);
+gboolean _gda_sqlite_meta_constraints_tab_s (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **, 
+					     const GValue *table_schema, const GValue *table_name);
 
+gboolean _gda_sqlite_meta_constraints_ref   (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **);
+gboolean _gda_sqlite_meta_constraints_ref_c (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **, 
+					     const GValue *table_schema, const GValue *table_name);
 G_END_DECLS
 
 #endif

Modified: branches/V4-branch/libgda/sqlite/gda-sqlite-provider.c
==============================================================================
--- branches/V4-branch/libgda/sqlite/gda-sqlite-provider.c	(original)
+++ branches/V4-branch/libgda/sqlite/gda-sqlite-provider.c	Wed Mar  5 17:44:37 2008
@@ -235,6 +235,10 @@
 	provider_class->meta_funcs.columns = _gda_sqlite_meta_columns;
 	provider_class->meta_funcs.columns_t = _gda_sqlite_meta_columns_t;
 	provider_class->meta_funcs.columns_c = _gda_sqlite_meta_columns_c;
+	provider_class->meta_funcs.constraints_tab = _gda_sqlite_meta_constraints_tab;
+	provider_class->meta_funcs.constraints_tab_s = _gda_sqlite_meta_constraints_tab_s;
+	provider_class->meta_funcs.constraints_ref = _gda_sqlite_meta_constraints_ref;
+	provider_class->meta_funcs.constraints_ref_c = _gda_sqlite_meta_constraints_ref_c;
 }
 
 static void
@@ -1461,7 +1465,6 @@
 		goto out_err;
 
 	/* prepare statement */
-	g_print ("PREP1%s\n", sql);
 	status = sqlite3_prepare_v2 (cdata->connection, sql, -1, &sqlite_stmt, &left);
 	if (status != SQLITE_OK) {
 		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_PREPARE_STMT_ERROR,
@@ -1569,7 +1572,6 @@
 			if (!sql)
 				return NULL;
 
-			g_print ("PREP2%s\n", sql);
 			status = sqlite3_prepare_v2 (cdata->connection, sql, -1, &sqlite_stmt, (const char**) &left);
 			if (status != SQLITE_OK) {
 				g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_PREPARE_STMT_ERROR,
@@ -1659,7 +1661,7 @@
 			sqlite3_bind_null (ps->sqlite_stmt, i);
 		else if (G_VALUE_TYPE (value) == G_TYPE_STRING)
 			sqlite3_bind_text (ps->sqlite_stmt, i, 
-					   g_value_get_string (value), -1, SQLITE_STATIC);
+					   g_value_get_string (value), -1, SQLITE_TRANSIENT);
 		else if (G_VALUE_TYPE (value) == G_TYPE_INT)
 			sqlite3_bind_int (ps->sqlite_stmt, i, g_value_get_int (value));
 		else if (G_VALUE_TYPE (value) == G_TYPE_DOUBLE)
@@ -1685,12 +1687,12 @@
 		else if (G_VALUE_TYPE (value) == GDA_TYPE_BLOB) {
 			GdaBinary *bin = (GdaBinary *) gda_value_get_blob (value);
 			sqlite3_bind_blob (ps->sqlite_stmt, i, 
-					   bin->data, bin->binary_length, SQLITE_STATIC);
+					   bin->data, bin->binary_length, SQLITE_TRANSIENT);
 		}
 		else if (G_VALUE_TYPE (value) == GDA_TYPE_BINARY) {
 			GdaBinary *bin = (GdaBinary *) gda_value_get_binary (value);
 			sqlite3_bind_blob (ps->sqlite_stmt, i, 
-					   bin->data, bin->binary_length, SQLITE_STATIC);
+					   bin->data, bin->binary_length, SQLITE_TRANSIENT);
 		}
 		else if (G_VALUE_TYPE (value) == GDA_TYPE_TIME) {
 			gchar *str;
@@ -1723,7 +1725,7 @@
 			const GdaNumeric *gdan;
 			
 			gdan = gda_value_get_numeric (value);
-			sqlite3_bind_text (ps->sqlite_stmt, i, gdan->number, -1, SQLITE_STATIC);
+			sqlite3_bind_text (ps->sqlite_stmt, i, gdan->number, -1, SQLITE_TRANSIENT);
 		}
 		else {
 			gchar *str;
@@ -1761,7 +1763,7 @@
 			flags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD;
 
                 data_model = (GObject *) gda_sqlite_recordset_new (cnc, ps, flags, col_types);
-		gda_connection_internal_statement_executed (cnc, stmt, NULL);
+		gda_connection_internal_statement_executed (cnc, stmt, params, NULL);
 		return data_model;
         }
 	else {
@@ -1781,7 +1783,7 @@
                                 gda_connection_add_event (cnc, event);
 				g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
 					     GDA_SERVER_PROVIDER_STATEMENT_EXEC_ERROR, errmsg);
-				gda_connection_internal_statement_executed (cnc, stmt, event);
+				gda_connection_internal_statement_executed (cnc, stmt, params, event);
 				return NULL;
                         }
 			else {
@@ -1831,7 +1833,7 @@
                                 g_free (str);
                                 gda_connection_add_event (cnc, event);
                         }
-			gda_connection_internal_statement_executed (cnc, stmt, event);
+			gda_connection_internal_statement_executed (cnc, stmt, params, event);
 			return set;
 		}
 	}

Modified: branches/V4-branch/libgda/sqlite/gda-sqlite-recordset.c
==============================================================================
--- branches/V4-branch/libgda/sqlite/gda-sqlite-recordset.c	(original)
+++ branches/V4-branch/libgda/sqlite/gda-sqlite-recordset.c	Wed Mar  5 17:44:37 2008
@@ -163,8 +163,10 @@
 			}
 		}
 	}
+	/*
 	if (nb_missing > 0)
 		g_print ("Hey!, some columns are still not known for prep stmt %p\n", pmodel->prep_stmt);
+	*/
 	g_free (missing_cols);
 }
 

Modified: branches/V4-branch/providers/postgres/gda-postgres-meta.c
==============================================================================
--- branches/V4-branch/providers/postgres/gda-postgres-meta.c	(original)
+++ branches/V4-branch/providers/postgres/gda-postgres-meta.c	Wed Mar  5 17:44:37 2008
@@ -44,6 +44,14 @@
 	I_STMT_SCHEMATA,
 	I_STMT_TABLES,
 	I_STMT_VIEWS,
+	I_STMT_TABLES_S,
+	I_STMT_VIEWS_S,
+	I_STMT_ALLCOLUMNS,
+	I_STMT_COLUMNS_OF_TABLE,
+	I_STMT_ALL_TABLES_CONSTRAINTS,
+	I_STMT_TABLE_CONSTRAINTS,
+	I_STMT_ALL_REF_CONSTRAINTS,
+	I_STMT_REF_CONSTRAINTS
 } InternalStatementItem;
 
 
@@ -51,11 +59,32 @@
  * predefined statements' SQL
  */
 static gchar *internal_sql[] = {
+	/* I_STMT_CATALOG */
 	"SELECT pg_catalog.current_database()",
+	/* I_STMT_BTYPES */
 	"SELECT t.typname, 'pg_catalog.' || t.typname, 'gchararray', pg_catalog.obj_description(t.oid), NULL, CASE WHEN t.typname ~ '^_' THEN TRUE WHEN typtype = 'p' THEN TRUE WHEN t.typname in ('any', 'anyarray', 'anyelement', 'cid', 'cstring', 'int2vector', 'internal', 'language_handler', 'oidvector', 'opaque', 'record', 'refcursor', 'regclass', 'regoper', 'regoperator', 'regproc', 'regprocedure', 'regtype', 'SET', 'smgr', 'tid', 'trigger', 'unknown', 'void', 'xid', 'oid', 'aclitem') THEN TRUE ELSE FALSE END, CAST (t.oid AS int8) FROM pg_catalog.pg_type t, pg_catalog.pg_user u, pg_catalog.pg_namespace n WHERE t.typowner=u.usesysid AND n.oid = t.typnamespace AND pg_catalog.pg_type_is_visible(t.oid) AND (typtype='b' OR typtype='p')",
+	/* I_STMT_SCHEMATA */
 	"SELECT catalog_name, schema_name, schema_owner, CASE WHEN schema_name ~'^pg_' THEN TRUE WHEN schema_name ='information_schema' THEN TRUE ELSE FALSE END FROM information_schema.schemata",
+	/* I_STMT_TABLES */
 	"SELECT current_database()::information_schema.sql_identifier AS table_catalog, nc.nspname::information_schema.sql_identifier AS table_schema, c.relname::information_schema.sql_identifier AS table_name, CASE WHEN nc.oid = pg_my_temp_schema() THEN 'LOCAL TEMPORARY'::text WHEN c.relkind = 'r' THEN 'BASE TABLE' WHEN c.relkind = 'v' THEN 'VIEW' ELSE NULL::text END::information_schema.character_data AS table_type, CASE WHEN c.relkind = 'r' THEN TRUE ELSE FALSE END, pg_catalog.obj_description(c.oid), CASE WHEN pg_catalog.pg_table_is_visible(c.oid) IS TRUE AND nc.nspname!='pg_catalog' THEN c.relname ELSE coalesce (nc.nspname || '.', '') || c.relname END, coalesce (nc.nspname || '.', '') || c.relname, o.rolname FROM pg_namespace nc, pg_class c, pg_authid o WHERE c.relnamespace = nc.oid AND (c.relkind = ANY (ARRAY['r', 'v'])) AND NOT pg_is_other_temp_schema(nc.oid) AND (pg_has_role(c.relowner, 'USAGE'::text) OR has_table_privilege(c.oid, 'SELECT'::text) OR has_table_privilege(c.oid,
  'INSERT'::text) OR has_table_privilege(c.oid, 'UPDATE'::text) OR has_table_privilege(c.oid, 'DELETE'::text) OR has_table_privilege(c.oid, 'REFERENCES'::text) OR has_table_privilege(c.oid, 'TRIGGER'::text)) AND o.oid=c.relowner",
-	"SELECT current_database()::information_schema.sql_identifier AS table_catalog, nc.nspname::information_schema.sql_identifier AS table_schema, c.relname::information_schema.sql_identifier AS table_name, pg_catalog.pg_get_viewdef(c.oid, TRUE), NULL, CASE WHEN c.relkind = 'r'::\"char\" THEN TRUE ELSE FALSE END FROM pg_namespace nc, pg_class c WHERE c.relnamespace = nc.oid AND c.relkind = 'v' AND NOT pg_is_other_temp_schema(nc.oid) AND (pg_has_role(c.relowner, 'USAGE'::text) OR has_table_privilege(c.oid, 'SELECT'::text) OR has_table_privilege(c.oid, 'INSERT'::text) OR has_table_privilege(c.oid, 'UPDATE'::text) OR has_table_privilege(c.oid, 'DELETE'::text) OR has_table_privilege(c.oid, 'REFERENCES'::text) OR has_table_privilege(c.oid, 'TRIGGER'::text))"
+	/* I_STMT_VIEWS */
+	"SELECT current_database()::information_schema.sql_identifier AS table_catalog, nc.nspname::information_schema.sql_identifier AS table_schema, c.relname::information_schema.sql_identifier AS table_name, pg_catalog.pg_get_viewdef(c.oid, TRUE), NULL, CASE WHEN c.relkind = 'r'::\"char\" THEN TRUE ELSE FALSE END FROM pg_namespace nc, pg_class c WHERE c.relnamespace = nc.oid AND c.relkind = 'v' AND NOT pg_is_other_temp_schema(nc.oid) AND (pg_has_role(c.relowner, 'USAGE'::text) OR has_table_privilege(c.oid, 'SELECT'::text) OR has_table_privilege(c.oid, 'INSERT'::text) OR has_table_privilege(c.oid, 'UPDATE'::text) OR has_table_privilege(c.oid, 'DELETE'::text) OR has_table_privilege(c.oid, 'REFERENCES'::text) OR has_table_privilege(c.oid, 'TRIGGER'::text))",
+	/* I_STMT_TABLES_S */
+	"SELECT current_database()::information_schema.sql_identifier AS table_catalog, nc.nspname::information_schema.sql_identifier AS table_schema, c.relname::information_schema.sql_identifier AS table_name, CASE WHEN nc.oid = pg_my_temp_schema() THEN 'LOCAL TEMPORARY'::text WHEN c.relkind = 'r' THEN 'BASE TABLE' WHEN c.relkind = 'v' THEN 'VIEW' ELSE NULL::text END::information_schema.character_data AS table_type, CASE WHEN c.relkind = 'r' THEN TRUE ELSE FALSE END, pg_catalog.obj_description(c.oid), CASE WHEN pg_catalog.pg_table_is_visible(c.oid) IS TRUE AND nc.nspname!='pg_catalog' THEN c.relname ELSE coalesce (nc.nspname || '.', '') || c.relname END, coalesce (nc.nspname || '.', '') || c.relname, o.rolname FROM pg_namespace nc, pg_class c, pg_authid o WHERE c.relnamespace = nc.oid AND (c.relkind = ANY (ARRAY['r', 'v'])) AND NOT pg_is_other_temp_schema(nc.oid) AND (pg_has_role(c.relowner, 'USAGE'::text) OR has_table_privilege(c.oid, 'SELECT'::text) OR has_table_privilege(c.oid,
  'INSERT'::text) OR has_table_privilege(c.oid, 'UPDATE'::text) OR has_table_privilege(c.oid, 'DELETE'::text) OR has_table_privilege(c.oid, 'REFERENCES'::text) OR has_table_privilege(c.oid, 'TRIGGER'::text)) AND o.oid=c.relowner AND table_schema = ##schema::string",
+	/* I_STMT_VIEWS_S */
+	"SELECT current_database()::information_schema.sql_identifier AS table_catalog, nc.nspname::information_schema.sql_identifier AS table_schema, c.relname::information_schema.sql_identifier AS table_name, pg_catalog.pg_get_viewdef(c.oid, TRUE), NULL, CASE WHEN c.relkind = 'r'::\"char\" THEN TRUE ELSE FALSE END FROM pg_namespace nc, pg_class c WHERE c.relnamespace = nc.oid AND c.relkind = 'v' AND NOT pg_is_other_temp_schema(nc.oid) AND (pg_has_role(c.relowner, 'USAGE'::text) OR has_table_privilege(c.oid, 'SELECT'::text) OR has_table_privilege(c.oid, 'INSERT'::text) OR has_table_privilege(c.oid, 'UPDATE'::text) OR has_table_privilege(c.oid, 'DELETE'::text) OR has_table_privilege(c.oid, 'REFERENCES'::text) OR has_table_privilege(c.oid, 'TRIGGER'::text)) AND table_schema = ##schema::string",
+	/* I_STMT_ALLCOLUMNS */
+	"SELECT current_database(), nc.nspname, c.relname, a.attname, a.attnum, pg_get_expr(ad.adbin, ad.adrelid), CASE WHEN a.attnotnull OR t.typtype = 'd' AND t.typnotnull THEN FALSE ELSE TRUE END, coalesce (nt.nspname || '.', '') || t.typname, CASE WHEN t.typelem <> 0::oid AND t.typlen = -1 THEN 1 ELSE 0 END, CASE WHEN t.typelem <> 0::oid AND t.typlen = -1 THEN 'ARRAY' || 'COL' || current_database() || '.' || nc.nspname || '.' || c.relname || '.' || a.attnum ELSE NULL END, 'gchararray', information_schema._pg_char_max_length(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*)), information_schema._pg_char_octet_length(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*)), information_schema._pg_numeric_precision(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*)), information_schema._pg_numeric_scale(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truety
 pmod(a.*, t.*)), information_schema._pg_datetime_precision(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*)), NULL, NULL, NULL, NULL, NULL, NULL, CASE WHEN pg_get_expr(ad.adbin, ad.adrelid) LIKE 'nextval(%' THEN 'AUTO_INCREMENT' ELSE NULL END, CASE WHEN c.relkind = 'r' THEN TRUE ELSE FALSE END, pg_catalog.col_description(c.oid, a.attnum), CAST (t.oid AS int8) FROM pg_attribute a LEFT JOIN pg_attrdef ad ON a.attrelid = ad.adrelid AND a.attnum = ad.adnum, pg_class c, pg_namespace nc, pg_type t JOIN pg_namespace nt ON t.typnamespace = nt.oid LEFT JOIN (pg_type bt JOIN pg_namespace nbt ON bt.typnamespace = nbt.oid) ON t.typtype = 'd' AND t.typbasetype = bt.oid WHERE a.attrelid = c.oid AND a.atttypid = t.oid AND nc.oid = c.relnamespace AND NOT pg_is_other_temp_schema(nc.oid) AND a.attnum > 0 AND NOT a.attisdropped AND (c.relkind = ANY (ARRAY['r', 'v'])) AND (pg_has_role(c.relowner, 'USAGE'::text) OR has_table_privilege(c.oid, 'SELECT'::text)
  OR has_table_privilege(c.oid, 'INSERT'::text) OR has_table_privilege(c.oid, 'UPDATE'::text) OR has_table_privilege(c.oid, 'REFERENCES'::text))",
+	/* I_STMT_COLUMNS_OF_TABLE */
+	"SELECT current_database(), nc.nspname, c.relname, a.attname, a.attnum, pg_get_expr(ad.adbin, ad.adrelid), CASE WHEN a.attnotnull OR t.typtype = 'd' AND t.typnotnull THEN FALSE ELSE TRUE END, coalesce (nt.nspname || '.', '') || t.typname, CASE WHEN t.typelem <> 0::oid AND t.typlen = -1 THEN 1 ELSE 0 END, CASE WHEN t.typelem <> 0::oid AND t.typlen = -1 THEN 'ARRAY' || 'COL' || current_database() || '.' || nc.nspname || '.' || c.relname || '.' || a.attnum ELSE NULL END, 'gchararray', information_schema._pg_char_max_length(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*)), information_schema._pg_char_octet_length(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*)), information_schema._pg_numeric_precision(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*)), information_schema._pg_numeric_scale(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truety
 pmod(a.*, t.*)), information_schema._pg_datetime_precision(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*)), NULL, NULL, NULL, NULL, NULL, NULL, CASE WHEN pg_get_expr(ad.adbin, ad.adrelid) LIKE 'nextval(%' THEN 'AUTO_INCREMENT' ELSE NULL END, CASE WHEN c.relkind = 'r' THEN TRUE ELSE FALSE END, pg_catalog.col_description(c.oid, a.attnum), CAST (t.oid AS int8) FROM pg_attribute a LEFT JOIN pg_attrdef ad ON a.attrelid = ad.adrelid AND a.attnum = ad.adnum, pg_class c, pg_namespace nc, pg_type t JOIN pg_namespace nt ON t.typnamespace = nt.oid LEFT JOIN (pg_type bt JOIN pg_namespace nbt ON bt.typnamespace = nbt.oid) ON t.typtype = 'd' AND t.typbasetype = bt.oid WHERE nc.nspname = ##schema::string AND c.relname = ##tblname::string AND a.attrelid = c.oid AND a.atttypid = t.oid AND nc.oid = c.relnamespace AND NOT pg_is_other_temp_schema(nc.oid) AND a.attnum > 0 AND NOT a.attisdropped AND (c.relkind = ANY (ARRAY['r', 'v'])) AND (pg_has_role(c.re
 lowner, 'USAGE'::text) OR has_table_privilege(c.oid, 'SELECT'::text) OR has_table_privilege(c.oid, 'INSERT'::text) OR has_table_privilege(c.oid, 'UPDATE'::text) OR has_table_privilege(c.oid, 'REFERENCES'::text))",
+	/* I_STMT_ALL_TABLES_CONSTRAINTS */
+	"SELECT constraint_catalog, constraint_schema, constraint_name, table_catalog, table_schema, table_name, constraint_type, CASE WHEN is_deferrable = 'YES' THEN TRUE ELSE FALSE END, CASE WHEN initially_deferred = 'YES' THEN TRUE ELSE FALSE END FROM information_schema.table_constraints",
+	/* I_STMT_TABLE_CONSTRAINTS */
+	"SELECT constraint_catalog, constraint_schema, constraint_name, table_catalog, table_schema, table_name, constraint_type, CASE WHEN is_deferrable = 'YES' THEN TRUE ELSE FALSE END, CASE WHEN initially_deferred = 'YES' THEN TRUE ELSE FALSE END FROM information_schema.table_constraints WHERE table_schema = ##schema::string AND table_name = ##tblname::string",
+	/* I_STMT_ALL_REF_CONSTRAINTS */
+	"SELECT constraint_catalog, constraint_schema, constraint_name, unique_constraint_catalog, unique_constraint_schema, unique_constraint_name, match_option, update_rule, delete_rule FROM information_schema.referential_constraints",
+	/* I_STMT_REF_CONSTRAINTS */
+	"SELECT constraint_catalog, constraint_schema, constraint_name, unique_constraint_catalog, unique_constraint_schema, unique_constraint_name, match_option, update_rule, delete_rule FROM information_schema.referential_constraints WHERE constraint_schema = ##schema::string AND constraint_name = ##constname::string"
 };
 
 /*
@@ -68,7 +97,7 @@
  * global static values
  */
 static GdaSqlParser *internal_parser = NULL;
-/* TO_ADD: other static values */
+static GdaSet       *pragma_set;
 
 
 /*
@@ -96,6 +125,9 @@
         }
 
 	/* initialize static values here */
+	pragma_set = gda_set_new_inline (3, "tblname", G_TYPE_STRING, "",
+					 "schema", G_TYPE_STRING, "",
+					 "constname", G_TYPE_STRING, "");
 }
 
 gboolean
@@ -222,17 +254,32 @@
 				   GdaMetaStore *store, GdaMetaContext *context, GError **error, 
 				   const GValue *table_schema, const GValue *table_name)
 {
-	GdaDataModel *model;
+	GdaDataModel *tables_model, *views_model;
 	gboolean retval = TRUE;
 
-	model = gda_meta_store_create_modify_data_model (store, context->table_name);
-	g_assert (model);
+	gda_holder_set_value (gda_set_get_holder (pragma_set, "schema"), table_schema);
+	tables_model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_TABLES_S], pragma_set, error);
+	if (!tables_model)
+		return FALSE;
+	views_model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_VIEWS_S], pragma_set, error);
+	if (!views_model) {
+		g_object_unref (tables_model);
+		return FALSE;
+	}
+
+	GdaMetaContext c2;
+	c2 = *context; /* copy contents, just because we need to modify @context->table_name */
+	if (retval) {
+		c2.table_name = "_tables";
+		retval = gda_meta_store_modify_with_context (store, &c2, tables_model, error);
+	}
+	if (retval) {
+		c2.table_name = "_views";
+		retval = gda_meta_store_modify_with_context (store, &c2, views_model, error);
+	}
+	g_object_unref (tables_model);
+	g_object_unref (views_model);
 
-	/* fill in @model */
-	TO_IMPLEMENT;
-	if (retval)
-		retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
-	g_object_unref (model);
 
 	return retval;
 }
@@ -241,16 +288,44 @@
 _gda_postgres_meta_columns (GdaServerProvider *prov, GdaConnection *cnc, 
 			    GdaMetaStore *store, GdaMetaContext *context, GError **error)
 {
-	GdaDataModel *model;
+	GdaDataModel *model, *proxy;
 	gboolean retval = TRUE;
+	gint i, nrows;
+	PostgresConnectionData *cdata;
 
-	model = gda_meta_store_create_modify_data_model (store, context->table_name);
-	g_assert (model);
+	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata)
+		return FALSE;
 
-	/* fill in @model */
-	TO_IMPLEMENT;
+	/* use a prepared statement for the "base" model */
+	model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_ALLCOLUMNS], NULL, error);
+	if (!model)
+		return FALSE;
+
+	/* use a proxy to customize @model */
+	proxy = (GdaDataModel*) gda_data_proxy_new (model);
+	gda_data_proxy_set_sample_size ((GdaDataProxy*) proxy, 0);
+	nrows = gda_data_model_get_n_rows (model);
+	for (i = 0; i < nrows; i++) {
+		const GValue *value;
+		GType type;
+		value = gda_data_model_get_value_at (model, 25, i);
+		
+		type = _gda_postgres_type_oid_to_gda (cdata, g_value_get_int64 (value));
+		if (type != G_TYPE_STRING) {
+			GValue *v;
+			g_value_set_string (v = gda_value_new (G_TYPE_STRING), g_type_name (type));
+			retval = gda_data_model_set_value_at (proxy, 10, i, v, error);
+			gda_value_free (v);
+			if (!retval)
+				break;
+		}
+	}
+
+	/* modify meta store with @proxy */
 	if (retval)
-		retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
+		retval = gda_meta_store_modify (store, context->table_name, proxy, NULL, error, NULL);
+	g_object_unref (proxy);
 	g_object_unref (model);
 
 	return retval;
@@ -261,7 +336,54 @@
 			      GdaMetaStore *store, GdaMetaContext *context, GError **error, 
 			      const GValue *table_schema, const GValue *table_name)
 {
-	return _gda_postgres_meta_columns_c (prov, cnc, store, context, error, table_schema, table_name, NULL);
+	GdaDataModel *model, *proxy;
+	gboolean retval = TRUE;
+	gint i, nrows;
+	PostgresConnectionData *cdata;
+	GType col_types[] = {
+		G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, 
+		G_TYPE_INT, G_TYPE_NONE
+	};
+
+	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata)
+		return FALSE;
+
+	/* use a prepared statement for the "base" model */
+	gda_holder_set_value (gda_set_get_holder (pragma_set, "schema"), table_schema);
+	gda_holder_set_value (gda_set_get_holder (pragma_set, "tblname"), table_name);
+	model = gda_connection_statement_execute_select_full (cnc, internal_stmt[I_STMT_COLUMNS_OF_TABLE], pragma_set, 
+							      GDA_STATEMENT_MODEL_RANDOM_ACCESS, col_types, error);
+	if (!model)
+		return FALSE;
+
+	/* use a proxy to customize @model */
+	proxy = (GdaDataModel*) gda_data_proxy_new (model);
+	gda_data_proxy_set_sample_size ((GdaDataProxy*) proxy, 0);
+	nrows = gda_data_model_get_n_rows (model);
+	for (i = 0; i < nrows; i++) {
+		const GValue *value;
+		GType type;
+		value = gda_data_model_get_value_at (model, 25, i);
+		
+		type = _gda_postgres_type_oid_to_gda (cdata, g_value_get_int64 (value));
+		if (type != G_TYPE_STRING) {
+			GValue *v;
+			g_value_set_string (v = gda_value_new (G_TYPE_STRING), g_type_name (type));
+			retval = gda_data_model_set_value_at (proxy, 10, i, v, error);
+			gda_value_free (v);
+			if (!retval)
+				break;
+		}
+	}
+
+	/* modify meta store with @proxy */
+	if (retval)
+		retval = gda_meta_store_modify (store, context->table_name, proxy, NULL, error, NULL);
+	g_object_unref (proxy);
+	g_object_unref (model);
+
+	return retval;
 }
 
 gboolean
@@ -283,3 +405,118 @@
 
 	return retval;
 }
+
+gboolean
+_gda_postgres_meta_constraints_tab (GdaServerProvider *prov, GdaConnection *cnc, 
+				    GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	GdaDataModel *model;
+	gboolean retval = TRUE;
+	PostgresConnectionData *cdata;
+
+	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata)
+		return FALSE;
+
+	/* use a prepared statement for the "base" model */
+	model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_ALL_TABLES_CONSTRAINTS], NULL, 
+							 error);
+	if (!model)
+		return FALSE;
+
+
+	/* modify meta store with @proxy */
+	if (retval)
+		retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
+	g_object_unref (model);
+
+	return retval;
+}
+
+gboolean
+_gda_postgres_meta_constraints_tab_s (GdaServerProvider *prov, GdaConnection *cnc, 
+				      GdaMetaStore *store, GdaMetaContext *context, GError **error,
+				      const GValue *table_schema, const GValue *table_name)
+{
+	GdaDataModel *model;
+	gboolean retval = TRUE;
+	PostgresConnectionData *cdata;
+
+	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata)
+		return FALSE;
+
+	/* use a prepared statement for the "base" model */
+	gda_holder_set_value (gda_set_get_holder (pragma_set, "schema"), table_schema);
+	gda_holder_set_value (gda_set_get_holder (pragma_set, "tblname"), table_name);
+	model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_TABLE_CONSTRAINTS], pragma_set, 
+							 error);
+	if (!model)
+		return FALSE;
+
+
+	/* modify meta store with @proxy */
+	if (retval)
+		retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
+	g_object_unref (model);
+
+	return retval;
+}
+
+gboolean
+_gda_postgres_meta_constraints_ref (GdaServerProvider *prov, GdaConnection *cnc, 
+				    GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	GdaDataModel *model;
+	gboolean retval = TRUE;
+	PostgresConnectionData *cdata;
+
+	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata)
+		return FALSE;
+
+	/* use a prepared statement for the "base" model */
+	model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_ALL_REF_CONSTRAINTS], NULL, 
+							 error);
+	if (!model)
+		return FALSE;
+
+
+	/* modify meta store with @proxy */
+	if (retval)
+		retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
+	g_object_unref (model);
+
+	return retval;
+}
+
+gboolean
+_gda_postgres_meta_constraints_ref_c (GdaServerProvider *prov, GdaConnection *cnc, 
+				      GdaMetaStore *store, GdaMetaContext *context, GError **error,
+				      const GValue *constraint_schema, const GValue *constraint_name)
+{
+	GdaDataModel *model;
+	gboolean retval = TRUE;
+	PostgresConnectionData *cdata;
+
+	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata)
+		return FALSE;
+
+	/* use a prepared statement for the "base" model */
+	gda_holder_set_value (gda_set_get_holder (pragma_set, "schema"), constraint_schema);
+	gda_holder_set_value (gda_set_get_holder (pragma_set, "constname"), constraint_name);
+	model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_REF_CONSTRAINTS], pragma_set, 
+							 error);
+	if (!model)
+		return FALSE;
+
+
+	/* modify meta store with @proxy */
+	if (retval)
+		retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
+	g_object_unref (model);
+
+	return retval;
+}
+

Modified: branches/V4-branch/providers/postgres/gda-postgres-meta.h
==============================================================================
--- branches/V4-branch/providers/postgres/gda-postgres-meta.h	(original)
+++ branches/V4-branch/providers/postgres/gda-postgres-meta.h	Wed Mar  5 17:44:37 2008
@@ -26,29 +26,35 @@
 
 G_BEGIN_DECLS
 
-void     _gda_postgres_provider_meta_init (GdaServerProvider *provider);
-gboolean _gda_postgres_meta_info          (GdaServerProvider *prov, GdaConnection *cnc, 
-				       GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_postgres_meta_btypes        (GdaServerProvider *prov, GdaConnection *cnc, 
-				       GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_postgres_meta_schemata      (GdaServerProvider *prov, GdaConnection *cnc, 
-				       GdaMetaStore *store, GdaMetaContext *context, GError **error, 
-				       const GValue *schema_name);
-gboolean _gda_postgres_meta_tables_views  (GdaServerProvider *prov, GdaConnection *cnc, 
-				       GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_postgres_meta_tables_views_s(GdaServerProvider *prov, GdaConnection *cnc, 
-				       GdaMetaStore *store, GdaMetaContext *context, GError **error, 
-				       const GValue *table_schema, const GValue *table_name);
-gboolean _gda_postgres_meta_columns        (GdaServerProvider *prov, GdaConnection *cnc, 
-					GdaMetaStore *store, GdaMetaContext *context, GError **error);
-gboolean _gda_postgres_meta_columns_t      (GdaServerProvider *prov, GdaConnection *cnc, 
-					GdaMetaStore *store, GdaMetaContext *context, GError **error, 
-					const GValue *table_schema, const GValue *table_name);
-gboolean _gda_postgres_meta_columns_c      (GdaServerProvider *prov, GdaConnection *cnc, 
-					GdaMetaStore *store, GdaMetaContext *context, GError **error, 
-					const GValue *table_schema, const GValue *table_name, const GValue *column_name);
+void     _gda_postgres_provider_meta_init    (GdaServerProvider *provider);
+gboolean _gda_postgres_meta_info             (GdaServerProvider *prov, GdaConnection *cnc, 
+					      GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_postgres_meta_btypes           (GdaServerProvider *prov, GdaConnection *cnc, 
+					      GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_postgres_meta_schemata         (GdaServerProvider *prov, GdaConnection *cnc, 
+					      GdaMetaStore *store, GdaMetaContext *context, GError **error, 
+					      const GValue *schema_name);
+gboolean _gda_postgres_meta_tables_views     (GdaServerProvider *prov, GdaConnection *cnc, 
+					      GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_postgres_meta_tables_views_s   (GdaServerProvider *prov, GdaConnection *cnc, 
+					      GdaMetaStore *store, GdaMetaContext *context, GError **error, 
+					      const GValue *table_schema, const GValue *table_name);
+gboolean _gda_postgres_meta_columns           (GdaServerProvider *prov, GdaConnection *cnc, 
+					       GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_postgres_meta_columns_t         (GdaServerProvider *prov, GdaConnection *cnc, 
+					       GdaMetaStore *store, GdaMetaContext *context, GError **error, 
+					       const GValue *table_schema, const GValue *table_name);
+gboolean _gda_postgres_meta_columns_c         (GdaServerProvider *prov, GdaConnection *cnc, 
+					       GdaMetaStore *store, GdaMetaContext *context, GError **error, 
+					       const GValue *table_schema, const GValue *table_name, const GValue *column_name);
+gboolean _gda_postgres_meta_constraints_tab   (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **);
+gboolean _gda_postgres_meta_constraints_tab_s (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **, 
+					       const GValue *table_schema, const GValue *table_name);
+
+gboolean _gda_postgres_meta_constraints_ref   (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **);
+gboolean _gda_postgres_meta_constraints_ref_c (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **, 
+					       const GValue *table_schema, const GValue *table_name);
 
-/* TO_ADD: more functions as defined in GdaServerProviderMeta */
 
 G_END_DECLS
 

Modified: branches/V4-branch/providers/postgres/gda-postgres-provider.c
==============================================================================
--- branches/V4-branch/providers/postgres/gda-postgres-provider.c	(original)
+++ branches/V4-branch/providers/postgres/gda-postgres-provider.c	Wed Mar  5 17:44:37 2008
@@ -193,6 +193,10 @@
 	provider_class->meta_funcs.columns = _gda_postgres_meta_columns;
 	provider_class->meta_funcs.columns_t = _gda_postgres_meta_columns_t;
 	provider_class->meta_funcs.columns_c = _gda_postgres_meta_columns_c;
+	provider_class->meta_funcs.constraints_tab = _gda_postgres_meta_constraints_tab;
+	provider_class->meta_funcs.constraints_tab_s = _gda_postgres_meta_constraints_tab_s;
+	provider_class->meta_funcs.constraints_ref = _gda_postgres_meta_constraints_ref;
+	provider_class->meta_funcs.constraints_ref_c = _gda_postgres_meta_constraints_ref_c;
 }
 
 static void
@@ -1748,7 +1752,7 @@
 		
 		/* create data model in CURSOR mode */
 		recset = gda_postgres_recordset_new_cursor (cnc, ps, cursor_name, col_types);
-		gda_connection_internal_statement_executed (cnc, stmt, NULL); /* required: help @cnc keep some stats */
+		gda_connection_internal_statement_executed (cnc, stmt, params, NULL); /* required: help @cnc keep some stats */
 		return (GObject*) recset;
 	}
 
@@ -1935,7 +1939,7 @@
 			event = _gda_postgres_make_error (cnc, cdata->pconn, NULL, error);
 	}
 
-	gda_connection_internal_statement_executed (cnc, stmt, NULL); /* required: help @cnc keep some stats */
+	gda_connection_internal_statement_executed (cnc, stmt, params, NULL); /* required: help @cnc keep some stats */
 	return retval;
 }
 

Modified: branches/V4-branch/providers/postgres/gda-postgres-recordset.c
==============================================================================
--- branches/V4-branch/providers/postgres/gda-postgres-recordset.c	(original)
+++ branches/V4-branch/providers/postgres/gda-postgres-recordset.c	Wed Mar  5 17:44:37 2008
@@ -294,7 +294,11 @@
 			GType gtype;
 			column = GDA_COLUMN (list->data);
 			postgres_type = PQftype (pg_res, i);
-			gtype = _gda_postgres_type_oid_to_gda (cdata, postgres_type);
+			gtype = _GDA_PSTMT (ps)->types [i];
+			if (gtype == 0) {
+				gtype = _gda_postgres_type_oid_to_gda (cdata, postgres_type);
+				_GDA_PSTMT (ps)->types [i] = gtype;
+			}
 			_GDA_PSTMT (ps)->types [i] = gtype;
 			gda_column_set_g_type (column, gtype);
 			gda_column_set_name (column, PQfname (pg_res, i));

Modified: branches/V4-branch/providers/postgres/parser.y
==============================================================================
--- branches/V4-branch/providers/postgres/parser.y	(original)
+++ branches/V4-branch/providers/postgres/parser.y	Wed Mar  5 17:44:37 2008
@@ -103,6 +103,8 @@
 	case '<':
 		if (op[1] == '=')
 			return GDA_SQL_OPERATOR_LEQ;
+		else if (op[1] == '>')
+			return GDA_SQL_OPERATOR_DIFF;
 		else if (op[1] == 0)
 			return GDA_SQL_OPERATOR_LT;
 		break;

Modified: branches/V4-branch/providers/skel-implementation/capi/gda-capi-provider.c
==============================================================================
--- branches/V4-branch/providers/skel-implementation/capi/gda-capi-provider.c	(original)
+++ branches/V4-branch/providers/skel-implementation/capi/gda-capi-provider.c	Wed Mar  5 17:44:37 2008
@@ -988,7 +988,7 @@
 			flags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD;
 
                 data_model = (GObject *) gda_capi_recordset_new (cnc, ps, flags, col_types);
-		gda_connection_internal_statement_executed (cnc, stmt, NULL); /* required: help @cnc keep some stats */
+		gda_connection_internal_statement_executed (cnc, stmt, params, NULL); /* required: help @cnc keep some stats */
 		return data_model;
         }
 	else {
@@ -998,7 +998,7 @@
                 /* Create a #GdaSet containing "IMPACTED_ROWS" */
 		/* Create GdaConnectionEvent notice with the type of command and impacted rows */
 
-		gda_connection_internal_statement_executed (cnc, stmt, event); /* required: help @cnc keep some stats */
+		gda_connection_internal_statement_executed (cnc, stmt, params, event); /* required: help @cnc keep some stats */
 		return (GObject*) set;
 	}
 }

Modified: branches/V4-branch/tools/command-exec.c
==============================================================================
--- branches/V4-branch/tools/command-exec.c	(original)
+++ branches/V4-branch/tools/command-exec.c	Wed Mar  5 17:44:37 2008
@@ -341,7 +341,8 @@
 		const gchar *sql = "SELECT table_schema AS Schema, table_name AS Name, table_type as Type, "
 			"table_owner as Owner, table_comments as Description "
 			"FROM _tables WHERE table_name=##tname::string AND "
-			"table_type LIKE '%TABLE%' AND table_short_name = table_name";
+			"table_type LIKE '%TABLE%' AND table_short_name = table_name "
+			"ORDER BY table_schema, table_name";
 
 		g_value_set_string (v = gda_value_new (G_TYPE_STRING), args[0]);
 		model = gda_meta_store_extract (gda_connection_get_meta_store (cnc), sql, error, "tname", v, NULL);
@@ -350,7 +351,8 @@
 	else {
 		const gchar *sql = "SELECT table_schema AS Schema, table_name AS Name, table_type as Type, "
 			"table_owner as Owner, table_comments as Description "
-			"FROM _tables WHERE table_type LIKE '%TABLE%' AND table_short_name = table_name";
+			"FROM _tables WHERE table_type LIKE '%TABLE%' AND table_short_name = table_name "
+			"ORDER BY table_schema, table_name";
 		model = gda_meta_store_extract (gda_connection_get_meta_store (cnc), sql, error);
 	}
 	if (!model)
@@ -381,7 +383,8 @@
 		const gchar *sql = "SELECT table_schema AS Schema, table_name AS Name, table_type as Type, "
 			"table_owner as Owner, table_comments as Description "
 			"FROM _tables WHERE table_name=##tname::string AND "
-			"table_type = 'VIEW' AND table_short_name = table_name";
+			"table_type = 'VIEW' AND table_short_name = table_name "
+			"ORDER BY table_schema, table_name";
 
 		g_value_set_string (v = gda_value_new (G_TYPE_STRING), args[0]);
 		model = gda_meta_store_extract (gda_connection_get_meta_store (cnc), sql, error, "tname", v, NULL);
@@ -390,7 +393,8 @@
 	else {
 		const gchar *sql = "SELECT table_schema AS Schema, table_name AS Name, table_type as Type, "
 			"table_owner as Owner, table_comments as Description "
-			"FROM _tables WHERE table_type='VIEW' AND table_short_name = table_name";
+			"FROM _tables WHERE table_type='VIEW' AND table_short_name = table_name "
+			"ORDER BY table_schema, table_name";
 		model = gda_meta_store_extract (gda_connection_get_meta_store (cnc), sql, error);
 	}
 	if (!model)
@@ -406,6 +410,46 @@
 }
 
 GdaInternalCommandResult *
+gda_internal_command_list_schemas (GdaConnection *cnc, const gchar **args, GError **error, gpointer data)
+{
+	GdaInternalCommandResult *res;
+	GdaDataModel *model;
+
+	if (!cnc) {
+		g_set_error (error, 0, 0, _("No current connection"));
+		return NULL;
+	}
+
+	if (args[0] && *args[0]) {
+		GValue *v;
+		const gchar *sql = "SELECT schema_name AS Schema, schema_owner AS Owner, "
+			"CASE WHEN schema_internal THEN 'yes' ELSE 'no' END AS Internal "
+			"FROM _schemata WHERE schema_name=##sname::string "
+			"ORDER BY schema_name";
+
+		g_value_set_string (v = gda_value_new (G_TYPE_STRING), args[0]);
+		model = gda_meta_store_extract (gda_connection_get_meta_store (cnc), sql, error, "sname", v, NULL);
+		gda_value_free (v);
+	}
+	else {
+		const gchar *sql = "SELECT schema_name AS Schema, schema_owner AS Owner, "
+			"CASE WHEN schema_internal THEN 'yes' ELSE 'no' END AS Internal "
+			"FROM _schemata ORDER BY schema_name";
+		model = gda_meta_store_extract (gda_connection_get_meta_store (cnc), sql, error);
+	}
+	if (!model)
+		return NULL;
+
+	g_object_set_data (G_OBJECT (model), "name", _("List of schemas"));
+	
+	res = g_new0 (GdaInternalCommandResult, 1);
+	res->type = GDA_INTERNAL_COMMAND_RESULT_DATA_MODEL;
+	res->u.model = model;
+
+	return res;
+}
+
+GdaInternalCommandResult *
 gda_internal_command_list_queries (GdaConnection *cnc, const gchar **args,
 				   GError **error, gpointer data)
 {
@@ -466,283 +510,250 @@
 	return res;
 }
 
-GdaInternalCommandResult *
-gda_internal_command_detail (GdaConnection *cnc, const gchar **args,
-			     GError **error, gpointer data)
+GdaMetaStruct *
+gda_internal_command_build_meta_struct (GdaConnection *cnc, const gchar **args, GError **error)
 {
-	if (!cnc) {
-		g_set_error (error, 0, 0, _("No current connection"));
-		return NULL;
-	}
+	GdaMetaStruct *mstruct;
+	gint index;
+	const gchar *arg;
+	GdaMetaStore *store;
+
+	store = gda_connection_get_meta_store (cnc);
+	mstruct = gda_meta_struct_new ();
 
 	if (!args[0]) {
-		TO_IMPLEMENT;
-		return NULL;
+		/* use all tables or views */
+		GdaDataModel *model;
+		gint i, nrows;
+		const gchar *sql = "SELECT t.table_catalog, t.table_schema, t.table_name, v.table_name FROM _tables as t LEFT JOIN _views as v ON (t.table_catalog=v.table_catalog AND t.table_schema=v.table_schema AND t.table_name=v.table_name) WHERE table_short_name != table_full_name";
+		model = gda_meta_store_extract (store, sql, error, NULL);
+		if (!model)
+			return NULL;
+		nrows = gda_data_model_get_n_rows (model);
+		for (i = 0; i < nrows; i++) {
+			const GValue *detv;
+			detv = gda_data_model_get_value_at (model, 3, i);
+			if (! gda_meta_struct_complement (mstruct, store, 
+							  detv && !gda_value_is_null (detv) && 
+							  g_value_get_string (detv) && *g_value_get_string (detv) ? 
+							  GDA_META_DB_VIEW : GDA_META_DB_TABLE,
+							  gda_data_model_get_value_at (model, 0, i),
+							  gda_data_model_get_value_at (model, 1, i),
+							  gda_data_model_get_value_at (model, 2, i), error)) 
+				goto onerror;
+		}
+		g_object_unref (model);
 	}
 
-	TO_IMPLEMENT;
-#ifdef OLD_CODE
-	GdaDictTable *table;
-	GdaDictDatabase *db = gda_dict_get_database (dict);
-	g_assert (db);
-	table = gda_dict_database_get_table_by_name (db, args[0]);
-	if (table) {
-		GdaInternalCommandResult *global_res, *res;
-
-		global_res = g_new0 (GdaInternalCommandResult, 1);
-		global_res->type = GDA_INTERNAL_COMMAND_RESULT_MULTIPLE;
-		global_res->u.multiple_results = NULL;
-
-		/*
-		 * First part: description of the table
-		 */
-		GdaDataModel *model;
-		GSList *fields, *list;		
-		gchar *str;
-		model = gda_data_model_array_new_with_g_types (4,
-							       G_TYPE_STRING,
-							       G_TYPE_STRING,
-							       G_TYPE_STRING,
-							       G_TYPE_STRING);
-		gda_data_model_set_column_title (model, 0, _("Column"));
-		gda_data_model_set_column_title (model, 1, _("Type"));
-		gda_data_model_set_column_title (model, 2, _("Modifiers"));
-		gda_data_model_set_column_title (model, 3, _("Description"));
-		str = g_strdup_printf (_("Description of table '%s'"), args[0]);
-		gda_object_set_name (GDA_OBJECT (model), str);
-		g_free (str);
-
-		fields = gda_entity_get_fields (GDA_ENTITY (table));
-		for (list = fields; list; list = list->next) {
-			gint row;
-			const gchar *cstr;
-			GString *string;
-			GValue *value;
-			row = gda_data_model_append_row (model, NULL);
-			
-			/* column */
-			cstr = gda_object_get_name (GDA_OBJECT (list->data));
-			value = gda_value_new_from_string (cstr ? cstr : "", G_TYPE_STRING);
-			gda_data_model_set_value_at (model, 0, row, value, NULL);
-			gda_value_free (value);
-
-			/* type */
-			GdaDictType *type;
-			GType gtype;
-			type = gda_entity_field_get_dict_type (GDA_ENTITY_FIELD (list->data));
-			gtype = gda_entity_field_get_g_type (GDA_ENTITY_FIELD (list->data));
-			if (type) {
-				gint len = gda_dict_field_get_length (GDA_DICT_FIELD (list->data));
-				if (len >= 0) {
-				    if (gtype == G_TYPE_STRING)
-					    str = g_strdup_printf ("%s (%d)", gda_dict_type_get_sqlname (type), len);
-				    else if (gtype == GDA_TYPE_NUMERIC) 
-					    str = g_strdup_printf ("%s (%d,%d)", 
-								   gda_dict_type_get_sqlname (type), len,
-								   gda_dict_field_get_scale (GDA_DICT_FIELD (list->data)));
-				    else
-					    str = g_strdup (gda_dict_type_get_sqlname (type)); 
-				} else
-					str = g_strdup (gda_dict_type_get_sqlname (type));
-			}
-			else
-				str = g_strdup_printf ("(%s)", g_type_name (gtype));
-			value = gda_value_new_from_string (str, G_TYPE_STRING);
-			/*g_print ("%s => %s (%s)\n", gda_object_get_name (GDA_OBJECT (list->data)),
-			  str, g_type_name (gtype));*/
-			g_free (str);
-			gda_data_model_set_value_at (model, 1, row, value, NULL);
-			gda_value_free (value);
-
-			/* modifiers */
-			gboolean start = TRUE;
-			string = g_string_new ("");
-#ifdef BE_CORRECT
-			gint attrs = gda_dict_field_get_attributes (GDA_DICT_FIELD (list->data));
-			if (attrs & FIELD_AUTO_INCREMENT) {
-				g_string_append (string, "AUTO INCREMENT");
-				start = FALSE;
+	for (index = 0, arg = args[0]; arg; index++, arg = args[index]) {
+		GValue *v;
+		g_value_set_string (v = gda_value_new (G_TYPE_STRING), arg);
+
+		/* try to find it as a table or view */
+		{
+			GdaDataModel *model;
+			gint i, nrows;
+			gboolean include_deps = FALSE;
+
+			const gchar *sql = "SELECT t.table_catalog, t.table_schema, t.table_name, v.table_name FROM _tables as t LEFT JOIN _views as v ON (t.table_catalog=v.table_catalog AND t.table_schema=v.table_schema AND t.table_name=v.table_name) WHERE table_short_name = ##tname::string";
+
+			if (g_str_has_suffix (arg, "=")) {
+				gchar *str;
+				str = g_strdup (arg);
+				str[strlen (str) - 1] = 0;
+				g_value_take_string (v, str);
+				include_deps = TRUE;
 			}
-#else
-			if (g_object_get_data (G_OBJECT (list->data), "raw_extra_attributes")) {
-				g_string_append (string, 
-						 (gchar *) g_object_get_data (G_OBJECT (list->data), "raw_extra_attributes"));
-				start = FALSE;
+			model = gda_meta_store_extract (store, sql, error, "tname", v, NULL);
+			if (!model)
+				return NULL;
+			nrows = gda_data_model_get_n_rows (model);
+			for (i = 0; i < nrows; i++) {
+				const GValue *detv;
+				detv = gda_data_model_get_value_at (model, 3, i);
+				if (! gda_meta_struct_complement (mstruct, store, 
+								  detv && !gda_value_is_null (detv) && 
+								  g_value_get_string (detv) && *g_value_get_string (detv) ? 
+								  GDA_META_DB_VIEW : GDA_META_DB_TABLE,
+								  gda_data_model_get_value_at (model, 0, i),
+								  gda_data_model_get_value_at (model, 1, i),
+								  gda_data_model_get_value_at (model, 2, i), error)) 
+					goto onerror;
 			}
-#endif
-			if (! gda_dict_field_is_null_allowed (GDA_DICT_FIELD (list->data))) {
-				if (!start) 
-					g_string_append (string, ", ");
-				else
-					start = FALSE;
-				g_string_append (string, "NOT NULL");
+			g_object_unref (model);
+
+			if (include_deps) {
+				GSList *list;
+				for (list = mstruct->db_objects; list; ) {
+					GdaMetaDbObject *dbo = GDA_META_DB_OBJECT (list->data);
+					GValue *v1, *v2, *v3;
+					
+					g_value_set_string ((v1 = gda_value_new (G_TYPE_STRING)), dbo->obj_catalog);
+					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);
+					
+					if (dbo->obj_type == GDA_META_DB_UNKNOWN) {
+						if (! gda_meta_struct_complement (mstruct, store, GDA_META_DB_TABLE,
+										  v1, v2, v3, error)) {
+							gda_value_free (v1);
+							gda_value_free (v2);
+							gda_value_free (v3);
+							goto onerror;
+						}
+						gda_value_free (v1);
+						gda_value_free (v2);
+						gda_value_free (v3);
+						list = mstruct->db_objects;
+					}
+					else
+						list = list->next;	
+				}
 			}
-			const GValue *def_val;
-			def_val = gda_dict_field_get_default_value (GDA_DICT_FIELD (list->data));
-			if (def_val && !gda_value_is_null (def_val)) {
-				if (!start) 
-					g_string_append (string, ", ");
-				else
-					start = FALSE;
-				str = gda_value_stringify (def_val);
-				g_string_append_printf (string, "DEFAULT %s", str);
-				g_free (str);
+		}
+
+		/* see if we have the form <schema_name>.*, to list all the objects in a given schema */
+		if (g_str_has_suffix (arg, ".*") && (*arg != '.')) {
+			gchar *str;
+			GdaDataModel *model;
+			gint i, nrows;
+
+			str = g_strdup (arg);
+			str[strlen (str) - 2] = 0;
+			g_value_take_string (v, str);
+			const gchar *sql = "SELECT t.table_catalog, t.table_schema, t.table_name, v.table_name FROM _tables as t LEFT JOIN _views as v ON (t.table_catalog=v.table_catalog AND t.table_schema=v.table_schema AND t.table_name=v.table_name) WHERE t.table_schema = ##ts::string";
+			model = gda_meta_store_extract (store, sql, error, "ts", v, NULL);
+			if (!model)
+				return NULL;
+			nrows = gda_data_model_get_n_rows (model);
+			for (i = 0; i < nrows; i++) {
+				const GValue *detv;
+				detv = gda_data_model_get_value_at (model, 3, i);
+				if (! gda_meta_struct_complement (mstruct, store, 
+								  detv && !gda_value_is_null (detv) && 
+								  g_value_get_string (detv) && *g_value_get_string (detv) ? 
+								  GDA_META_DB_VIEW : GDA_META_DB_TABLE,
+								  gda_data_model_get_value_at (model, 0, i),
+								  gda_data_model_get_value_at (model, 1, i),
+								  gda_data_model_get_value_at (model, 2, i), error)) 
+					goto onerror;
 			}
-			value = gda_value_new_from_string (string->str, G_TYPE_STRING);
-			gda_data_model_set_value_at (model, 2, row, value, NULL);
-			gda_value_free (value);
-			g_string_free (string, TRUE);
-				
-			/* description */
-			cstr = gda_object_get_description (GDA_OBJECT (list->data));
-			value = gda_value_new_from_string (cstr ? cstr : "", G_TYPE_STRING);
-			gda_data_model_set_value_at (model, 3, row, value, NULL);
-			gda_value_free (value);
+			g_object_unref (model);
 		}
-		g_slist_free (fields);
+	}
+
+	if (!mstruct->db_objects) {
+		g_set_error (error, 0, 0,
+			     _("No object found"));
+		goto onerror;
+	}
+	gda_meta_struct_order_db_objects (mstruct, NULL);
+	return mstruct;
+
+ onerror:
+	gda_meta_struct_free (mstruct);
+	return NULL;
+}
+
+GdaInternalCommandResult *
+gda_internal_command_detail (GdaConnection *cnc, const gchar **args,
+			     GError **error, gpointer data)
+{
+	GdaInternalCommandResult *res;
+	GdaDataModel *model;
+
+	if (!cnc) {
+		g_set_error (error, 0, 0, _("No current connection"));
+		return NULL;
+	}
 
+	if (!args[0] || !*args[0]) {
+		/* displays all tables, views, indexes and sequences which are "directly visible" */
+		const gchar *sql = "SELECT table_schema AS Schema, table_name AS Name, table_type as Type, "
+			"table_owner as Owner FROM _tables WHERE table_short_name = table_name "
+			"ORDER BY table_schema, table_name";
+		/* FIXME: include indexes and sequences when they are present in the information schema */
+		model = gda_meta_store_extract (gda_connection_get_meta_store (cnc), sql, error, NULL);
 		res = g_new0 (GdaInternalCommandResult, 1);
 		res->type = GDA_INTERNAL_COMMAND_RESULT_DATA_MODEL;
 		res->u.model = model;
-		global_res->u.multiple_results = g_slist_append (global_res->u.multiple_results, res);
+		return res;
+	}
 
-		/*
-		 * Second part: description of the constraints
-		 */
-		{
-			GString *string = NULL;
-			GSList *constraints, *list;
+	GdaMetaStruct *mstruct;
+	GSList *dbo_list;
+	mstruct = gda_internal_command_build_meta_struct (cnc, args, error);
+	if (!mstruct)
+		return NULL;
 
-			constraints = gda_dict_table_get_constraints (table);
-			for (list = constraints; list; list = list->next) {
-				GdaDictConstraint *ct = GDA_DICT_CONSTRAINT (list->data);
-				GSList *fields_list, *fl;
-
-				if (gda_dict_constraint_get_constraint_type (ct) == CONSTRAINT_NOT_NULL)
-					continue;
-
-				if (!string)
-					string = g_string_new ("");
-				else
-					g_string_append_c (string, '\n');
-				g_string_append (string, _("Constraint"));
-				if (gda_object_get_name (GDA_OBJECT (ct)))
-					g_string_append_printf (string, " %s:\n", gda_object_get_name (GDA_OBJECT (ct)));
-				else
-					g_string_append (string, ":\n");
-				switch (gda_dict_constraint_get_constraint_type (ct)) {
-				case CONSTRAINT_PRIMARY_KEY:
-					g_string_append (string, " PRIMARY KEY (");
-					fields_list = gda_dict_constraint_pkey_get_fields (ct);
-					for (fl = fields_list; fl; fl = fl->next) {
-						if (fl != fields_list)
-							g_string_append (string, ", ");
-						g_string_append (string, gda_object_get_name (GDA_OBJECT (fl->data)));
-					}
-					g_string_append_c (string, ')');
-					g_slist_free (fields_list);
-					break;
-				case CONSTRAINT_FOREIGN_KEY: {
-					GdaDictTable *ref_table;
-					ref_table = gda_dict_constraint_fkey_get_ref_table (ct);
-					g_string_append (string, " FOREIGN KEY (");
-					fields_list = gda_dict_constraint_fkey_get_fields (ct);
-					for (fl = fields_list; fl; fl = fl->next) {
-						GdaDictConstraintFkeyPair *pair = (GdaDictConstraintFkeyPair*) fl->data;
-						if (fl != fields_list)
-							g_string_append (string, ", ");
-						g_string_append (string, gda_object_get_name (GDA_OBJECT (pair->fkey)));
-					}
-					g_string_append_c (string, ')');
+	res = g_new0 (GdaInternalCommandResult, 1);
+	res->type = GDA_INTERNAL_COMMAND_RESULT_MULTIPLE;
+	res->u.multiple_results = NULL;
 
-					g_string_append (string, " REFERENCES ");
-					g_string_append_printf (string, "%s (", 
-								gda_object_get_name (GDA_OBJECT (ref_table)));
-					for (fl = fields_list; fl; fl = fl->next) {
-						GdaDictConstraintFkeyPair *pair = (GdaDictConstraintFkeyPair*) fl->data;
-						if (fl != fields_list)
-							g_string_append (string, ", ");
-						g_string_append (string, gda_object_get_name (GDA_OBJECT (pair->ref_pkey)));
-					}
-					g_string_append_c (string, ')');
-					g_slist_free (fields_list);
-					/* FIXME: need the actions */
-					break;
-				}
-				case CONSTRAINT_UNIQUE:
-					g_string_append (string, " UNIQUE (");
-					fields_list = gda_dict_constraint_unique_get_fields (ct);
-					for (fl = fields_list; fl; fl = fl->next) {
-						if (fl != fields_list)
-							g_string_append (string, ", ");
-						g_string_append (string, gda_object_get_name (GDA_OBJECT (fl->data)));
-					}
-					g_string_append_c (string, ')');
-					g_slist_free (fields_list);
-					break;
-				case CONSTRAINT_NOT_NULL: 
-					/* Dont' display anything here */
-					break;
-				case CONSTRAINT_CHECK_EXPR:
-					break;
-				case CONSTRAINT_CHECK_IN_LIST:
-					break;
-				case CONSTRAINT_CHECK_SETOF_LIST:
-					break;
-				default:
-					break;
-				}
+	for (dbo_list = mstruct->db_objects; dbo_list; dbo_list = dbo_list->next) {
+		GdaMetaDbObject *dbo = GDA_META_DB_OBJECT (dbo_list->data);
+		GdaInternalCommandResult *subres;
+
+		switch (dbo->obj_type) {
+		case GDA_META_DB_UNKNOWN:
+			break;
+		case GDA_META_DB_VIEW: 
+		case GDA_META_DB_TABLE: {
+			GdaMetaTable *mt = GDA_META_DB_OBJECT_GET_TABLE (dbo);
+			GSList *list;
+
+			model = gda_data_model_array_new (4);
+			gda_data_model_set_column_title (model, 0, _("Column"));
+			gda_data_model_set_column_title (model, 1, _("Type"));
+			gda_data_model_set_column_title (model, 2, _("Nullable"));
+			gda_data_model_set_column_title (model, 3, _("Default"));
+			if (dbo->obj_type == GDA_META_DB_VIEW)
+				g_object_set_data_full (G_OBJECT (model), "name", 
+							g_strdup_printf (_("List of columns for view '%s'"), 
+									 dbo->obj_short_name), 	g_free);
+			else
+				g_object_set_data_full (G_OBJECT (model), "name", 
+							g_strdup_printf (_("List of columns for table '%s'"), 
+									 dbo->obj_short_name), g_free);
+			for (list = mt->columns; list; list = list->next) {
+				GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data);
+				GList *values = NULL;
+				GValue *val;
+
+				g_value_set_string ((val = gda_value_new (G_TYPE_STRING)), tcol->column_name);
+				values = g_list_append (values, val);
+				g_value_set_string ((val = gda_value_new (G_TYPE_STRING)), tcol->column_type);
+				values = g_list_append (values, val);
+				g_value_set_string ((val = gda_value_new (G_TYPE_STRING)), tcol->nullok ? _("yes") : _("no"));
+				values = g_list_append (values, val);
+				g_value_set_string ((val = gda_value_new (G_TYPE_STRING)), tcol->default_value);
+				values = g_list_append (values, val);
+				gda_data_model_append_values (model, values, NULL);
+				g_list_foreach (values, (GFunc) gda_value_free, NULL);
+				g_list_free (values);
 			}
-			g_slist_free (constraints);
 
-			if (!string && ! gda_dict_table_is_view (table))
-				string = g_string_new (_("No constraint for this table."));
-			if (string) {
-				res = g_new0 (GdaInternalCommandResult, 1);
-				res->type = GDA_INTERNAL_COMMAND_RESULT_TXT;
-				res->u.txt = string;
-				global_res->u.multiple_results = g_slist_append (global_res->u.multiple_results, res);
-			}
-		}
+			subres = g_new0 (GdaInternalCommandResult, 1);
+			subres->type = GDA_INTERNAL_COMMAND_RESULT_DATA_MODEL;
+			subres->u.model = model;
+			res->u.multiple_results = g_slist_append (res->u.multiple_results, subres);
 
-		/*
-		 * 3rd part: SQL definition
-		 */
-		{
-			GString *string = NULL;
-			if (gda_dict_table_is_view (table)) {
-				GdaDataModel *schema;
-				GdaParameterList *plist;
-				plist = gda_parameter_list_new_inline (dict, "name", G_TYPE_STRING, 
-								       gda_object_get_name (GDA_OBJECT (table)), NULL);
-				schema = gda_connection_get_schema (cnc, GDA_CONNECTION_SCHEMA_VIEWS, plist, NULL);
-				g_object_unref (plist);
-				if (schema) {
-					const GValue *cvalue;
-					cvalue = gda_data_model_get_value_at (schema, 3, 0);
-					if (cvalue && !gda_value_is_null (cvalue) && 
-					    g_value_get_string (cvalue) && *g_value_get_string (cvalue)) {
-						string = g_string_new (_("View definition:"));
-						g_string_append (string, "\n ");
-						g_string_append (string, g_value_get_string (cvalue));
-					}
-					g_object_unref (schema);
-				}
-			}
-			if (string) {
-				res = g_new0 (GdaInternalCommandResult, 1);
-				res->type = GDA_INTERNAL_COMMAND_RESULT_TXT;
-				res->u.txt = string;
-				global_res->u.multiple_results = g_slist_append (global_res->u.multiple_results, res);
+			if (dbo->obj_type == GDA_META_DB_VIEW) {
+				GdaMetaView *mv = GDA_META_DB_OBJECT_GET_VIEW (dbo);
+				
+				subres = g_new0 (GdaInternalCommandResult, 1);
+				subres->type = GDA_INTERNAL_COMMAND_RESULT_TXT;
+				subres->u.txt = g_string_new ("");
+				g_string_append_printf (subres->u.txt, _("View definition: %s"), mv->view_def);
+				res->u.multiple_results = g_slist_append (res->u.multiple_results, subres);
 			}
+			break;
+		}
+		default:
+			TO_IMPLEMENT;
+			break;
 		}
-		
-
-		return global_res;
 	}
-#endif
 
-	g_set_error (error, 0, 0,
-		     _("No object named '%s' found"), args[0]);
-	return NULL;
+	gda_meta_struct_free (mstruct);
+	return res;
 }

Modified: branches/V4-branch/tools/command-exec.h
==============================================================================
--- branches/V4-branch/tools/command-exec.h	(original)
+++ branches/V4-branch/tools/command-exec.h	Wed Mar  5 17:44:37 2008
@@ -93,9 +93,14 @@
 							    GError **error, gpointer data);
 GdaInternalCommandResult *gda_internal_command_list_views (GdaConnection *cnc, const gchar **args,
 							   GError **error, gpointer data);
+GdaInternalCommandResult *gda_internal_command_list_schemas (GdaConnection *cnc, const gchar **args,
+							     GError **error, gpointer data);
 GdaInternalCommandResult *gda_internal_command_list_queries (GdaConnection *cnc, const gchar **args,
 							     GError **error, gpointer data);
 GdaInternalCommandResult *gda_internal_command_detail (GdaConnection *cnc, const gchar **args,
 						       GError **error, gpointer data);
 
+/* Misc */
+GdaMetaStruct            *gda_internal_command_build_meta_struct (GdaConnection *cnc, const gchar **args, GError **error);
+
 #endif

Modified: branches/V4-branch/tools/gda-sql.c
==============================================================================
--- branches/V4-branch/tools/gda-sql.c	(original)
+++ branches/V4-branch/tools/gda-sql.c	Wed Mar  5 17:44:37 2008
@@ -34,6 +34,7 @@
 #include <unistd.h>
 #include <sys/types.h>
 #include <libgda/gda-quark-list.h>
+#include <libgda/gda-meta-struct.h>
 
 #ifndef G_OS_WIN32
 #include <signal.h>
@@ -244,8 +245,12 @@
 	init_input ();
 	init_history ();
 	for (;;) {
-		gchar *cmde = read_a_line (data);
+		gchar *cmde;
 
+		/* run any pending iterations */
+		while (g_main_context_iteration (NULL, FALSE));
+
+		cmde = read_a_line (data);
 		if (!cmde) {
 			save_history (NULL, NULL);
 			if (!data->output_stream)
@@ -1141,6 +1146,9 @@
 static GdaInternalCommandResult *extra_command_unset (GdaConnection *cnc, const gchar **args,
 						      GError **error, MainData *data);
 
+static GdaInternalCommandResult *extra_command_graph (GdaConnection *cnc, const gchar **args,
+						      GError **error, MainData *data);
+
 static GdaInternalCommandsList *
 build_internal_commands_list (MainData *data)
 {
@@ -1189,8 +1197,18 @@
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Information");
-	c->name = g_strdup_printf (_("%s [NAME]"), "d");
-	c->description = _("Describe table or view");
+	c->name = g_strdup_printf (_("%s [SCHEMA]"), "dn");
+	c->description = _("List all schemas (or named schema)");
+	c->args = NULL;
+	c->command_func = gda_internal_command_list_schemas;
+	c->user_data = NULL;
+	c->arguments_delimiter_func = NULL;
+	commands->commands = g_slist_prepend (commands->commands, c);
+
+	c = g_new0 (GdaInternalCommand, 1);
+	c->group = _("Information");
+	c->name = g_strdup_printf (_("%s [OBJ_NAME|SCHEMA.*]"), "d");
+	c->description = _("Describe object or full list of objects");
 	c->args = NULL;
 	c->command_func = gda_internal_command_detail;
 	c->user_data = NULL;
@@ -1199,6 +1217,16 @@
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Information");
+	c->name = g_strdup_printf (_("%s [TABLE1 [TABLE2...]]"), "graph");
+	c->description = _("Create a graph of all or the listed tables");
+	c->args = NULL;
+	c->command_func = (GdaInternalCommandFunc) extra_command_graph;
+	c->user_data = NULL;
+	c->arguments_delimiter_func = NULL;
+	commands->commands = g_slist_prepend (commands->commands, c);
+
+	c = g_new0 (GdaInternalCommand, 1);
+	c->group = _("Information");
 	c->name = g_strdup_printf (_("%s [QUERY] [+]"), "dq");
 	c->description = _("List all queries (or named query) in dictionary");
 	c->args = NULL;
@@ -1213,7 +1241,7 @@
 	c->name = g_strdup_printf (_("%s [CNC_NAME [DSN [USER [PASSWORD]]]]"), "c");
 	c->description = _("Connect to another defined data source (DSN, see \\dsn_list)");
 	c->args = NULL;
-	c->command_func = (GdaInternalCommandFunc)extra_command_manage_cnc;
+	c->command_func = (GdaInternalCommandFunc) extra_command_manage_cnc;
 	c->user_data = data;
 	c->arguments_delimiter_func = NULL;
 	commands->commands = g_slist_prepend (commands->commands, c);
@@ -2324,6 +2352,183 @@
 	return res;
 }
 
+#define DO_UNLINK(x) g_unlink(x)
+static void
+graph_func_child_died_cb (GPid pid, gint status, gchar *fname)
+{
+	DO_UNLINK (fname);
+	g_free (fname);
+	g_spawn_close_pid (pid);
+}
+
+static gchar *
+create_graph_from_meta_struct (GdaConnection *cnc, GdaMetaStruct *mstruct, GError **error)
+{
+#define FNAME "graph.dot"
+	GString *string;
+	gint i;
+
+	/* prepare the graph */
+	string = g_string_new ("digraph G {\nrankdir = BT;\nnode [shape = plaintext];\n");
+	GSList *dbo_list;
+	for (dbo_list = mstruct->db_objects; dbo_list; dbo_list = dbo_list->next) {
+		gchar *objname, *fullname;
+		GdaMetaDbObject *dbo = GDA_META_DB_OBJECT (dbo_list->data);
+		GSList *list;
+
+		/* obj human readable name, and full name */
+		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
+			objname = g_strdup_printf ("%s.%s", dbo->obj_schema, dbo->obj_name);
+
+		/* node */
+		switch (dbo->obj_type) {
+		case GDA_META_DB_UNKNOWN:
+			break;
+		case GDA_META_DB_TABLE:
+			g_string_append_printf (string, "\"%s\" [label=<<TABLE BORDER=\"1\" CELLBORDER=\"0\" CELLSPACING=\"0\">", fullname);
+			g_string_append_printf (string, "<TR><TD COLSPAN=\"2\" BGCOLOR=\"grey\" BORDER=\"1\">%s</TD></TR>", objname);
+			break;
+		case GDA_META_DB_VIEW:
+			g_string_append_printf (string, "\"%s\" [label=<<TABLE BORDER=\"1\" CELLBORDER=\"0\" CELLSPACING=\"0\">", fullname);
+			g_string_append_printf (string, "<TR><TD BGCOLOR=\"yellow\" BORDER=\"1\">%s</TD></TR>", objname);
+			break;
+		default:
+			TO_IMPLEMENT;
+			g_string_append_printf (string, "\"%s\" [ shape = note ", fullname);
+			break;
+		}
+
+		/* columns, only for tables */
+		if (dbo->obj_type == GDA_META_DB_TABLE) {
+			GdaMetaTable *mt = GDA_META_DB_OBJECT_GET_TABLE (dbo);
+			for (list = mt->columns; list; list = list->next) {
+				GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data);
+				GString *extra = g_string_new ("");
+				if (tcol->pkey)
+					g_string_append_printf (extra, "key");
+				g_string_append_printf (string, "<TR><TD ALIGN=\"left\">%s</TD><TD ALIGN=\"right\">%s</TD></TR>", 
+							tcol->column_name, extra->str);
+				g_string_free (extra, TRUE);
+			}
+			g_string_append (string, "</TABLE>>];\n");
+			/* foreign keys */
+			for (i = 1, list = mt->fk_list; list; i++, list = list->next) {
+				GdaMetaTableForeignKey *tfk = GDA_META_TABLE_FOREIGN_KEY (list->data);
+				if (tfk->depend_on->obj_type != GDA_META_DB_UNKNOWN) 
+					g_string_append_printf (string, "\"%s\" -> \"%s.%s.%s\" [label=\"(%d)\"];\n", fullname,
+								tfk->depend_on->obj_catalog, tfk->depend_on->obj_schema, 
+								tfk->depend_on->obj_name, i);
+			}
+		}
+		else if (dbo->obj_type == GDA_META_DB_VIEW) {
+			GdaMetaTable *mt = GDA_META_DB_OBJECT_GET_TABLE (dbo);
+			for (list = mt->columns; list; list = list->next) {
+				GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data);
+				g_string_append_printf (string, "<TR><TD ALIGN=\"left\">%s</TD></TR>", tcol->column_name);
+			}
+			g_string_append (string, "</TABLE>>];\n");
+		}
+
+		g_free (objname);
+		g_free (fullname);
+	}
+	g_string_append_c (string, '}');
+
+	/* do something with the graph */
+	gchar *result = NULL;
+	if (g_file_set_contents (FNAME, string->str, -1, error)) {
+		const gchar *viewer;
+		const gchar *format;
+		
+		viewer = g_getenv ("GDA_SQL_VIEWER_PNG");
+		if (viewer)
+			format = "png";
+		else {
+			viewer = g_getenv ("GDA_SQL_VIEWER_PDF");
+			if (viewer)
+				format = "pdf";
+		}
+		if (viewer) {
+			static gint counter = 0;
+			gchar *tmpname, *suffix;
+			gchar *argv[] = {"dot", NULL, "-o",  NULL, FNAME, NULL};
+			guint eventid = 0;
+
+			suffix = g_strdup_printf (".gda_graph_tmp-%d", counter++);
+			tmpname = g_build_filename (g_get_tmp_dir (), suffix, NULL);
+			g_free (suffix);
+			argv[1] = g_strdup_printf ("-T%s", format);
+			argv[3] = tmpname;
+			if (g_spawn_sync (NULL, argv, NULL,
+					  G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, 
+					  NULL, NULL,
+					  NULL, NULL, NULL, NULL)) {
+				gchar *vargv[3];
+				GPid pid;
+				vargv[0] = (gchar *) viewer;
+				vargv[1] = tmpname;
+				vargv[2] = NULL;
+				if (g_spawn_async (NULL, vargv, NULL,
+						   G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL | 
+						   G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_DO_NOT_REAP_CHILD, 
+						   NULL, NULL,
+						   &pid, NULL)) {
+					eventid = g_child_watch_add (pid, (GChildWatchFunc) graph_func_child_died_cb, 
+								     tmpname);
+				}
+			}
+			if (eventid == 0) {
+				DO_UNLINK (tmpname);
+				g_free (tmpname);
+			}
+			g_free (argv[1]);
+			result = g_strdup_printf (_("Graph written to '%s'\n"), FNAME);
+		}
+		else 
+			result = g_strdup_printf (_("Graph written to '%s'\n"
+						    "Use 'dot' (from the GraphViz package) to create a picture, for example:\n"
+						    "\tdot -Tpng -o graph.png %s\n"
+						    "Note: set the GDA_SQL_VIEWER_PNG or GDA_SQL_VIEWER_PDF environment "
+						    "variables to view the graph"), FNAME, FNAME);
+	}
+	g_string_free (string, TRUE);
+	return result;
+}
+
+static GdaInternalCommandResult *
+extra_command_graph (GdaConnection *cnc, const gchar **args,
+		     GError **error, MainData *data)
+{
+	gchar *result;
+	GdaMetaStruct *mstruct;
+
+	if (!cnc) {
+		g_set_error (error, 0, 0, _("No current connection"));
+		return NULL;
+	}
+
+	mstruct = gda_internal_command_build_meta_struct (cnc, args, error);
+	if (!mstruct)
+		return NULL;
+	
+	result = create_graph_from_meta_struct (cnc, mstruct, error);
+	gda_meta_struct_free (mstruct);
+	if (result) {
+		GdaInternalCommandResult *res;
+		res = g_new0 (GdaInternalCommandResult, 1);
+		res->type = GDA_INTERNAL_COMMAND_RESULT_TXT_STDOUT;
+		res->u.txt = g_string_new (result);
+		g_free (result);
+		return res;
+	}
+	else 
+		return NULL;
+}
+
+
 static gchar **
 args_as_string_func (const gchar *str)
 {



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