libgda r3211 - in trunk: . doc/C doc/C/tmpl libgda libgda/sqlite tests/data-models tools



Author: vivien
Date: Thu Sep 18 18:52:53 2008
New Revision: 3211
URL: http://svn.gnome.org/viewvc/libgda?rev=3211&view=rev

Log:
2008-09-18  Vivien Malerba <malerba gnome-db org>

        * libgda/gda-data-model.c: make gda_data_model_dump() work whith data models which
        can only be accessed with a cursor
        * libgda/gda-meta-store.c: handle the 'autoinc' column attribute, and bug fixes
        * libgda/sqlite/gda-sqlite-ddl.c: correctly handle the "INTEGER PRIMARY KEY AUTOINCREMENT"
        * doc/C: better documentation for GdaDataProxy
        * tools/gda-sql.c:
          - allow to pass a file name on the command line to open as an SQLite or MDB file
          - reorganized "query buffer" commands:
            - \e [FILE]: Edit the query buffer (or file) with external editor
            - \g [QUERY_BUFFER_NAME]: Execute contents of query buffer, or named query buffer
            - \qa: List all saved query buffers in dictionary
            - \qd QUERY_BUFFER_NAME: Delete query buffer from dictionary
            - \ql QUERY_BUFFER_NAME: Load query buffer from dictionary
            - \qp: Show the contents of the query buffer
            - \qr [FILE]: Reset the query buffer (fill buffer with contents of file)
            - \qs QUERY_BUFFER_NAME: Save query buffer to dictionary
            - \qw FILE: Write query buffer to file
        * tests/data-models/check_pmodel.c: more testing


Added:
   trunk/doc/C/data_proxy1.dia   (contents, props changed)
   trunk/doc/C/data_proxy1.png   (contents, props changed)
   trunk/doc/C/data_proxy2.dia   (contents, props changed)
   trunk/doc/C/data_proxy2.png   (contents, props changed)
   trunk/doc/C/data_proxy3.dia   (contents, props changed)
   trunk/doc/C/data_proxy3.png   (contents, props changed)
   trunk/doc/C/data_proxy4.dia   (contents, props changed)
   trunk/doc/C/data_proxy4.png   (contents, props changed)
   trunk/doc/C/data_proxy5.dia   (contents, props changed)
   trunk/doc/C/data_proxy5.png   (contents, props changed)
   trunk/doc/C/gda-sql-graph.png   (contents, props changed)
Modified:
   trunk/ChangeLog
   trunk/doc/C/Makefile.am
   trunk/doc/C/gda-sql-manual.xml
   trunk/doc/C/libgda-4.0-docs.sgml
   trunk/doc/C/tmpl/gda-data-proxy.sgml
   trunk/libgda/gda-data-model.c
   trunk/libgda/gda-meta-store.c
   trunk/libgda/sqlite/gda-sqlite-ddl.c
   trunk/tests/data-models/check_pmodel.c
   trunk/tools/gda-sql.c

Modified: trunk/doc/C/Makefile.am
==============================================================================
--- trunk/doc/C/Makefile.am	(original)
+++ trunk/doc/C/Makefile.am	Thu Sep 18 18:52:53 2008
@@ -51,7 +51,9 @@
 	stmt-update.png stmt-compound.png information_schema.png \
 	MetaStore1.png MetaStore2.png i_s_data_types.png \
 	writable_data_model.png GdaDataModelIter.png \
-	data_validation_holder.png data_validation_proxy.png data_validation_set.png
+	data_validation_holder.png data_validation_proxy.png data_validation_set.png \
+	data_proxy1.png data_proxy2.png data_proxy3.png data_proxy4.png data_proxy5.png \
+	gda-sql-graph.png
 
 # Extra options to supply to gtkdoc-fixref
 FIXXREF_OPTIONS=

Added: trunk/doc/C/data_proxy1.dia
==============================================================================
Binary file. No diff available.

Added: trunk/doc/C/data_proxy1.png
==============================================================================
Binary file. No diff available.

Added: trunk/doc/C/data_proxy2.dia
==============================================================================
Binary file. No diff available.

Added: trunk/doc/C/data_proxy2.png
==============================================================================
Binary file. No diff available.

Added: trunk/doc/C/data_proxy3.dia
==============================================================================
Binary file. No diff available.

Added: trunk/doc/C/data_proxy3.png
==============================================================================
Binary file. No diff available.

Added: trunk/doc/C/data_proxy4.dia
==============================================================================
Binary file. No diff available.

Added: trunk/doc/C/data_proxy4.png
==============================================================================
Binary file. No diff available.

Added: trunk/doc/C/data_proxy5.dia
==============================================================================
Binary file. No diff available.

Added: trunk/doc/C/data_proxy5.png
==============================================================================
Binary file. No diff available.

Added: trunk/doc/C/gda-sql-graph.png
==============================================================================
Binary file. No diff available.

Modified: trunk/doc/C/gda-sql-manual.xml
==============================================================================
--- trunk/doc/C/gda-sql-manual.xml	(original)
+++ trunk/doc/C/gda-sql-manual.xml	Thu Sep 18 18:52:53 2008
@@ -96,9 +96,14 @@
       </itemizedlist>
     </para>
     <para>
-      Connections to be opened can be specified on the command line using either defined data 
-      sources (the ones listed using the <option>-l</option> option), or using connection strings
-      which have the following format: "[&lt;provider&gt;://][&lt;username&gt;[:&lt;password&gt;] ]&lt;connection_params&gt;". Note that if provided, &lt;username&gt;, &lt;password&gt; and &lt;provider&gt; must be encoded as per RFC 1738.
+      Connections to be opened can be specified on the command line using either:
+      <itemizedlist>
+	<listitem><para>defined data sources (the ones listed using the <option>-l</option> option)</para></listitem>
+	<listitem><para>connection strings which have the following format: 
+	    "[&lt;provider&gt;://][&lt;username&gt;[:&lt;password&gt;] ]&lt;connection_params&gt;". 
+	    Note that if provided, &lt;username&gt;, &lt;password&gt; and &lt;provider&gt; must be encoded as per RFC 1738</para></listitem>
+	<listitem><para>for SQLite and MS Access files: the file name</para></listitem>
+      </itemizedlist>
     </para>
     <para>
       Connections can also be opened while the tool is running using the <command>.c</command> 
@@ -108,7 +113,8 @@
       Examples:
       <programlisting>
 [prompt]> gda-sql-4.0 Sales
-[prompt]> gda-sql-4.0 Postgresql://username DB_NAME=mydb SQLite://DB_NAME=fspot Sales	
+[prompt]> gda-sql-4.0 Postgresql://username DB_NAME=mydb SQLite://DB_NAME=fspot Sales
+[prompt]> gda-sql-4.0 path/to/dbfile.db
       </programlisting>
     </para>
   </sect1>
@@ -118,15 +124,197 @@
 <chapter id="gda-sql-manual-open">
   <title>Connections management</title>
   <para>
-    Blah.
+    The console tool is able to handle several connections at the same time, they can dynamically be opened and
+    closed during a session. The current connection in use is indicated by the prompt.
+    Use the <command>.c</command> command to open a connection with the connection name (the name by which
+    the connection is identified within the tool) and a connection string; for example:
+    <programlisting>
+gda> .c cnc1 SalesTest
+cnc1>
+    </programlisting>
   </para>
+  <para>
+    The list of connection can be listed using the same <command>.c</command> command without any argument, for example:
+    <programlisting>
+ia32> .c
+          List of opened connections
+Name | Provider | DSN or connection string | Username
+-----+----------+--------------------------+---------
+cnc1 | SQLite   | SalesTest                |         
+ia32 | SQLite   | IA32Instructions         |         
+(2 rows)
 
-  <sect1>
-    <title>Connection string's format</title>
-  </sect1>
+ia32>
+    </programlisting>
+  </para>
+  <para>
+    To switch from one connection to the other, use the <command>.c</command> command with the connection name to use
+    as single argument, for example to switch from using the "ia32" to the "cnc1" connection: 
+    <programlisting>
+ia32> .c cnc1
+cnc1>
+    </programlisting>
+  </para>
 
   <sect1>
     <title>Meta data</title>
+    <para>
+      When a connection is opened for the first time, the tool get all the possible meta data associated to that connection (list of
+      tables, table's columns and their constraints, views, etc). The meta data are refered to when the user wants for example
+      to list a table's attributes, or for command line completion.
+    </para>
+    <para>
+      If some modifications to the database structure have been made (either from the SQL console or from another tool), then
+      the meta data must be updated using the <command>.meta</command> command, which does not output anything unless an error
+      occurred.
+    </para>
+    <para>
+      As the meta data are also stored in a database, the console tool allows one to directly execute SQL commands in the
+      meta data database associated to a connection. The meta data connection associated to a connection is by convention named
+      as the tilde character concatenated with the connection name (for example if the connection is named "cnc1", then the connection
+      to its meta data will be named "~cnc1"). To open a meta data connection, make sure the current connection is the one for which
+      you want to access the meta data, and then use the <command>.c ~</command> command:
+      <programlisting>
+cnc1> .c ~
+Getting database schema information, this may take some time... Done.
+~cnc1> .dt
+                           List of tables
+Schema | Name                             | Type       | Owner | Description
+-------+----------------------------------+------------+-------+------------
+main   | _attributes                      | BASE TABLE |       |            
+main   | _builtin_data_types              | BASE TABLE |       |            
+main   | _character_sets                  | BASE TABLE |       |            
+main   | _check_column_usage              | BASE TABLE |       |            
+main   | _collations                      | BASE TABLE |       |            
+main   | _columns                         | BASE TABLE |       |            
+main   | _domain_constraints              | BASE TABLE |       |            
+main   | _domains                         | BASE TABLE |       |            
+main   | _element_types                   | BASE TABLE |       |            
+main   | _enums                           | BASE TABLE |       |            
+main   | _information_schema_catalog_name | BASE TABLE |       |            
+main   | _key_column_usage                | BASE TABLE |       |            
+main   | _parameters                      | BASE TABLE |       |            
+main   | _referential_constraints         | BASE TABLE |       |            
+main   | _routine_columns                 | BASE TABLE |       |            
+main   | _routines                        | BASE TABLE |       |            
+main   | _schemata                        | BASE TABLE |       |            
+main   | _table_constraints               | BASE TABLE |       |            
+main   | _tables                          | BASE TABLE |       |            
+main   | _triggers                        | BASE TABLE |       |            
+main   | _udt                             | BASE TABLE |       |            
+main   | _udt_columns                     | BASE TABLE |       |            
+main   | _view_column_usage               | BASE TABLE |       |            
+main   | _views                           | BASE TABLE |       |            
+main   | gda_sql_query_buffers            | BASE TABLE |       |            
+(25 rows)
+
+~cnc1> SELECT table_name FROM _tables;
+table_name     
+---------------
+customers      
+locations      
+orders         
+order_contents 
+roles          
+salesrep       
+sales_orga     
+warehouses     
+categories     
+products       
+products_copied
+(11 rows)
+
+~cnc1>
+      </programlisting>
+    </para>
+    
+    <sect2>
+      <title>Information about tables</title>
+      <para>
+	Use the <command>.dt</command> command to list all the tables (or list only one table if the table name is specified as
+	an argument to the command):
+	<programlisting>
+cnc1> .dt
+                  List of tables
+Schema | Name            | Type       | Owner | Description
+-------+-----------------+------------+-------+------------
+main   | categories      | BASE TABLE |       |            
+main   | customers       | BASE TABLE |       |            
+main   | locations       | BASE TABLE |       |            
+main   | order_contents  | BASE TABLE |       |            
+main   | orders          | BASE TABLE |       |            
+main   | products        | BASE TABLE |       |            
+main   | products_copied | BASE TABLE |       |            
+main   | roles           | BASE TABLE |       |            
+main   | sales_orga      | BASE TABLE |       |            
+main   | salesrep        | BASE TABLE |       |            
+main   | warehouses      | BASE TABLE |       |            
+(11 rows)
+
+cnc1> .dt customers
+               List of tables
+Schema | Name      | Type       | Owner | Description
+-------+-----------+------------+-------+------------
+main   | customers | BASE TABLE |       |            
+(1 row)
+
+cnc1>
+	</programlisting>
+      </para>
+      <para>
+	To display the details about a single table, use the <command>.d &lt;table_name&gt;</command> command:
+	<programlisting>
+cnc1> .d customers
+          List of columns for table 'customers'
+Column            | Type    | Nullable | Default | Extra         
+------------------+---------+----------+---------+---------------
+id                | integer | no       |         | Auto increment
+name              | string  | no       | ''      |               
+default_served_by | integer | yes      |         |               
+country           | string  | yes      |         |               
+city              | string  | yes      |         |               
+(5 rows)
+
+Primary key 'primary_key' (id)
+Foreign key 'fk_locations' (country, city) references  main.locations (country, city)
+Foreign key 'fk_salesrep' (default_served_by) references  main.salesrep (default_served_by)
+cnc1>
+	</programlisting>
+      </para>
+
+      <para>
+	Finally, the <command>.graph [TABLE1 [TABLE2...]]</command> will create a graph of all the tables (or
+	only the tables mentionned as arguments). The graph creates a <application>GraphViz</application> file
+	named "graph.dot" which can then be processed with the GraphViz'<command>dot</command> command to
+	produce an image or a PDF file for example.
+      </para>
+      <para>
+	If the <envar>GDA_SQL_VIEWER_PNG</envar> or <envar>GDA_SQL_VIEWER_PDF</envar> environment variables are set
+	(for example to <application>eog</application> or <application>evince</application>) and if the <command>dot</command> command
+	is installed, then the console tool will perform the transformation and display the graph (if under a graphical session).
+	The following figure shows an example of graph:
+	<mediaobject>
+          <imageobject role="html">
+            <imagedata fileref="gda-sql-graph.png" format="PNG" contentwidth="140mm"/>
+          </imageobject>
+          <textobject>
+            <phrase>Sample output from the ".graph" command</phrase>
+          </textobject>
+	</mediaobject>
+      </para>
+    </sect2>
+
+    <sect2>
+      <title>Information about views</title>
+      <para>
+      </para>
+    </sect2>
+
+    <sect2>
+      <title>Information about other objects</title>
+      <para>
+      </para>
+    </sect2>
   </sect1>
 
 </chapter>

Modified: trunk/doc/C/libgda-4.0-docs.sgml
==============================================================================
--- trunk/doc/C/libgda-4.0-docs.sgml	(original)
+++ trunk/doc/C/libgda-4.0-docs.sgml	Thu Sep 18 18:52:53 2008
@@ -584,17 +584,6 @@
       &libgda-GdaDataProxy;
       &libgda-GdaDataComparator;
       &libgda-GdaDataModelQuery;
-      <para>
-	The following UML diagram shows the various implementations of the GdaDataModel interface and their usage:
-	<mediaobject>
-	  <imageobject role="html">
-            <imagedata fileref="DataModels.png" format="PNG"/>
-	  </imageobject>
-	  <textobject>
-            <phrase>Various implementations of the GdaDataModel interface</phrase>
-	  </textobject>
-	</mediaobject>
-      </para>
     </chapter>
 
     <chapter id="data_conv">

Modified: trunk/doc/C/tmpl/gda-data-proxy.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-data-proxy.sgml	(original)
+++ trunk/doc/C/tmpl/gda-data-proxy.sgml	Thu Sep 18 18:52:53 2008
@@ -33,8 +33,75 @@
 	</itemizedlist>
     </para></listitem>
   </itemizedlist>
+  This situation is illustrated in the following schema, where there is a direct mapping between the proxy's
+  rows and the proxied data model's rows:
+  <mediaobject>
+    <imageobject role="html">
+      <imagedata fileref="data_proxy1.png" format="PNG" contentwidth="170mm"/>
+    </imageobject>
+    <textobject>
+      <phrase>GdaDataProxy's values mapping regarding the proxied data model</phrase>
+    </textobject>
+  </mediaobject>
+
   Note that unless explicitely mentionned, the columns are read-only.
 </para>
+<para>
+  The following figures illustrate row mappings bewteen the data proxy and the proxied data model in 
+  several situations (which can be combined, but are shown alone for simplicity):
+  <itemizedlist>
+    <listitem><para>situation where rows 1 and 5 have been marked as deleted from the data proxy, using
+	<link linkend="gda-data-proxy-delete">gda_data_proxy_delete()</link> method, the data
+	proxy has 2 rows less than the proxied data model:
+	<mediaobject>
+	  <imageobject role="html">
+	    <imagedata fileref="data_proxy2.png" format="PNG" contentwidth="100mm"/>
+	  </imageobject>
+	  <textobject>
+	    <phrase>GdaDataProxy with 2 rows marked as deleted</phrase>
+	  </textobject>
+	</mediaobject>
+    </para></listitem>
+
+    <listitem><para>situation where the data proxy only shows a sample of the proxied data model
+	at any given time, using the 
+	<link linkend="gda-data-proxy-set-sample-size">gda_data_proxy_set_sample_size()</link> method
+	(the sample here is 4 rows wide, and starts at row 3):
+	<mediaobject>
+	  <imageobject role="html">
+	    <imagedata fileref="data_proxy3.png" format="PNG" contentwidth="100mm"/>
+	  </imageobject>
+	  <textobject>
+	    <phrase>GdaDataProxy with a sample size of 4</phrase>
+	  </textobject>
+	</mediaobject>
+    </para></listitem>
+
+    <listitem><para>situation where the data proxy shows a row of NULL values, using the
+	<link linkend="GdaDataproxy--prepend-null-entry">"prepend-null-entry"</link> property:
+	<mediaobject>
+	  <imageobject role="html">
+	    <imagedata fileref="data_proxy4.png" format="PNG" contentwidth="100mm"/>
+	  </imageobject>
+	  <textobject>
+	    <phrase>GdaDataProxy with an extra row of NULL values</phrase>
+	  </textobject>
+	</mediaobject>
+    </para></listitem>
+
+    <listitem><para>situation where a row has been added to the data proxy, using for example the
+	<link linkend="gda_data_model_append_row">gda_data_model_append_row()</link> method:
+	<mediaobject>
+	  <imageobject role="html">
+	    <imagedata fileref="data_proxy5.png" format="PNG" contentwidth="100mm"/>
+	  </imageobject>
+	  <textobject>
+	    <phrase>GdaDataProxy where a row has been added</phrase>
+	  </textobject>
+	</mediaobject>
+    </para></listitem>
+  </itemizedlist>
+</para>
 
 <!-- ##### SECTION See_Also ##### -->
 <para>

Modified: trunk/libgda/gda-data-model.c
==============================================================================
--- trunk/libgda/gda-data-model.c	(original)
+++ trunk/libgda/gda-data-model.c	Thu Sep 18 18:52:53 2008
@@ -30,6 +30,7 @@
 #include <libgda/gda-data-model-extra.h>
 #include <libgda/gda-data-model-iter.h>
 #include <libgda/gda-data-model-import.h>
+#include <libgda/gda-data-access-wrapper.h>
 #include <libgda/gda-log.h>
 #include <libgda/gda-util.h>
 #include <libgda/gda-row.h>
@@ -2065,7 +2066,18 @@
 	g_string_append_c (string, '\n');
 
 	/* ... and data */
-	if (allok && gda_data_model_get_access_flags (model) & GDA_DATA_MODEL_ACCESS_RANDOM) {
+	GdaDataModel *ramodel;
+	if (gda_data_model_get_access_flags (model) & GDA_DATA_MODEL_ACCESS_RANDOM)
+		ramodel = g_object_ref (model);
+	else {
+		if (! (gda_data_model_get_access_flags (model) & GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD)) {
+			g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR,
+				     _("Data model does not support backward cursor move, not displaying data"));
+			allok = FALSE;
+		}
+		ramodel = gda_data_access_wrapper_new (model);
+	}
+	if (allok) {
 		for (j = 0; j < n_rows; j++) {
 			/* determine height for each column in that row */
 			gint *cols_height = g_new (gint, n_cols + col_offset);
@@ -2081,7 +2093,7 @@
 
 			for (i = 0; i < n_cols; i++) {
 				if (!dump_attributes) {
-					value = gda_data_model_get_value_at (model, i, j, error);
+					value = gda_data_model_get_value_at (ramodel, i, j, error);
 					if (!value) {
 						allok = FALSE;
 						break;
@@ -2096,7 +2108,7 @@
 				}
 				else {
 					GdaValueAttribute attrs;
-					attrs = gda_data_model_get_attributes_at (model, i, j);
+					attrs = gda_data_model_get_attributes_at (ramodel, i, j);
 					str = g_strdup_printf ("%u", attrs);
 				}
 				if (str) {
@@ -2182,9 +2194,8 @@
 		}
 		g_string_append_printf (string, ngettext("(%d row)\n", "(%d rows)\n", n_rows), n_rows);
 	}
-	else 
-		g_string_append (string, _("Model does not support random access, not showing data\n"));
 
+	g_object_unref (ramodel);
 	g_free (cols_size);
 	g_free (cols_is_num);
 

Modified: trunk/libgda/gda-meta-store.c
==============================================================================
--- trunk/libgda/gda-meta-store.c	(original)
+++ trunk/libgda/gda-meta-store.c	Thu Sep 18 18:52:53 2008
@@ -140,7 +140,8 @@
 	gchar        *column_type;
 	GType         gtype;
 	gboolean      pkey;
-        gboolean      nullok; 
+        gboolean      nullok;
+	gboolean      autoinc;
 } TableColumn;
 static void table_column_free (TableColumn *tcol);
 #define TABLE_COLUMN(x) ((TableColumn*)(x))
@@ -897,7 +898,7 @@
 		if (! gda_server_operation_set_value_at (op, tcol->nullok ? "FALSE" : "TRUE", error,
 							 "/FIELDS_A/@COLUMN_NNUL/%d", index))
 			goto onerror;
-		if (! gda_server_operation_set_value_at (op, "FALSE", error,
+		if (! gda_server_operation_set_value_at (op, tcol->autoinc ? "TRUE" : "FALSE", error,
 							 "/FIELDS_A/@COLUMN_AUTOINC/%d", index))
 			goto onerror;
 		repl = provider_specific_match (specific_hash, prov, "dummy", "/FIELDS_A/@COLUMN_PKEY");
@@ -1279,6 +1280,7 @@
 			xmlChar *cname, *ctype, *xstr;
                         gboolean pkey = FALSE;
                         gboolean nullok = FALSE; 
+			gboolean autoinc = FALSE;
  
                         if (strcmp ((gchar *) cnode->name, "column"))
                                 continue;
@@ -1297,6 +1299,12 @@
                                         nullok = TRUE;
                                 xmlFree (xstr);
                         }
+                        xstr = xmlGetProp (cnode, BAD_CAST "autoinc");
+                        if (xstr) {
+                                if ((*xstr == 't') || (*xstr == 'T'))
+                                        autoinc = TRUE;
+                                xmlFree (xstr);
+                        }
                         ctype = xmlGetProp (cnode, BAD_CAST "type");
                         
                         /* a field */
@@ -1381,13 +1389,40 @@
                         TABLE_INFO (dbobj)->type_cols_array [colindex+1] = G_TYPE_NONE;
 
 			/* TableColumn */
-			TableColumn *tcol = g_new0 (TableColumn, 1);
-			TABLE_INFO (dbobj)->columns = g_slist_append (TABLE_INFO (dbobj)->columns, tcol);
-			tcol->column_name = g_strdup ((gchar *) cname);
-			tcol->column_type = ctype ? g_strdup ((gchar *) ctype) : NULL;
-			tcol->gtype = ptype;
-			tcol->pkey = pkey;
-			tcol->nullok = nullok;
+			TableColumn *tcol = NULL;
+			GSList *tlist;
+			for (tlist = TABLE_INFO (dbobj)->columns; tlist; tlist = tlist->next) {
+				if (((TableColumn*) tlist->data)->column_name && 
+				    !strcmp (((TableColumn*) tlist->data)->column_name, cname)) {
+					tcol = (TableColumn*) tlist->data;
+					if ((tcol->gtype != ptype) ||
+					    (tcol->pkey != pkey) ||
+					    (tcol->nullok != nullok) ||
+					    (tcol->autoinc != autoinc) ||
+					    (! tcol->column_type && ctype) ||
+					    (tcol->column_type && !ctype) ||
+					    (tcol->column_type && strcmp (tcol->column_type, (gchar *) ctype))) {
+						g_set_error (error, 0, 0,
+							     _("Column '%s' already exists and has different characteristics"), 
+							     tcol->column_name);
+						xmlFree (cname);
+						if (ctype)
+							xmlFree (ctype);
+						goto onerror;
+					}
+					break;
+				}
+			}
+			if (!tcol) {
+				tcol = g_new0 (TableColumn, 1);
+				TABLE_INFO (dbobj)->columns = g_slist_append (TABLE_INFO (dbobj)->columns, tcol);
+				tcol->column_name = g_strdup ((gchar *) cname);
+				tcol->column_type = ctype ? g_strdup ((gchar *) ctype) : NULL;
+				tcol->gtype = ptype;
+				tcol->pkey = pkey;
+				tcol->nullok = nullok;
+				tcol->autoinc = autoinc;
+			}
 
 			/* free mem */
 			xmlFree (cname);
@@ -3107,6 +3142,46 @@
  *      with the GDA_META_STORE_SCHEMA_OBJECT_CONFLICT_ERROR error code</para></listitem>
  * </itemizedlist>
  *
+ * The @xml_description defines the table of view's definition, for example:
+ * <programlisting><![CDATA[<table name="mytable">
+    <column name="id" pkey="TRUE"/>
+    <column name="value"/>
+</table>]]></programlisting>
+ *
+ * The partial DTD for this XML description of the object to add is the following (the top node must be
+ * a &lt;table&gt; or a &lt;view&gt;):
+ * <programlisting><![CDATA[<!ELEMENT table (column*,check*,fkey*,unique*)>
+<!ATTLIST table
+          name NMTOKEN #REQUIRED>
+
+<!ELEMENT column EMPTY>
+<!ATTLIST column
+          name NMTOKEN #REQUIRED
+          type CDATA #IMPLIED
+          pkey (TRUE|FALSE) #IMPLIED
+          autoinc (TRUE|FALSE) #IMPLIED
+          nullok (TRUE|FALSE) #IMPLIED>
+
+<!ELEMENT check (#PCDATA)>
+
+<!ELEMENT fkey (part+)>
+<!ATTLIST fkey
+          ref_table NMTOKEN #REQUIRED>
+
+<!ELEMENT part EMPTY>
+<!ATTLIST part
+          column NMTOKEN #IMPLIED
+          ref_column NMTOKEN #IMPLIED>
+
+<!ELEMENT unique (column*)>
+
+<!ELEMENT view (definition)>
+<!ATTLIST view
+          name NMTOKEN #REQUIRED
+          descr CDATA #IMPLIED>
+
+<!ELEMENT definition (#PCDATA)>]]></programlisting>
+ *
  * Returns: TRUE if the new object has sucessfully been added
  */
 gboolean
@@ -3121,7 +3196,7 @@
 	GdaMetaStruct *mstruct = NULL;
 	GError *lerror = NULL;
 
-	GSList *pre_p_db_objects;
+	GSList *pre_p_db_objects = NULL;
 
 	g_return_val_if_fail (GDA_IS_META_STORE (store), FALSE);
 	g_return_val_if_fail (xml_description && *xml_description, FALSE);
@@ -3154,7 +3229,7 @@
 	/* keep a list of custom DB objects _before_ adding the new one(s) (more than
 	 * one if there are dependencies) */
 	pre_p_db_objects = g_slist_copy (store->priv->p_db_objects);
-
+	
 	/* create DbObject structure from XML description, stored in @store's custom db objects */
 	if (!strcmp ((gchar *) node->name, "table")) 
 		dbo = create_table_object (klass, store, node, error);
@@ -3167,7 +3242,7 @@
 	doc = NULL;
 
 	/* check for an already existing database object with the same name */
-	g_print ("Obj name: %s\n", dbo->obj_name);
+	/*g_print ("Obj name: %s\n", dbo->obj_name);*/
 
 	/* make sure the private connection's meta store is up to date about the requested object */
 	switch (dbo->obj_type) {
@@ -3212,7 +3287,7 @@
 	if (eobj) {
 		gboolean conflict = FALSE;
 
-		g_print ("Check Existing object's conformance...\n");
+		/*g_print ("Check Existing object's conformance...\n");*/
 		switch (eobj->obj_type) {
 		case GDA_META_DB_TABLE:
 			if (dbo->obj_type != GDA_SERVER_OPERATION_CREATE_TABLE)
@@ -3258,7 +3333,7 @@
 			goto onerror;
 		
 		/* actually create the object in database */
-		g_print ("Creating object: %s\n", dbo->obj_name);
+		/*g_print ("Creating object: %s\n", dbo->obj_name);*/
 		if (dbo->create_op) {
 			if (!gda_server_provider_perform_operation (prov, store->priv->cnc, dbo->create_op, error))
 				goto onerror;

Modified: trunk/libgda/sqlite/gda-sqlite-ddl.c
==============================================================================
--- trunk/libgda/sqlite/gda-sqlite-ddl.c	(original)
+++ trunk/libgda/sqlite/gda-sqlite-ddl.c	Thu Sep 18 18:52:53 2008
@@ -78,6 +78,7 @@
 		/* manually defined fields */
 		first = TRUE;
 		for (i = 0; i < nrows; i++) {
+			gboolean pkautoinc = FALSE;
 			hasfields = TRUE;
 			if (first) 
 				first = FALSE;
@@ -88,84 +89,101 @@
 			g_string_append (string, g_value_get_string (value));
 			g_string_append_c (string, ' ');
 				
-			value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_TYPE/%d", i);
-			g_string_append (string, g_value_get_string (value));
-				
-			value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_SIZE/%d", i);
-			if (value && G_VALUE_HOLDS (value, G_TYPE_UINT)) {
-				g_string_append_printf (string, "(%d", g_value_get_uint (value));
-
-				value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_SCALE/%d", i);
-				if (value && G_VALUE_HOLDS (value, G_TYPE_UINT))
-					g_string_append_printf (string, ",%d)", g_value_get_uint (value));
-				else
-					g_string_append (string, ")");
+			if (nbpkfields == 1) {
+				value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_AUTOINC/%d", i);
+				if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) {
+					const gchar *tmp;
+					value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_TYPE/%d", i);
+					tmp = g_value_get_string (value);
+					if (!g_ascii_strcasecmp (tmp, "gint") ||
+					    !g_ascii_strcasecmp (tmp, "int")) {
+						g_string_append (string, "INTEGER PRIMARY KEY AUTOINCREMENT");
+						pkautoinc = TRUE;
+					}
+				}
 			}
 
-			value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_DEFAULT/%d", i);
-			if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) {
-				const gchar *str = g_value_get_string (value);
-				if (str && *str) {
-					g_string_append (string, " DEFAULT ");
-					g_string_append (string, str);
+			if (!pkautoinc) {
+				value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_TYPE/%d", i);
+				g_string_append (string, g_value_get_string (value));
+				
+				value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_SIZE/%d", i);
+				if (value && G_VALUE_HOLDS (value, G_TYPE_UINT)) {
+					g_string_append_printf (string, "(%d", g_value_get_uint (value));
+					
+					value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_SCALE/%d", i);
+					if (value && G_VALUE_HOLDS (value, G_TYPE_UINT))
+						g_string_append_printf (string, ",%d)", g_value_get_uint (value));
+					else
+						g_string_append (string, ")");
 				}
-			}
 				
-			value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_NNUL/%d", i);
-			if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
-				g_string_append (string, " NOT NULL");
-
-			value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_UNIQUE/%d", i);
-			if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
-				g_string_append (string, " UNIQUE");
+				value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_DEFAULT/%d", i);
+				if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) {
+					const gchar *str = g_value_get_string (value);
+					if (str && *str) {
+						g_string_append (string, " DEFAULT ");
+						g_string_append (string, str);
+					}
+				}
 				
-			if (nbpkfields == 1) {
-				value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_PKEY/%d", i);
-				if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) {
-					g_string_append (string, " PRIMARY KEY");
-					
-					value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_CONFLICT/%d", i);
-					if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) {
-						const gchar *str = g_value_get_string (value);
-						if (str && *str) {
-							g_string_append (string, " ON CONFLICT ");
-							g_string_append (string, str);
-						}
+				value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_NNUL/%d", i);
+				if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
+					g_string_append (string, " NOT NULL");
+				
+				value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_UNIQUE/%d", i);
+				if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
+					g_string_append (string, " UNIQUE");
+
+				if (nbpkfields == 1) {
+					value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_PKEY/%d", i);
+					if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) {
+						g_string_append (string, " PRIMARY KEY");
 						
-					} 
-					value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_AUTOINC/%d", i);
-					if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
-						g_string_append (string, " AUTOINCREMENT");
+						value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_CONFLICT/%d", i);
+						if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) {
+							const gchar *str = g_value_get_string (value);
+							if (str && *str) {
+								g_string_append (string, " ON CONFLICT ");
+								g_string_append (string, str);
+							}
+							
+						} 
+						value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_AUTOINC/%d", i);
+						if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) {
+							g_string_append (string, " AUTOINCREMENT");
+						}
+					}
+					
 				}
-
-			}
-			else {
-				if (!conflict_algo) {
-					value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_CONFLICT/%d", i);
-					if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) {
-						const gchar *str = g_value_get_string (value);
-						if (str && *str) 
-							conflict_algo = g_strdup (str);
-					} 
+				else {
+					if (!conflict_algo) {
+						value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_CONFLICT/%d", i);
+						if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) {
+							const gchar *str = g_value_get_string (value);
+							if (str && *str) 
+								conflict_algo = g_strdup (str);
+						} 
+					}
 				}
-			}
 				
-			value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_CHECK/%d", i);
-			if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) {
-				const gchar *str = g_value_get_string (value);
-				if (str && *str) {
-					g_string_append (string, " CHECK (");
-					g_string_append (string, str);
-					g_string_append_c (string, ')');
+				value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_CHECK/%d", i);
+				if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) {
+					const gchar *str = g_value_get_string (value);
+					if (str && *str) {
+						g_string_append (string, " CHECK (");
+						g_string_append (string, str);
+						g_string_append_c (string, ')');
+					}
 				}
-			}
-
-			value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_COLLATE/%d", i);
-			if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) {
-				const gchar *str = g_value_get_string (value);
-				if (str && *str) {
-					g_string_append (string, " COLLATE ");
-					g_string_append (string, str);
+				
+				value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_COLLATE/%d", i);
+				if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) {
+					const gchar *str = g_value_get_string (value);
+					if (str && *str) {
+						g_string_append (string, " COLLATE ");
+						g_string_append (string, str);
+					}
 				}
 			}
 		}

Modified: trunk/tests/data-models/check_pmodel.c
==============================================================================
--- trunk/tests/data-models/check_pmodel.c	(original)
+++ trunk/tests/data-models/check_pmodel.c	Thu Sep 18 18:52:53 2008
@@ -1243,9 +1243,15 @@
 	clear_signals ();
 
 	/* create GdaDataSelect */
-	stmt = stmt_from_string ("SELECT * FROM customers WHERE id <= ##id::int");
+	stmt = stmt_from_string ("SELECT * FROM customers WHERE id <= ##id::int ORDER BY name");
 	g_assert (gda_statement_get_parameters (stmt, &params, NULL));
-	g_assert (gda_set_set_holder_value (params, &error, "id", "9"));
+	g_assert (gda_set_set_holder_value (params, &error, "id", 9));
+
+	model = gda_connection_statement_execute_select (cnc, stmt, params, &error);
+	g_assert (model);
+	gda_data_model_dump (model, stdout);
+	g_object_unref (model);
+
 	model = gda_connection_statement_execute_select_full (cnc, stmt, params, 
 							      GDA_STATEMENT_MODEL_CURSOR_FORWARD, 
 							      NULL, &error);
@@ -1308,6 +1314,47 @@
 #endif
 		goto out;
 	}
+	gda_value_free (value);
+
+	/**/
+	g_value_set_int ((value = gda_value_new (G_TYPE_INT)), 1);
+	if (! gda_data_model_iter_set_value_at (iter, 0, value, &error)) {
+		nfailed++;
+#ifdef CHECK_EXTRA_INFO
+		g_print ("GdaDataModelIter value set failed: %s\n",
+			 error && error->message ? error->message : "No detail");
+#endif
+		goto out;
+	}
+	if (! check_expected_signal (model, 'U', 1)) {
+		nfailed++;
+		goto out;
+	}
+	cvalue = gda_data_model_iter_get_value_at (iter, 0);
+	if (!cvalue) {
+		nfailed++;
+#ifdef CHECK_EXTRA_INFO
+		g_print ("gda_data_model_iter_get_value_at() failed after modification\n");
+#endif
+		goto out;
+	}
+	if (gda_value_differ (cvalue, value)) {
+		nfailed++;
+#ifdef CHECK_EXTRA_INFO
+		g_print ("gda_data_model_iter_get_value_at() and modified value differ\n");
+#endif
+		goto out;
+	}
+
+	GdaDataModel *rerun;
+	rerun = gda_connection_statement_execute_select (cnc, stmt, params, &error);
+	g_assert (rerun);
+	gda_data_model_dump (rerun, stdout);
+	
+	gda_value_free (value);
+	
+	
+
 	g_object_unref (iter);
 
 

Modified: trunk/tools/gda-sql.c
==============================================================================
--- trunk/tools/gda-sql.c	(original)
+++ trunk/tools/gda-sql.c	Thu Sep 18 18:52:53 2008
@@ -888,22 +888,50 @@
 	GdaConnection *newcnc = NULL;
 	ConnectionSetting *cs = NULL;
 	static gint cncindex = 0;
+	gchar *real_cnc_string;
 
 	if (cnc_name && ! connection_name_is_valid (cnc_name)) {
 		g_set_error (error, 0, 0,
 			     _("Connection name '%s' is invalid"), cnc_name);
 		return NULL;
 	}
-
+	
 	GdaDsnInfo *info;
 	gchar *user, *pass, *real_cnc, *real_provider, *real_auth_string = NULL;
-	gda_connection_string_split (cnc_string, &real_cnc, &real_provider, &user, &pass);
+
+	/* if cnc string is a regular file, then use it with SQLite */
+	if (g_file_test (cnc_string, G_FILE_TEST_IS_REGULAR)) {
+		gchar *path, *file, *e1, *e2;
+		const gchar *pname = "SQLite";
+		
+		path = g_path_get_dirname (cnc_string);
+		file = g_path_get_basename (cnc_string);
+		if (g_str_has_suffix (file, ".mdb")) {
+			pname = "MSAccess";
+			file [strlen (file) - 4] = 0;
+		}
+		else if (g_str_has_suffix (file, ".db"))
+			file [strlen (file) - 3] = 0;
+		e1 = gda_rfc1738_encode (path);
+		e2 = gda_rfc1738_encode (file);
+		g_free (path);
+		g_free (file);
+		real_cnc_string = g_strdup_printf ("%s://DB_DIR=%s;DB_NAME=%s", pname, e1, e2);
+		g_free (e1);
+		g_free (e2);
+		gda_connection_string_split (real_cnc_string, &real_cnc, &real_provider, &user, &pass);
+	}
+	else {
+		gda_connection_string_split (cnc_string, &real_cnc, &real_provider, &user, &pass);
+		real_cnc_string = g_strdup (cnc_string);
+	}
 	if (!real_cnc) {
 		g_free (user);
 		g_free (pass);
 		g_free (real_provider);
 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR, 
 			     _("Malformed connection string '%s'"), cnc_string);
+		g_free (real_cnc_string);
 		return NULL;
 	}
 
@@ -918,6 +946,7 @@
 				g_free (real_provider);
 				g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR, 
 					     _("No username for '%s'"), cnc_string);
+				g_free (real_cnc_string);
 				return NULL;
 			}
 			g_free (user);
@@ -933,6 +962,7 @@
 				g_free (real_provider);
 				g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR, 
 					     _("No password for '%s'"), cnc_string);
+				g_free (real_cnc_string);
 				return NULL;
 			}
 			g_free (pass);
@@ -955,10 +985,11 @@
 	
 	info = gda_config_get_dsn_info (real_cnc);
 	if (info && !real_provider)
-		newcnc = gda_connection_open_from_dsn (cnc_string, real_auth_string, 0, error);
+		newcnc = gda_connection_open_from_dsn (real_cnc_string, real_auth_string, 0, error);
 	else 
-		newcnc = gda_connection_open_from_string (NULL, cnc_string, real_auth_string, 0, error);
+		newcnc = gda_connection_open_from_string (NULL, real_cnc_string, real_auth_string, 0, error);
 	
+	g_free (real_cnc_string);
 	g_free (real_cnc);
 	g_free (user);
 	g_free (pass);
@@ -1324,6 +1355,10 @@
 								     GError **error, MainData *data);
 static GdaInternalCommandResult *extra_command_query_buffer_from_dict (GdaConnection *cnc, const gchar **args,
 								       GError **error, MainData *data);
+static GdaInternalCommandResult *extra_command_query_buffer_list_dict (GdaConnection *cnc, const gchar **args,
+								       GError **error, MainData *data);
+static GdaInternalCommandResult *extra_command_query_buffer_delete_dict (GdaConnection *cnc, const gchar **args,
+									 GError **error, MainData *data);
 
 static GdaInternalCommandResult *extra_command_set (GdaConnection *cnc, const gchar **args,
 						    GError **error, MainData *data);
@@ -1552,7 +1587,7 @@
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Query buffer");
-	c->name = g_strdup_printf (_("%s [FILE]"), "r");
+	c->name = g_strdup_printf (_("%s [FILE]"), "qr");
 	c->description = _("Reset the query buffer (fill buffer with contents of file)");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_reset_buffer;
@@ -1562,7 +1597,7 @@
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Query buffer");
-	c->name = "p";
+	c->name = "qp";
 	c->description = _("Show the contents of the query buffer");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_show_buffer;
@@ -1572,8 +1607,8 @@
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Query buffer");
-	c->name = "g";
-	c->description = _("Execute contents of query buffer");
+	c->name = g_strdup_printf (_("%s [QUERY_BUFFER_NAME]"), "g");
+	c->description = _("Execute contents of query buffer, or named query buffer");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_exec_buffer;
 	c->user_data = data;
@@ -1582,7 +1617,7 @@
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Query buffer");
-	c->name = g_strdup_printf (_("%s FILE"), "w");
+	c->name = g_strdup_printf (_("%s FILE"), "qw");
 	c->description = _("Write query buffer to file");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_write_buffer;
@@ -1592,7 +1627,7 @@
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Query buffer");
-	c->name = g_strdup_printf (_("%s [QUERY_NAME]"), "w_dict");
+	c->name = g_strdup_printf (_("%s QUERY_BUFFER_NAME"), "qs");
 	c->description = _("Save query buffer to dictionary");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_query_buffer_to_dict;
@@ -1602,8 +1637,8 @@
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Query buffer");
-	c->name = g_strdup_printf (_("%s QUERY_NAME"), "r_dict");
-	c->description = _("Set named query from dictionary into query buffer");
+	c->name = g_strdup_printf (_("%s QUERY_BUFFER_NAME"), "ql");
+	c->description = _("Load query buffer from dictionary");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_query_buffer_from_dict;
 	c->user_data = data;
@@ -1612,6 +1647,26 @@
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Query buffer");
+	c->name = g_strdup_printf (_("%s QUERY_BUFFER_NAME"), "qd");
+	c->description = _("Delete query buffer from dictionary");
+	c->args = NULL;
+	c->command_func = (GdaInternalCommandFunc) extra_command_query_buffer_delete_dict;
+	c->user_data = data;
+	c->arguments_delimiter_func = NULL;
+	commands->commands = g_slist_prepend (commands->commands, c);
+
+	c = g_new0 (GdaInternalCommand, 1);
+	c->group = _("Query buffer");
+	c->name = g_strdup_printf (_("%s"), "qa");
+	c->description = _("List all saved query buffers in dictionary");
+	c->args = NULL;
+	c->command_func = (GdaInternalCommandFunc) extra_command_query_buffer_list_dict;
+	c->user_data = data;
+	c->arguments_delimiter_func = NULL;
+	commands->commands = g_slist_prepend (commands->commands, c);
+
+	c = g_new0 (GdaInternalCommand, 1);
+	c->group = _("Query buffer");
 	c->name = g_strdup_printf (_("%s [NAME [VALUE|_null_]]"), "set");
 	c->description = _("Set or show internal parameter, or list all if no parameters");
 	c->args = NULL;
@@ -2374,6 +2429,15 @@
 		return NULL;
 	}
 
+	if (args[0] && *args[0]) {
+		/* load named query buffer first */
+		res = extra_command_query_buffer_from_dict (cnc, args, error, data);
+		if (!res)
+			return NULL;
+		gda_internal_command_exec_result_free (res);
+		res = NULL;
+	}
+
 	if (!data->current->query_buffer) 
 		data->current->query_buffer = g_string_new ("");
 	if (*data->current->query_buffer->str != 0)
@@ -2412,12 +2476,64 @@
 	return res;
 }
 
-static GdaStatement *
-find_statement_in_connection_meta_store (GdaConnection *cnc, const gchar *query_name)
+#define QUERY_BUFFERS_TABLE_NAME "gda_sql_query_buffers"
+#define QUERY_BUFFERS_TABLE_DESC \
+	"<table name=\"" QUERY_BUFFERS_TABLE_NAME "\"> "			    \
+	"   <column name=\"id\" type=\"gint\" pkey=\"TRUE\" autoinc=\"TRUE\"/>"	    \
+	"   <column name=\"name\"/>"				    \
+	"   <column name=\"sql\"/>"				    \
+	"</table>"
+#define QUERY_BUFFERS_TABLE_INSERT \
+	"INSERT INTO " QUERY_BUFFERS_TABLE_NAME " (name, sql) VALUES (##name::string, ##sql::string)"
+#define QUERY_BUFFERS_TABLE_SELECT \
+	"SELECT name, sql FROM " QUERY_BUFFERS_TABLE_NAME " ORDER BY name"
+#define QUERY_BUFFERS_TABLE_SELECT_ONE \
+	"SELECT sql FROM " QUERY_BUFFERS_TABLE_NAME " WHERE name = ##name::string"
+#define QUERY_BUFFERS_TABLE_DELETE \
+	"DELETE FROM " QUERY_BUFFERS_TABLE_NAME " WHERE name = ##name::string"
+
+static GdaInternalCommandResult *
+extra_command_query_buffer_list_dict (GdaConnection *cnc, const gchar **args,
+				      GError **error, MainData *data)
 {
-	GdaStatement *stmt = NULL;
-	TO_IMPLEMENT;
-	return stmt;
+	GdaInternalCommandResult *res = NULL;
+
+	if (!data->current) {
+		g_set_error (error, 0, 0, _("No connection opened"));
+		return NULL;
+	}
+
+	/* Meta store's init */
+	GdaMetaStore *mstore;
+	mstore = gda_connection_get_meta_store (data->current->cnc);
+	if (!gda_meta_store_schema_add_custom_object (mstore, QUERY_BUFFERS_TABLE_DESC, NULL)) {
+		g_set_error (error, 0, 0,
+			     _("Can't initialize dictionary to store query buffers"));
+		return NULL;
+	}
+		
+	/* actual list retreival */
+	static GdaStatement *sel_stmt = NULL;
+	GdaDataModel *model;
+	if (!sel_stmt) {
+		sel_stmt = gda_sql_parser_parse_string (data->current->parser, 
+							QUERY_BUFFERS_TABLE_SELECT, NULL, NULL);
+		g_assert (sel_stmt);
+	}
+
+	GdaConnection *store_cnc;
+	store_cnc = gda_meta_store_get_internal_connection (mstore);
+	model = gda_connection_statement_execute_select (store_cnc, sel_stmt, NULL, error);
+	if (!model)
+		return NULL;
+
+	gda_data_model_set_column_title (model, 0, _("Query buffer name"));
+	gda_data_model_set_column_title (model, 1, _("SQL"));
+	res = g_new0 (GdaInternalCommandResult, 1);
+	res->type = GDA_INTERNAL_COMMAND_RESULT_DATA_MODEL;
+	res->u.model = model;
+
+	return res;
 }
 
 static GdaInternalCommandResult *
@@ -2434,36 +2550,48 @@
 	if (!data->current->query_buffer) 
 		data->current->query_buffer = g_string_new ("");
 	if (*data->current->query_buffer->str != 0) {
-		GdaStatement *stmt;
+		/* find a suitable name */
 		gchar *qname;
-
-		/* check SQL validity */
-		const gchar *remain = NULL;
-		stmt = gda_sql_parser_parse_string (data->current->parser, data->current->query_buffer->str, &remain, error);
-		if (!stmt)
-			return NULL;
-		g_object_unref (stmt);
-		if (remain) {
+		if (args[0] && *args[0]) 
+			qname = g_strdup ((gchar *) args[0]);
+		else {
 			g_set_error (error, 0, 0,
-				     _("Query buffer contains more than one SQL statement"));
+				     _("Missing query buffer name"));
 			return NULL;
 		}
 
-		/* find a suitable name */
-		if (args[0] && *args[0]) 
-			qname = g_strdup ((gchar *) args[0]);
-		else {
-			gint i;
-			for (i = 0; ; i++) {
-				qname = g_strdup_printf ("saved_stmt_%d", i);
-				stmt = find_statement_in_connection_meta_store (data->current->cnc, qname);
-				if (!stmt)
-					break;
-			}
+		/* Meta store's init */
+		GdaMetaStore *mstore;
+		mstore = gda_connection_get_meta_store (data->current->cnc);
+		if (!gda_meta_store_schema_add_custom_object (mstore, QUERY_BUFFERS_TABLE_DESC, NULL)) {
+			g_set_error (error, 0, 0,
+				     _("Can't initialize dictionary to store query buffers"));
+			g_free (qname);
+			return NULL;
+		}
+		
+		/* actual store of the statement */
+		static GdaStatement *ins_stmt = NULL;
+		static GdaSet *ins_params = NULL;
+		if (!ins_stmt) {
+			ins_stmt = gda_sql_parser_parse_string (data->current->parser, 
+								QUERY_BUFFERS_TABLE_INSERT, NULL, NULL);
+			g_assert (ins_stmt);
+			g_assert (gda_statement_get_parameters (ins_stmt, &ins_params, NULL));
 		}
 
-		TO_IMPLEMENT; /* add data->current->query_buffer->str as a new query in data->current->cnc's meta store */
+		if (! gda_set_set_holder_value (ins_params, error, "name", qname) ||
+		    ! gda_set_set_holder_value (ins_params, error, "sql", data->current->query_buffer->str)) {
+			g_free (qname);
+			return NULL;
+		}
 		g_free (qname);
+		
+		GdaConnection *store_cnc;
+		store_cnc = gda_meta_store_get_internal_connection (mstore);
+		if (gda_connection_statement_execute_non_select (store_cnc, ins_stmt, ins_params,
+								 NULL, error) == -1)
+			return NULL;
 		res = g_new0 (GdaInternalCommandResult, 1);
 		res->type = GDA_INTERNAL_COMMAND_RESULT_EMPTY;
 	}
@@ -2489,26 +2617,102 @@
 		data->current->query_buffer = g_string_new ("");
 
 	if (args[0] && *args[0]) {
-		GdaStatement *stmt = find_statement_in_connection_meta_store (data->current->cnc, args[0]);
-		if (stmt) {
-			gchar *str;
-			str = gda_statement_to_sql_extended (stmt, data->current->cnc, NULL, 
-							     GDA_STATEMENT_SQL_PARAMS_SHORT, NULL, error);
-			if (!str)
-				return NULL;
+		/* Meta store's init */
+		GdaMetaStore *mstore;
+		mstore = gda_connection_get_meta_store (data->current->cnc);
+		if (!gda_meta_store_schema_add_custom_object (mstore, QUERY_BUFFERS_TABLE_DESC, NULL)) {
+			g_set_error (error, 0, 0,
+				     _("Can't initialize dictionary to store query buffers"));
+			return NULL;
+		}
+		
+		/* query retreival */
+		static GdaStatement *sel_stmt = NULL;
+		static GdaSet *sel_params = NULL;
+		GdaDataModel *model;
+		const GValue *cvalue;
+		if (!sel_stmt) {
+			sel_stmt = gda_sql_parser_parse_string (data->current->parser, 
+								QUERY_BUFFERS_TABLE_SELECT_ONE, NULL, NULL);
+			g_assert (sel_stmt);
+			g_assert (gda_statement_get_parameters (sel_stmt, &sel_params, NULL));
+		}
 
-			g_string_assign (data->current->query_buffer, str);
-			g_free (str);
+		if (! gda_set_set_holder_value (sel_params, error, "name", args[0]))
+			return NULL;
+
+		GdaConnection *store_cnc;
+		store_cnc = gda_meta_store_get_internal_connection (mstore);
+		model = gda_connection_statement_execute_select (store_cnc, sel_stmt, sel_params, error);
+		if (!model)
+			return NULL;
+		
+		if ((gda_data_model_get_n_rows (model) == 1) &&
+		    (cvalue = gda_data_model_get_value_at (model, 0, 0, NULL))) {
+			g_string_assign (data->current->query_buffer, g_value_get_string (cvalue));
 			res = g_new0 (GdaInternalCommandResult, 1);
 			res->type = GDA_INTERNAL_COMMAND_RESULT_EMPTY;
 		}
-		else
+		else 
 			g_set_error (error, 0, 0,
-				     _("Could not find query named '%s'"), args[0]);
+				     _("Could not find query buffer named '%s'"), args[0]);
+		g_object_unref (model);
+	}
+	else
+		g_set_error (error, 0, 0,
+			     _("Missing query buffer name"));
+		
+	return res;
+}
+
+static GdaInternalCommandResult *
+extra_command_query_buffer_delete_dict (GdaConnection *cnc, const gchar **args,
+					GError **error, MainData *data)
+{
+	GdaInternalCommandResult *res = NULL;
+
+	if (!data->current) {
+		g_set_error (error, 0, 0, _("No connection opened"));
+		return NULL;
+	}
+
+	if (!data->current->query_buffer) 
+		data->current->query_buffer = g_string_new ("");
+
+	if (args[0] && *args[0]) {
+		/* Meta store's init */
+		GdaMetaStore *mstore;
+		mstore = gda_connection_get_meta_store (data->current->cnc);
+		if (!gda_meta_store_schema_add_custom_object (mstore, QUERY_BUFFERS_TABLE_DESC, NULL)) {
+			g_set_error (error, 0, 0,
+				     _("Can't initialize dictionary to store query buffers"));
+			return NULL;
+		}
+		
+		/* query retreival */
+		static GdaStatement *del_stmt = NULL;
+		static GdaSet *del_params = NULL;
+		if (!del_stmt) {
+			del_stmt = gda_sql_parser_parse_string (data->current->parser, 
+								QUERY_BUFFERS_TABLE_DELETE, NULL, NULL);
+			g_assert (del_stmt);
+			g_assert (gda_statement_get_parameters (del_stmt, &del_params, NULL));
+		}
+
+		if (! gda_set_set_holder_value (del_params, error, "name", args[0]))
+			return NULL;
+
+		GdaConnection *store_cnc;
+		store_cnc = gda_meta_store_get_internal_connection (mstore);
+		if (gda_connection_statement_execute_non_select (store_cnc, del_stmt, del_params,
+								 NULL, error) == -1)
+			return NULL;
+		res = g_new0 (GdaInternalCommandResult, 1);
+		res->type = GDA_INTERNAL_COMMAND_RESULT_EMPTY;
 	}
 	else
 		g_set_error (error, 0, 0,
-			     _("Missing query name"));
+			     _("Missing query buffer name"));
 		
 	return res;
 }



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