libgda r3146 - in trunk: . doc/C doc/C/tmpl libgda libgda/sql-parser providers/mysql providers/postgres providers/skel-implementation/capi tools



Author: vivien
Date: Tue Apr 15 09:26:32 2008
New Revision: 3146
URL: http://svn.gnome.org/viewvc/libgda?rev=3146&view=rev

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

	* configure.in: Rename libext variable to avoid contaminating libtool-2.2
	variable by same name, for bug #527892 (from Cygwin Ports maintainer)
	* libgda/gda-connection.c: corrected a bug in gda_connection_get_events(): the
	returned list is now read-only, the last GdaConnectionEvent being first in the list
	* libgda/gda-connection-event.c: removed gda_connection_event_free() as
	g_object_unref() should be used instead, removed gda_connection_event_list_free()
	and gda_connection_event_list_copy()
	* libgda/gda-util.[ch]: added a new gda_completion_list_get() function to make
	Libgda compute a list of possible completions when writinf a SQL statement
	* tools/command-exec.c:
	* tools/gda-sql.c:
	* tools/tools-input.c: improved completion mechanism using gda_completion_list_get()
	* libgda/sql-parser/gda-statement-struct-util.[ch]:
	* libgda/gda-meta-struct.[ch]: improved handling of double quoted SQL identifiers
	* tools/gda-sql.c: removed the -p (Provider name), -s (Data source) and
	-c (Direct connection string) options: now any number of connection can be opened
	by listing them one after the other using either a DSN name or a connection string
	like "PostgreSQL://DB_NAME=mydb"
	* providers/postgres/gda-postgres-meta.c: bug fixed in the I_STMT_REF_CONSTRAINTS and
	I_STMT_REF_CONSTRAINTS_ALL statements

	Made a review of the DSN and connection strings in Libgda, and decided to require
	string encoded using RFC 1738 (Uniform Resource Locators (URL)): the non ascii
	(and some special characters) must be represented in their "%ab" form where
	"ab" is their hexa. representation; this will solve problems where DSN and/or 
	auth string must contain some ";" character.
	* libgda/gda-util.[ch]: added the gda_rfc1738_encode(), gda_rfc1738_decode(),
	gda_dsn_split() and gda_connection_string_split() functions
	* libgda/gda-quark-list.c: modified gda_quark_list_new_from_string() and
	gda_quark_list_add_from_string() to decode the key and value for each pair.
	* libgda/gda-config.[ch]: use gda_rfc1738_encode() when reading provider name, username
	and password from config file.
	* libgda/gda-connection.c: changed gda_connection_open_from_dsn() to accept DSN in
	the form [<username>[:<password>] ]<DSN> where <username> and <password> are RFC 1738
	encoded.
	* libgda/sql-parser/gda-statement-struct-parts.c: applied patch by Daniel Espinosa for
	bug #528057


Modified:
   trunk/ChangeLog
   trunk/configure.in
   trunk/doc/C/libgda-4.0-docs.sgml
   trunk/doc/C/libgda-4.0-sections.txt
   trunk/doc/C/prov-writing.xml
   trunk/doc/C/tmpl/gda-connection-event.sgml
   trunk/doc/C/tmpl/gda-connection.sgml
   trunk/doc/C/tmpl/gda-util.sgml
   trunk/doc/C/tmpl/gda-value.sgml
   trunk/libgda/gda-config.c
   trunk/libgda/gda-config.h
   trunk/libgda/gda-connection-event.c
   trunk/libgda/gda-connection-event.h
   trunk/libgda/gda-connection.c
   trunk/libgda/gda-connection.h
   trunk/libgda/gda-meta-struct.c
   trunk/libgda/gda-meta-struct.h
   trunk/libgda/gda-quark-list.c
   trunk/libgda/gda-util.c
   trunk/libgda/gda-util.h
   trunk/libgda/sql-parser/gda-statement-struct-parts.c
   trunk/libgda/sql-parser/gda-statement-struct-util.c
   trunk/libgda/sql-parser/gda-statement-struct-util.h
   trunk/providers/mysql/gda-mysql-blob-op.c
   trunk/providers/postgres/gda-postgres-meta.c
   trunk/providers/skel-implementation/capi/gda-capi-blob-op.c
   trunk/tools/command-exec.c
   trunk/tools/gda-sql.c
   trunk/tools/tools-input.c
   trunk/tools/tools-input.h

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Tue Apr 15 09:26:32 2008
@@ -250,8 +250,8 @@
 
 dnl this is the shared link library extension, which varies by platform
 case $host_os in
-	cygwin*) libext=".dll.a" ;;
-	*) libext=".so" ;;
+	cygwin*) linklibext=".dll.a" ;;
+	*) linklibext=".so" ;;
 esac
 
 dnl Test for Berkeley DB
@@ -282,7 +282,7 @@
 		AC_MSG_CHECKING(for Berkeley DB files)
 		for d in $dir /usr /usr/local
 		do
-			if test -f $d/$lib/libdb$libext -a -f $d/include/db.h
+			if test -f $d/$lib/libdb$linklibext -a -f $d/include/db.h
 			then
 				AC_MSG_RESULT(found Berkeley DB in $d)
 				bdblib="-ldb"
@@ -330,14 +330,14 @@
 	AC_MSG_CHECKING(for ODBC files)
 	for d in $dir /usr /usr/local
 	do
-		if test -f $d/$lib/libodbc$libext -a -f $d/include/sql.h
+		if test -f $d/$lib/libodbc$linklibext -a -f $d/include/sql.h
 		then
 			AC_MSG_RESULT(found ODBC in $d)
 			odbclib="-lodbc"
 			odbcdir=$d
 			break
 		fi
-		if test -f $d/$lib/libiodbc$libext -a -f $d/include/sql.h
+		if test -f $d/$lib/libiodbc$linklibext -a -f $d/include/sql.h
 		then
 			AC_MSG_RESULT(found iODBC in $d)
 			odbclib="-liodbc"
@@ -393,14 +393,14 @@
 			else
 				mysqldir_suffix=
 			fi
-			if test -f $d/$lib/mysql/libmysqlclient.a -o -f $d/$lib/mysql/libmysqlclient$libext
+			if test -f $d/$lib/mysql/libmysqlclient.a -o -f $d/$lib/mysql/libmysqlclient$linklibext
 			then
 				AC_MSG_RESULT(found mysql in $d)
 				mysqldir=$d
 				mysqllibdir_suffix=/mysql
 				break
 			fi
-			if test -f $d/$lib/libmysqlclient.a -o -f $d/$lib/libmysqlclient$libext
+			if test -f $d/$lib/libmysqlclient.a -o -f $d/$lib/libmysqlclient$linklibext
 			then
 				AC_MSG_RESULT(found mysql in $d)
 				mysqldir=$d
@@ -452,14 +452,14 @@
 		else
 			msqldir_suffix=
 		fi
-		if test -f $d/$lib/msql/libmsql.a -o -f $d/$lib/msql/libmsql$libext
+		if test -f $d/$lib/msql/libmsql.a -o -f $d/$lib/msql/libmsql$linklibext
 		then
 			AC_MSG_RESULT(found mSQL in $d)
 			msqldir=$d
 			msqllibdir_suffix=/msql
 			break
 		fi
-		if test -f $d/$lib/libmsql.a -o -f $d/$lib/libmsql$libext
+		if test -f $d/$lib/libmsql.a -o -f $d/$lib/libmsql$linklibext
 		then
 			AC_MSG_RESULT(found mSQL in $d)
 			msqldir=$d
@@ -509,7 +509,7 @@
 	AC_MSG_CHECKING(for Postgres files)
 	for d in $dir /usr /usr/local/postgres /opt/postgres /opt/packages/postgres /disk/postgres /usr/local/pgsql
 	do
-		if test -f $d/$lib/libpq.a -o -f $d/$lib/libpq$libext
+		if test -f $d/$lib/libpq.a -o -f $d/$lib/libpq$linklibext
 		then
 			AC_MSG_RESULT(found Postgres in $d)
 			postgresdir=$d
@@ -569,13 +569,13 @@
 	AC_MSG_CHECKING(for freetds files)
 	for d in $dir /usr/local/freetds /usr /opt/freetds /opt/packages/freetds /opt/freetds-0.50
 	do
-		if test -f "$d/include/tds.h" -a -e "$d/$lib/libtds$libext" -a -f "$d/include/tdsver.h"
+		if test -f "$d/include/tds.h" -a -e "$d/$lib/libtds$linklibext" -a -f "$d/include/tdsver.h"
 		then
 			AC_MSG_RESULT(found freetds in $d)
 			freetdsdir="$d"
 			freetds_incdir="$d/include"
 			break
-		elif test -f "$d/include/freetds/tds.h" -a -e "$d/$lib/libtds$libext" -a -f "$d/include/freetds/tdsver.h"
+		elif test -f "$d/include/freetds/tds.h" -a -e "$d/$lib/libtds$linklibext" -a -f "$d/include/freetds/tdsver.h"
 		then
 			AC_MSG_RESULT(found freetds in $d and includes in $d/include/freetds)
 			freetdsdir="$d"
@@ -932,7 +932,7 @@
 	mdbdir=""
 	for d in $dir /usr /usr/local /opt/gnome
 	do
-		if test -f $d/include/mdbtools.h -a -f $d/$lib/libmdb$libext -o -f $d/include/mdbtools.h -a -f $d/$lib/libmdb.a
+		if test -f $d/include/mdbtools.h -a -f $d/$lib/libmdb$linklibext -o -f $d/include/mdbtools.h -a -f $d/$lib/libmdb.a
 		then
 			AC_MSG_RESULT(found MDB Tools in $d)
 			mdbdir=$d

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	Tue Apr 15 09:26:32 2008
@@ -791,7 +791,7 @@
 	  </mediaobject>
 	</para>
 
-	<sect2>
+	<sect2 id="information_schema:data_types">
 	  <title>Data types</title>
 	  <para>
 	    Data types (as reported for example for table's columns) can be one of the following kinds:
@@ -844,6 +844,21 @@
 	  </para>
 	</sect2>
 
+	<sect2 id="information_schema:sql_identifiers">
+	  <title>SQL identifiers</title>
+	  <para>
+	    SQL identifiers (database object's names) are case insitive, but it is still possible to specify
+	    that an SQL identifier be case sensitive by putting it between double quotes. &LIBGDA; has chosen
+	    the convention that case insitive SQL identifiers should all be in lower case in the meta data's tables
+	    whereas case sensitive SQL identifiers can soncain some upper case ASCII characters.
+	  </para>
+	  <para>
+	    This convention must be respected by database providers' implementations or the 
+	    <link linkend="GdaMetaStruct">GdaMetaStruct</link> object and the associated features
+	    (such as keyword completion) will not work properly.
+	  </para>
+	</sect2>
+
 	<sect2>
 	  <title>Short and full names</title>
 	  <para>
@@ -927,19 +942,61 @@
 Sales    | PostgreSQL | Sales        | DB_NAME=sales          |
 [...]
 	</programlisting>
-	To run an interractive session, just specify a DSN (using the <option>-s DSN</option> option) or
-	a connection string (using the <option>-c "connection string"</option> and <option>-p provider</option> options). 
-	Alternatively, it is also possible to use the &quot;&lt;provider&gt;://&lt;connection string&gt;&quot; 
-	format (such as for example "Firebird://DATABASE=/path/to/dbfile.fdb")for an all-in-one connection 
-	specification (pass this string without any option specifier), or set
-	the GDA_SQL_CNC environment variable to contain that string, and run the command without any argument.
+	To run an interractive session, just specify a DSN or a connection string using
+	the &quot;&lt;provider&gt;://&lt;connection string&gt;&quot; 
+	format (such as for example "Firebird://DATABASE=/path/to/dbfile.fdb"), or set
+	the GDA_SQL_CNC environment variable to contain that string, and run the command without any argument, 
+	for example:
+	<programlisting>
+[prompt]> gda-sql-4.0 PostgreSQL://DB_NAME=sales
+Welcome to the GDA SQL console, version 3.99.3
+
+Type: .copyright to show usage and distribution terms
+      .? for help with internal commands
+      .q (or CTRL-D) to quit
+      (the '.' can be replaced by a '\')
+      or any query terminated by a semicolon
+
+Opening connection 'c0' for: PostgreSQL://DB_NAME=sales
+        Getting database schema information, this may take some time... Done.
+c0>
+	</programlisting>
+	Note that the "c0" is the prompt for the first opened connection.
       </para>
       <para>
-	Several connections can be opened at once (with only one "active" at any given time), use the <option>\c</option>
+	Several connections can be opened at once (with only one "active" at any given time), by specifying
+	all of them on the command line, or by using the <option>\c</option>
 	and <option>\close</option> to manage (open, change, close) the connections; the prompt contains
-	the name of the current connection used. 
+	the name of the current connection used. The following example opens two connections, one for the "pgsales"
+	DSN, and one for the "PostgreSQL://DB_NAME=sales" connection string, and shows the usage of the ".c" command
+	to list the opened connections:
+	<programlisting>
+[prompt]> gda-sql-4.0 pgsales PostgreSQL://DB_NAME=sales
+Welcome to the GDA SQL console, version 3.99.3
+
+Type: .copyright to show usage and distribution terms
+      .? for help with internal commands
+      .q (or CTRL-D) to quit
+      (the '.' can be replaced by a '\')
+      or any query terminated by a semicolon
+
+Opening connection 'pgsales' for: pgsales
+Opening connection 'c1' for: PostgreSQL://DB_NAME=sales
+        Getting database schema information, this may take some time... Done.
+c1> .c
+             List of opened connections
+Name    | Provider   | DSN or connection string | Username
+--------+------------+--------------------------+---------
+pgsales | PostgreSQL | pgsales                  |         
+c1      | PostgreSQL | DB_NAME=sales            |         
+(2 rows)
+
+c1>
+	</programlisting>
       </para>
-      <programlisting><![CDATA[
+      <para>
+	Here is another sample session showing how to use variables in statements:
+	<programlisting><![CDATA[
 [prompt]> gda-sql-4.0 -p SQLite -c "DB_DIR=.;DB_NAME=sales_test"
 Welcome to the GDA SQL console, version 3.1.2
 
@@ -962,7 +1019,8 @@
 ---+-------------+-------------------+---------+-----
  9 | Greg Popoff |                 2 | SP      | MDR 
 c0> ]]>
-      </programlisting>
+	</programlisting>
+      </para>
       <para>
 	The &gda-sql; tool uses the following environment variables, when set:
 	<itemizedlist>

Modified: trunk/doc/C/libgda-4.0-sections.txt
==============================================================================
--- trunk/doc/C/libgda-4.0-sections.txt	(original)
+++ trunk/doc/C/libgda-4.0-sections.txt	Tue Apr 15 09:26:32 2008
@@ -684,16 +684,19 @@
 <SECTION>
 <FILE>gda-util</FILE>
 <TITLE>Utility functions</TITLE>
-g_type_to_string
-g_type_from_string
-gda_string_hash_to_list
+gda_g_type_to_string
+gda_g_type_from_string
+<SUBSECTION>
 gda_default_escape_string
-gda_sql_replace_placeholders
-gda_file_load
-gda_file_save
-gda_server_provider_get_schema_nb_columns
-gda_server_provider_init_schema_model
-<SUBSECTION Standard>
+gda_default_unescape_string
+gda_identifier_hash
+gda_identifier_equal
+gda_completion_list_get
+<SUBSECTION>
+gda_rfc1738_encode
+gda_rfc1738_decode
+gda_dsn_split
+gda_connection_string_split
 </SECTION>
 
 <SECTION>

Modified: trunk/doc/C/prov-writing.xml
==============================================================================
--- trunk/doc/C/prov-writing.xml	(original)
+++ trunk/doc/C/prov-writing.xml	Tue Apr 15 09:26:32 2008
@@ -320,8 +320,10 @@
       are in the specified catalog and schema.
     </para>
     <para>
-      For further information about the tables, see the schema displayed in 
-      the <link linkend="GdaMetaStore">GdaMetaStore</link>'s documentation.
+      Make sure you read the information about the meta data's database structure in the
+      <link linkend="information_schema">Database structure</link>, and specifically the
+      <link linkend="information_schema:data_types">data types</link> section and the 
+      <link linkend="information_schema:sql_identifiers">SQL identifiers</link> section.
     </para>
     <sect2>
       <title>_info()</title>

Modified: trunk/doc/C/tmpl/gda-connection-event.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-connection-event.sgml	(original)
+++ trunk/doc/C/tmpl/gda-connection-event.sgml	Tue Apr 15 09:26:32 2008
@@ -80,31 +80,6 @@
 @Returns: 
 
 
-<!-- ##### FUNCTION gda_connection_event_free ##### -->
-<para>
-
-</para>
-
- event: 
-
-
-<!-- ##### FUNCTION gda_connection_event_list_copy ##### -->
-<para>
-
-</para>
-
- events: 
- Returns: 
-
-
-<!-- ##### FUNCTION gda_connection_event_list_free ##### -->
-<para>
-
-</para>
-
- events: 
-
-
 <!-- ##### FUNCTION gda_connection_event_set_event_type ##### -->
 <para>
 

Modified: trunk/doc/C/tmpl/gda-connection.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-connection.sgml	(original)
+++ trunk/doc/C/tmpl/gda-connection.sgml	Tue Apr 15 09:26:32 2008
@@ -403,15 +403,6 @@
 @Returns: 
 
 
-<!-- ##### FUNCTION gda_connection_get_authentication ##### -->
-<para>
-
-</para>
-
- cnc: 
- Returns: 
-
-
 <!-- ##### FUNCTION gda_connection_add_event ##### -->
 <para>
 

Modified: trunk/doc/C/tmpl/gda-util.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-util.sgml	(original)
+++ trunk/doc/C/tmpl/gda-util.sgml	Tue Apr 15 09:26:32 2008
@@ -17,6 +17,24 @@
 <!-- ##### SECTION Stability_Level ##### -->
 
 
+<!-- ##### FUNCTION gda_g_type_to_string ##### -->
+<para>
+
+</para>
+
+ type: 
+ Returns: 
+
+
+<!-- ##### FUNCTION gda_g_type_from_string ##### -->
+<para>
+
+</para>
+
+ str: 
+ Returns: 
+
+
 <!-- ##### FUNCTION gda_default_escape_string ##### -->
 <para>
 
@@ -26,22 +44,84 @@
 @Returns: 
 
 
-<!-- ##### FUNCTION gda_server_provider_get_schema_nb_columns ##### -->
+<!-- ##### FUNCTION gda_default_unescape_string ##### -->
+<para>
+
+</para>
+
+ string: 
+ Returns: 
+
+
+<!-- ##### FUNCTION gda_identifier_hash ##### -->
 <para>
 
 </para>
 
- schema: 
+ id: 
 @Returns: 
 
 
-<!-- ##### FUNCTION gda_server_provider_init_schema_model ##### -->
+<!-- ##### FUNCTION gda_identifier_equal ##### -->
 <para>
 
 </para>
 
- model: 
- schema: 
+ id1: 
+ id2: 
 @Returns: 
 
 
+<!-- ##### FUNCTION gda_completion_list_get ##### -->
+<para>
+
+</para>
+
+ cnc: 
+ text: 
+ start: 
+ end: 
+ Returns: 
+
+
+<!-- ##### FUNCTION gda_rfc1738_encode ##### -->
+<para>
+
+</para>
+
+ string: 
+ Returns: 
+
+
+<!-- ##### FUNCTION gda_rfc1738_decode ##### -->
+<para>
+
+</para>
+
+ string: 
+ Returns: 
+
+
+<!-- ##### FUNCTION gda_dsn_split ##### -->
+<para>
+
+</para>
+
+ string: 
+ out_dsn: 
+ out_username: 
+ out_password: 
+
+
+<!-- ##### FUNCTION gda_connection_string_split ##### -->
+<para>
+
+</para>
+
+ string: 
+ out_cnc_params: 
+ out_provider: 
+ out_username: 
+ out_password: 
+
+

Modified: trunk/doc/C/tmpl/gda-value.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-value.sgml	(original)
+++ trunk/doc/C/tmpl/gda-value.sgml	Tue Apr 15 09:26:32 2008
@@ -546,6 +546,16 @@
 @Returns: 
 
 
+<!-- ##### FUNCTION gda_value_bcompare ##### -->
+<para>
+
+</para>
+
+ value1: 
+ value2: 
+ Returns: 
+
+
 <!-- ##### FUNCTION gda_value_compare ##### -->
 <para>
 

Modified: trunk/libgda/gda-config.c
==============================================================================
--- trunk/libgda/gda-config.c	(original)
+++ trunk/libgda/gda-config.c	Tue Apr 15 09:26:32 2008
@@ -32,6 +32,7 @@
 #include <libgda/gda-set.h>
 #include <libgda/gda-holder.h>
 #include <libgda/gda-log.h>
+#include <libgda/gda-util.h>
 #ifdef HAVE_FAM
 #include <fam.h>
 #include <glib/giochannel.h>
@@ -255,9 +256,9 @@
 					xmlFree (prop);
 					continue;
 				}
-				if (!strcmp ((gchar *) prop, "DSN"))
+				if (!strcmp ((gchar *) prop, "DSN")) 
 					info->cnc_string = g_strdup ((gchar *)value);
-				else if (!strcmp ((gchar *) prop, "Provider"))
+				else if (!strcmp ((gchar *) prop, "Provider")) 
 					info->provider = g_strdup ((gchar *)value);
 				else if (!strcmp ((gchar *) prop, "Description"))
 					info->description = g_strdup ((gchar *)value);
@@ -274,11 +275,17 @@
 			if (username) {
 				if (!info->auth_string) {
 					/* migrate username/password to auth_string */
-					if (password)
-						info->auth_string = g_strdup_printf ("USERNAME=%s;PASSWORD=%s",
-										     username, password);
+					gchar *s1;
+					s1 = gda_rfc1738_encode (username);
+					if (password) {
+						gchar *s2;
+						s2 = gda_rfc1738_encode (password);
+						info->auth_string = g_strdup_printf ("USERNAME=%s;PASSWORD=%s", s1, s2);
+						g_free (s2);
+					}
 					else
-						info->auth_string = g_strdup_printf ("USERNAME=%s", username);
+						info->auth_string = g_strdup_printf ("USERNAME=%s", s1);
+					g_free (s1);
 				}
 				g_free (username);
 				g_free (password);

Modified: trunk/libgda/gda-config.h
==============================================================================
--- trunk/libgda/gda-config.h	(original)
+++ trunk/libgda/gda-config.h	Tue Apr 15 09:26:32 2008
@@ -50,11 +50,11 @@
 } GdaConfigError;
 
 struct _GdaDataSourceInfo {
-        gchar    *name;
-        gchar    *provider;
-        gchar    *description;
-        gchar    *cnc_string;
-        gchar    *auth_string;
+        gchar    *name;        /* plain text, not RFC 1738 encoded */
+        gchar    *provider;    /* plain text, not RFC 1738 encoded */
+        gchar    *description; /* plain text, not RFC 1738 encoded */
+        gchar    *cnc_string;  /* semi-colon separated <key>=<value> list where <key> and <value> are RFC 1738 encoded */
+        gchar    *auth_string; /* semi-colon separated <key>=<value> list where <key> and <value> are RFC 1738 encoded */
         gboolean  is_system;
 };
 

Modified: trunk/libgda/gda-connection-event.c
==============================================================================
--- trunk/libgda/gda-connection-event.c	(original)
+++ trunk/libgda/gda-connection-event.c	Tue Apr 15 09:26:32 2008
@@ -187,56 +187,6 @@
 }
 
 /**
- * gda_connection_event_free:
- * @event: the event object.
- *
- * Frees the memory allocated by the event object.
- */
-void
-gda_connection_event_free (GdaConnectionEvent *event)
-{
-	g_object_unref (G_OBJECT (event));
-}
-
-/**
- * gda_connection_event_list_copy:
- * @events: a GList holding event objects.
- *
- * Creates a new list which contains the same events as @events and
- * adds a reference for each event in the list.
- *
- * You must free the list using #gda_connection_event_list_free.
- * Returns: a list of events.
- */
-GList *
-gda_connection_event_list_copy (const GList * events)
-{
-	GList *l;
-	GList *new_list;
-
-	new_list = g_list_copy ((GList *) events);
-	for (l = new_list; l; l = l->next)
-		g_object_ref (G_OBJECT (l->data));
-
-	return new_list;
-}
-
-/**
- * gda_connection_event_list_free:
- * @events: a GList holding event objects.
- *
- * Frees all event objects in the list and the list itself.
- * After this function has been called, the @events parameter doesn't point
- * to valid storage any more.
- */
-void
-gda_connection_event_list_free (GList * events)
-{
-	g_list_foreach (events, (GFunc) gda_connection_event_free, NULL);
-	g_list_free (events);
-}
-
-/**
  * gda_connection_event_set_event_type
  * @event: a #GdaConnectionEvent object
  * @type: the severity of the event

Modified: trunk/libgda/gda-connection-event.h
==============================================================================
--- trunk/libgda/gda-connection-event.h	(original)
+++ trunk/libgda/gda-connection-event.h	Tue Apr 15 09:26:32 2008
@@ -81,9 +81,6 @@
 
 GType                   gda_connection_event_get_type (void) G_GNUC_CONST;
 GdaConnectionEvent     *gda_connection_event_new (GdaConnectionEventType type);
-void                    gda_connection_event_free (GdaConnectionEvent * event);
-GList                  *gda_connection_event_list_copy (const GList * events);
-void                    gda_connection_event_list_free (GList * events);
 
 void                    gda_connection_event_set_event_type (GdaConnectionEvent *event, GdaConnectionEventType type);
 GdaConnectionEventType  gda_connection_event_get_event_type (GdaConnectionEvent *event);

Modified: trunk/libgda/gda-connection.c
==============================================================================
--- trunk/libgda/gda-connection.c	(original)
+++ trunk/libgda/gda-connection.c	Tue Apr 15 09:26:32 2008
@@ -41,6 +41,7 @@
 #include <sql-parser/gda-sql-parser.h>
 #include <sql-parser/gda-statement-struct-trans.h>
 #include <libgda/gda-meta-store-extra.h>
+#include <libgda/gda-util.h>
 
 #define PROV_CLASS(provider) (GDA_SERVER_PROVIDER_CLASS (G_OBJECT_GET_CLASS (provider)))
 
@@ -231,8 +232,10 @@
 		cnc->priv->provider_obj = NULL;
 	}
 
-	if (cnc->priv->events_list)
-		gda_connection_event_list_free (cnc->priv->events_list);
+	if (cnc->priv->events_list) {
+		g_list_foreach (cnc->priv->events_list, (GFunc) g_object_unref, NULL);
+		cnc->priv->events_list = NULL;
+	}
 
 	if (cnc->priv->trans_status) {
 		g_object_unref (cnc->priv->trans_status);
@@ -388,17 +391,24 @@
 /**
  * gda_connection_open_from_dsn
  * @dsn: data source name.
- * @auth_string: authentication string
+ * @auth_string: authentication string, or %NULL
  * @options: options for the connection (see #GdaConnectionOptions).
  * @error: a place to store an error, or %NULL
  *
- * This function is the way of opening database connections with libgda.
- *
- * Establishes a connection to a data source. 
+ * This function is the way of opening database connections with libgda, using a pre-defined data source (DSN),
+ * see gda_config_define_dsn() for more information about how to define a DSN. If you don't want to define
+ * a DSN, it is possible to use gda_connection_open_from_string() instead of this method.
+ *
+ * The @dsn string must have the following format: "[&lt;username&gt;[:&lt;password&gt;] ]&lt;DSN&gt;" 
+ * (if &lt;username&gt; and/or &lt;password&gt; are provided, and @auth_string is %NULL, then these username
+ * and passwords will be used). Note that if provided, &lt;username&gt; and &lt;password&gt; 
+ * must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information.
  *
- * The @auth_string must contain the authentication information for the server
+ * The @auth_string can contain the authentication information for the server
  * to accept the connection. It is a string containing semi-colon seperated named value, usually 
- * like "USERNAME=...;PASSWORD=..." where the ... are replaced by actual values. 
+ * like "USERNAME=...;PASSWORD=..." where the ... are replaced by actual values. Note that each
+ * name and value must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information.
+ *
  * The actual named parameters required depend on the provider being used, and that list is available
  * as the <parameter>auth_params</parameter> member of the #GdaProviderInfo structure for each installed
  * provider (use gda_config_get_provider_info() to get it). Also one can use the "gda-sql-4.0 -L" command to 
@@ -412,16 +422,42 @@
 {
 	GdaConnection *cnc = NULL;
 	GdaDataSourceInfo *dsn_info;
+	gchar *user, *pass, *real_dsn;
+	gchar *real_auth_string = NULL;
 
 	g_return_val_if_fail (dsn && *dsn, NULL);
+	gda_dsn_split (dsn, &real_dsn, &user, &pass);
+	if (!real_dsn) {
+		g_free (user);
+		g_free (pass);
+		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR, 
+			     _("Malformed data source specification '%s'"), dsn);
+		return NULL;
+	}
 
 	/* get the data source info */
-	dsn_info = gda_config_get_dsn (dsn);
+	dsn_info = gda_config_get_dsn (real_dsn);
 	if (!dsn_info) {
 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR, 
-			     _("Data source %s not found in configuration"), dsn);
+			     _("Data source %s not found in configuration"), real_dsn);
+		g_free (real_dsn);
+		g_free (user);
+		g_free (pass);
 		return NULL;
 	}
+	if (!auth_string && user) {
+		gchar *s1;
+		s1 = gda_rfc1738_encode (user);
+		if (pass) {
+			gchar *s2;
+			s2 = gda_rfc1738_encode (pass);
+			real_auth_string = g_strdup_printf ("USERNAME=%s;PASSWORD=%s", s1, s2);
+			g_free (s2);
+		}
+		else
+			real_auth_string = g_strdup_printf ("USERNAME=%s", s1);
+		g_free (s1);
+	}
 
 	/* try to find provider */
 	if (dsn_info->provider != NULL) {
@@ -431,16 +467,18 @@
 		if (prov) {
 			if (PROV_CLASS (prov)->create_connection) {
 				cnc = PROV_CLASS (prov)->create_connection (prov);
-				if (cnc) {
-					g_object_set (G_OBJECT (cnc), "provider_obj", prov, NULL);
-					if (dsn && *dsn)
-						g_object_set (G_OBJECT (cnc), "dsn", dsn, NULL);
-					g_object_set (G_OBJECT (cnc), "auth_string", auth_string, "options", options, NULL);
-				}
+				if (cnc) 
+					g_object_set (G_OBJECT (cnc), 
+						      "provider_obj", prov,
+						      "dsn", real_dsn,
+						      "auth_string", auth_string ? auth_string : real_auth_string, 
+						      "options", options, NULL);
 			}
 			else
-				cnc = g_object_new (GDA_TYPE_CONNECTION, "provider_obj", prov, 
-						    "dsn", dsn, "auth_string", auth_string, 
+				cnc = g_object_new (GDA_TYPE_CONNECTION, 
+						    "provider_obj", prov, 
+						    "dsn", real_dsn, 
+						    "auth_string", auth_string ? auth_string : real_auth_string, 
 						    "options", options, NULL);
 			
 			/* open connection */
@@ -454,6 +492,10 @@
 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_PROVIDER_NOT_FOUND_ERROR, 
 			     _("Datasource configuration error: no provider specified"));
 
+	g_free (real_auth_string);
+	g_free (real_dsn);
+	g_free (user);
+	g_free (pass);
 	return cnc;
 }
 
@@ -461,24 +503,35 @@
  * gda_connection_open_from_string
  * @provider_name: provider ID to connect to, or %NULL
  * @cnc_string: connection string.
- * @auth_string: authentication string
+ * @auth_string: authentication string, or %NULL
  * @options: options for the connection (see #GdaConnectionOptions).
  * @error: a place to store an error, or %NULL
  *
  * Opens a connection given a provider ID and a connection string. This
  * allows applications to open connections without having to create
- * a data source in the configuration. The format of @cnc_string is
+ * a data source (DSN) in the configuration. The format of @cnc_string is
  * similar to PostgreSQL and MySQL connection strings. It is a semicolumn-separated
- * series of key=value pairs. Do not add extra whitespace after the semicolumn
- * separator. The possible keys depend on the provider, the "gda-sql-4.0 -L" command
+ * series of &lt;key&gt;=&lt;value&gt; pairs, where each key and value are encoded as per RFC 1738, 
+ * see gda_rfc1738_encode() for more information.
+ *
+ * The possible keys depend on the provider, the "gda-sql-4.0 -L" command
  * can be used to list the actual keys for each installed database provider.
  *
  * For example the connection string to open an SQLite connection to a database
- * file named "my_data.db" in the current directory would be "DB_DIR=.;DB_NAME=my_data".
+ * file named "my_data.db" in the current directory would be <constant>"DB_DIR=.;DB_NAME=my_data"</constant>.
+ *
+ * The @cnc_string string must have the following format: 
+ * "[&lt;provider&gt;://][&lt;username&gt;[:&lt;password&gt;] ]&lt;connection_params&gt;"
+ * (if &lt;username&gt; and/or &lt;password&gt; are provided, and @auth_string is %NULL, then these username
+ * and passwords will be used, and if &lt;provider&gt; is provided and @provider_name is %NULL then this
+ * provider will be used). Note that if provided, &lt;username&gt;, &lt;password&gt; and  &lt;provider&gt;
+ * must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information.
  *
  * The @auth_string must contain the authentication information for the server
  * to accept the connection. It is a string containing semi-colon seperated named values, usually 
- * like "USERNAME=...;PASSWORD=..." where the ... are replaced by actual values. 
+ * like "USERNAME=...;PASSWORD=..." where the ... are replaced by actual values. Note that each
+ * name and value must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information.
+ *
  * The actual named parameters required depend on the provider being used, and that list is available
  * as the <parameter>auth_params</parameter> member of the #GdaProviderInfo structure for each installed
  * provider (use gda_config_get_provider_info() to get it). Similarly to the format of the connection
@@ -496,46 +549,63 @@
 				 GdaConnectionOptions options, GError **error)
 {
 	GdaConnection *cnc = NULL;
-	gchar *ptr, *dup;
+	gchar *user, *pass, *real_cnc, *real_provider;
+	gchar *real_auth_string = NULL;
 
 	g_return_val_if_fail (cnc_string && *cnc_string, NULL);
-
-	/* try to see if connection string has the "<provider>://<real cnc string>" format */
-	dup = g_strdup (cnc_string);
-	for (ptr = dup; *ptr; ptr++) {
-		if ((*ptr == ':') && (*(ptr+1) == '/') && (*(ptr+2) == '/')) {
-			if (!provider_name)
-				provider_name = dup;
-			*ptr = 0;
-			cnc_string = ptr + 3;
-		}
+	gda_connection_string_split (cnc_string, &real_cnc, &real_provider, &user, &pass);
+	if (!real_cnc) {
+		g_free (user);
+		g_free (pass);
+		g_free (real_provider);
+		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR, 
+			     _("Malformed connection string '%s'"), cnc_string);
+		return NULL;
 	}
-	
-	if (!provider_name) {
+
+	if (!provider_name && !real_provider) {
 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_PROVIDER_NOT_FOUND_ERROR, 
 			     _("No provider specified"));
-		g_free (dup);
+		g_free (user);
+		g_free (pass);
+		g_free (real_cnc);
 		return NULL;
 	}
 
+	if (!auth_string && user) {
+		gchar *s1;
+		s1 = gda_rfc1738_encode (user);
+		if (pass) {
+			gchar *s2;
+			s2 = gda_rfc1738_encode (pass);
+			real_auth_string = g_strdup_printf ("USERNAME=%s;PASSWORD=%s", s1, s2);
+			g_free (s2);
+		}
+		else
+			real_auth_string = g_strdup_printf ("USERNAME=%s", s1);
+		g_free (s1);
+	}
+
 	/* try to find provider */
-	if (provider_name) {
+	if (provider_name || real_provider) {
 		GdaServerProvider *prov;
 
-		prov = gda_config_get_provider_object (provider_name, error);
+		prov = gda_config_get_provider_object (provider_name ? provider_name : real_provider, error);
 		if (prov) {
 			if (PROV_CLASS (prov)->create_connection) {
 				cnc = PROV_CLASS (prov)->create_connection (prov);
-				if (cnc) {
-					g_object_set (G_OBJECT (cnc), "provider_obj", prov, NULL);
-					if (cnc_string && *cnc_string)
-						g_object_set (G_OBJECT (cnc), "cnc_string", cnc_string, NULL);
-					g_object_set (G_OBJECT (cnc), "auth_string", auth_string, "options", options, NULL);
-				}
+				if (cnc) 
+					g_object_set (G_OBJECT (cnc), 
+						      "provider_obj", prov,
+						      "cnc_string", real_cnc,
+						      "auth_string", auth_string ? auth_string : real_auth_string, 
+						      "options", options, NULL);
 			}
 			else 
-				cnc = (GdaConnection *) g_object_new (GDA_TYPE_CONNECTION, "provider_obj", prov,
-								      "cnc-string", cnc_string, "auth_string", auth_string,
+				cnc = (GdaConnection *) g_object_new (GDA_TYPE_CONNECTION, 
+								      "provider_obj", prov,
+								      "cnc-string", real_cnc, 
+								      "auth_string", auth_string ? auth_string : real_auth_string, 
 								      "options", options, NULL);
 			
 			/* open the connection */
@@ -546,7 +616,10 @@
 		}
 	}	
 
-	g_free (dup);
+	g_free (real_cnc);
+	g_free (user);
+	g_free (pass);
+	g_free (real_provider);
 
 	return cnc;
 }
@@ -631,13 +704,13 @@
 								   NULL, NULL, NULL))
 		cnc->priv->is_open = TRUE;
 	else {
-		GList *events;
+		const GList *events;
 		
 		events = gda_connection_get_events (cnc);
 		if (events) {
 			GList *l;
 
-			for (l = events; l; l = l->next) {
+			for (l = g_list_last ((GList*) events); l; l = l->prev) {
 				GdaConnectionEvent *event;
 
 				event = GDA_CONNECTION_EVENT (l->data);
@@ -647,7 +720,6 @@
 							     gda_connection_event_get_description (event));
 				}
 			}
-			g_list_free (events);
 		}
 
 		cnc->priv->is_open = FALSE;
@@ -660,11 +732,11 @@
 
 	if (cnc->priv->is_open) {
 #ifdef GDA_DEBUG_signal
-        g_print (">> 'CONN_OPENED' from %s\n", __FUNCTION__);
+		g_print (">> 'CONN_OPENED' from %s\n", __FUNCTION__);
 #endif
-        g_signal_emit (G_OBJECT (cnc), gda_connection_signals[CONN_OPENED], 0);
+		g_signal_emit (G_OBJECT (cnc), gda_connection_signals[CONN_OPENED], 0);
 #ifdef GDA_DEBUG_signal
-        g_print ("<< 'CONN_OPENED' from %s\n", __FUNCTION__);
+		g_print ("<< 'CONN_OPENED' from %s\n", __FUNCTION__);
 #endif
 	}
 
@@ -1071,7 +1143,7 @@
 	g_return_if_fail (cnc->priv);
 	
 	if (cnc->priv->events_list != NULL) {
-		gda_connection_event_list_free (cnc->priv->events_list);
+		g_list_foreach (cnc->priv->events_list, (GFunc) g_object_unref, NULL);
 		cnc->priv->events_list =  NULL;
 	}
 }
@@ -3026,20 +3098,19 @@
  * @cnc: a #GdaConnection.
  *
  * Retrieves a list of the last errors occurred during the connection. The returned list is
- * chronologically ordered such as that the most recent event is the #GdaConnectionEvent of the last node. 
+ * chronologically ordered such as that the most recent event is the #GdaConnectionEvent of the first node.
  *
- * The caller is responsible for freeing the returned list (but not the contents of each node) using
- * g_list_free().
- * 
- * Returns: a new GList of #GdaConnectionEvent.
+ * Warning: the @cnc object may change the list if connection events occur
+ *
+ * Returns: a GList of #GdaConnectionEvent objects (the list should not be modified)
  */
-GList *
+const GList *
 gda_connection_get_events (GdaConnection *cnc)
 {
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
 	g_return_val_if_fail (cnc->priv, FALSE);
 
-	return g_list_reverse (cnc->priv->events_list);
+	return cnc->priv->events_list;
 }
 
 /**

Modified: trunk/libgda/gda-connection.h
==============================================================================
--- trunk/libgda/gda-connection.h	(original)
+++ trunk/libgda/gda-connection.h	Tue Apr 15 09:26:32 2008
@@ -158,7 +158,7 @@
 GdaConnectionEvent  *gda_connection_add_event_string     (GdaConnection *cnc, const gchar *str, ...);
 void                 gda_connection_add_events_list      (GdaConnection *cnc, GList *events_list);
 void                 gda_connection_clear_events_list    (GdaConnection *cnc);
-GList               *gda_connection_get_events           (GdaConnection *cnc);
+const GList         *gda_connection_get_events           (GdaConnection *cnc);
 
 GdaSqlParser        *gda_connection_create_parser        (GdaConnection *cnc);
 GObject             *gda_connection_batch_execute        (GdaConnection *cnc,

Modified: trunk/libgda/gda-meta-struct.c
==============================================================================
--- trunk/libgda/gda-meta-struct.c	(original)
+++ trunk/libgda/gda-meta-struct.c	Tue Apr 15 09:26:32 2008
@@ -24,6 +24,7 @@
 #include <libgda/gda-util.h>
 #include <sql-parser/gda-sql-parser.h>
 #include <sql-parser/gda-sql-statement.h>
+#include <sql-parser/gda-statement-struct-util.h>
 
 /*
  * Main static functions
@@ -43,10 +44,14 @@
 
 
 struct _GdaMetaStructPrivate {
-	GHashTable *index; /* key = [catalog].[schema].[name], value = a GdaMetaDbObject */
+	GHashTable *index; /* key = [catalog].[schema].[name], value = a GdaMetaDbObject. Note: catalog, schema and name 
+			    * are case sensitive (and don't have any double quote around them) */
 	guint       features;
 };
 
+static GdaMetaDbObject *_meta_struct_get_db_object (GdaMetaStruct *mstruct, 
+						    const GValue *catalog, const GValue *schema, const GValue *name);
+
 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);
@@ -234,7 +239,7 @@
 			g_value_set_string ((catalog = gda_value_new (G_TYPE_STRING)), tmp_obj->obj_catalog);
 			g_value_set_string ((schema = gda_value_new (G_TYPE_STRING)), tmp_obj->obj_schema);
 			g_value_set_string ((name = gda_value_new (G_TYPE_STRING)), tmp_obj->obj_name);
-			ref_obj = gda_meta_struct_get_db_object (mstruct, catalog, schema, name);
+			ref_obj = _meta_struct_get_db_object (mstruct, catalog, schema, name);
 			if (!ref_obj) {
 				gchar *str;
 				ref_obj = g_new0 (GdaMetaDbObject, 1);
@@ -295,12 +300,20 @@
  * Creates a new #GdaMetaDbObject structure in @mstruct to represent the database object (of type @type)
  * which can be uniquely identified as @catalog  schema @name.
  *
+ * If @catalog is not %NULL, then @schema should not be %NULL.
+ *
  * If @catalog is %NULL and @schema is not %NULL, then the database object will be the one which is
  * "visible" by default (that is which can be accessed only by its short @name name).
  *
  * If both @catalog and @schema are %NULL, then the database object will be the one which 
  * can be accessed by its @schema  name name.
  *
+ * Important note: @catalog, @schema and @name must respect the following convention:
+ * <itemizedlist>
+ *   <listitem><para>be surrounded by double quotes for a case sensitive search</para></listitem>
+ *   <listitem><para>otherwise they will be converted to lower case for search</para></listitem>
+ * </itemizedlist>
+ *
  * Returns: the #GdaMetaDbObject corresponding to the database object if no error occurred, or %NULL
  */
 GdaMetaDbObject *
@@ -310,60 +323,86 @@
 {
 	GdaMetaDbObject *dbo = NULL;
 	GdaMetaDbObjectType real_type = type;
-	GValue *real_catalog = NULL, *real_schema = NULL, *real_name = NULL;
 	GValue *short_name = NULL, *full_name=NULL, *owner=NULL;
+	GValue *icatalog = NULL, *ischema = NULL, *iname = NULL; /* GValue with identifiers ready to be compared */
 
+	/* checks */
 	g_return_val_if_fail (GDA_IS_META_STORE (store), NULL);
 	g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), NULL);
 	g_return_val_if_fail (name && (G_VALUE_TYPE (name) == G_TYPE_STRING), NULL);
+	g_return_val_if_fail (!catalog || (catalog && schema), 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);
+
+	/* create ready to compare strings for catalog, schema and name */
+	gchar *schema_s, *name_s;
+	if (_split_identifier_string (g_value_dup_string (name), &schema_s, &name_s)) {
+		g_value_take_string ((iname = gda_value_new (G_TYPE_STRING)), _identifier_unquote (name_s));
+		if (schema_s)
+			g_value_take_string ((ischema = gda_value_new (G_TYPE_STRING)), _identifier_unquote (schema_s));
+	}
+	else
+		g_value_take_string ((iname = gda_value_new (G_TYPE_STRING)), 
+				     _identifier_unquote (g_value_dup_string (name)));
+	if (catalog)
+		g_value_take_string ((icatalog = gda_value_new (G_TYPE_STRING)), 
+				     _identifier_unquote (g_value_dup_string (catalog)));
+	if (schema && !ischema) 
+		g_value_take_string ((ischema = gda_value_new (G_TYPE_STRING)), 
+				     _identifier_unquote (g_value_dup_string (schema)));
 
 	if (!catalog) {
 		if (schema) {
 			g_return_val_if_fail (schema && (G_VALUE_TYPE (schema) == G_TYPE_STRING), NULL);
-			if (! determine_db_object_from_schema_and_name (mstruct, store, &real_type, &real_catalog, 
+			if (! determine_db_object_from_schema_and_name (mstruct, store, &real_type, &icatalog, 
 									&short_name, &full_name, &owner,
-									schema, name)) {
+									ischema, iname)) {
 				g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR,
 					     _("Could not find object named '%s.%s'"), 
 					     g_value_get_string (schema), g_value_get_string (name));
+				gda_value_free (ischema);
+				gda_value_free (iname);
 				return NULL;
 			}
-			catalog = real_catalog;
 		}
 		else {
-			if (! determine_db_object_from_short_name (mstruct, store, &real_type, &real_catalog, 
-								   &real_schema, &real_name, 
-								   &short_name, &full_name, &owner, name)) {
+			GValue *real_name = NULL;
+			if (! determine_db_object_from_short_name (mstruct, store, &real_type, &icatalog, 
+								   &ischema, &real_name, 
+								   &short_name, &full_name, &owner, iname)) {
 				g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR,
 					     _("Could not find object named '%s'"), g_value_get_string (name));
+				gda_value_free (iname);
 				return NULL;
 			}
-			if (real_name)
-				name = real_name;
-			catalog = real_catalog;
-			schema = real_schema;
+			if (real_name) {
+				gda_value_free (iname);
+				iname = real_name;
+			}
 		}
 	}
 	else if (type == GDA_META_DB_UNKNOWN) {
-		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);
-
 		if (! determine_db_object_from_missing_type (mstruct, store, &real_type, &short_name, &full_name, &owner,
-							     catalog, schema, name)) {
+							     icatalog, ischema, iname)) {
 			g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR,
 				     _("Could not find object named '%s.%s.%s'"), g_value_get_string (catalog),
 				     g_value_get_string (schema), g_value_get_string (name));
+			gda_value_free (icatalog);
+			gda_value_free (ischema);
+			gda_value_free (iname);
 			return NULL;
 		}
 	}
 	type = real_type;
+
+	/* at this point icatalog, ischema and iname are NOT NULL */
 	
 	/* create new GdaMetaDbObject or get already existing one */
-	dbo = gda_meta_struct_get_db_object (mstruct, catalog, schema, name);
+	dbo = _meta_struct_get_db_object (mstruct, icatalog, ischema, iname);
 	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_catalog = g_strdup (g_value_get_string (icatalog));
+		dbo->obj_schema = g_strdup (g_value_get_string (ischema));
 		dbo->obj_name = g_strdup (g_value_get_string (name));
 		if (short_name)
 			dbo->obj_short_name = g_strdup (g_value_get_string (short_name));
@@ -372,14 +411,18 @@
 		if (owner)
 			dbo->obj_owner = g_strdup (g_value_get_string (owner));
 	}
-	else if (dbo->obj_type == type)
+	else if (dbo->obj_type == type) {
+		if (icatalog) gda_value_free (icatalog);
+		if (ischema) gda_value_free (ischema);
+		gda_value_free (iname);
 		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));
+			     g_value_get_string (icatalog), g_value_get_string (ischema), 
+			     g_value_get_string (iname));
 		dbo = NULL;
 		goto onerror;
 	}
@@ -395,7 +438,7 @@
 		gint nrows;
 		GdaMetaView *mv;
 
-		model = gda_meta_store_extract (store, sql, error, "tc", catalog, "ts", schema, "tname", name, NULL);
+		model = gda_meta_store_extract (store, sql, error, "tc", icatalog, "ts", ischema, "tname", iname, NULL);
 		if (!model) 
 			goto onerror;
 		nrows = gda_data_model_get_n_rows (model);
@@ -403,8 +446,8 @@
 			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));
+				     g_value_get_string (icatalog), g_value_get_string (ischema), 
+				     g_value_get_string (iname));
 			goto onerror;
 		}
 		
@@ -454,7 +497,7 @@
 		GdaDataModel *model;
 		gint i, nrows;
 
-		model = gda_meta_store_extract (store, sql, error, "tc", catalog, "ts", schema, "tname", name, NULL);
+		model = gda_meta_store_extract (store, sql, error, "tc", icatalog, "ts", ischema, "tname", iname, NULL);
 		if (!model) 
 			goto onerror;
 
@@ -463,8 +506,8 @@
 			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));
+				     g_value_get_string (icatalog), g_value_get_string (ischema), 
+				     g_value_get_string (iname));
 			goto onerror;
 		}
 		if (!dbo->obj_short_name)
@@ -503,7 +546,7 @@
 
 		/* primary key */
 		sql = "SELECT 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);
+		model = gda_meta_store_extract (store, sql, error, "tc", icatalog, "ts", ischema, "tname", iname, NULL);
 		if (!model) 
 			goto onerror;
 
@@ -512,9 +555,9 @@
 			GdaDataModel *pkmodel;
 			sql = "SELECT column_name FROM _key_column_usage WHERE table_catalog = ##cc::string AND table_schema = ##cs::string AND table_name = ##tname::string AND constraint_name = ##cname::string ORDER BY ordinal_position";
 			pkmodel = gda_meta_store_extract (store, sql, error, 
-							  "cc", catalog,
-							  "cs", schema,
-							  "tname", name,
+							  "cc", icatalog,
+							  "cs", ischema,
+							  "tname", iname,
 							  "cname", gda_data_model_get_value_at (model, 0, 0), NULL);
 			if (!pkmodel) {
 				g_object_unref (model);
@@ -545,7 +588,7 @@
 		/* foreign keys */
 		if (mstruct->priv->features & GDA_META_STRUCT_FEATURE_FOREIGN_KEYS) { 
 			sql = "SELECT ref_table_catalog, ref_table_schema, ref_table_name FROM _referential_constraints WHERE 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);
+			model = gda_meta_store_extract (store, sql, error, "tc", icatalog, "ts", ischema, "tname", iname, NULL);
 			if (!model) 
 				goto onerror;
 			
@@ -559,7 +602,7 @@
 				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);
+				tfk->depend_on = _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);
@@ -594,9 +637,9 @@
 	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));
+		str = g_strdup_printf ("%s.%s.%s", g_value_get_string (icatalog), 
+				       g_value_get_string (ischema), 
+				       g_value_get_string (iname));
 		g_hash_table_insert (mstruct->priv->index, str, dbo);
 	}
 	if (dbo && (mstruct->priv->features & GDA_META_STRUCT_FEATURE_FOREIGN_KEYS)) {
@@ -641,20 +684,20 @@
 			}
 		}
 	}
-	if (real_catalog) gda_value_free (real_catalog);
-	if (real_schema) gda_value_free (real_schema);
-	if (real_name) gda_value_free (real_name);
+	gda_value_free (icatalog);
+	gda_value_free (ischema);
+	gda_value_free (iname);
 	if (short_name)	gda_value_free (short_name);
 	if (full_name)	gda_value_free (full_name);
 	if (owner) gda_value_free (owner);
 	return dbo;
 
  onerror:
+	gda_value_free (icatalog);
+	gda_value_free (ischema);
+	gda_value_free (iname);
 	if (dbo)
 		gda_meta_db_object_free (dbo);
-	if (real_catalog) gda_value_free (real_catalog);
-	if (real_schema) gda_value_free (real_schema);
-	if (real_name) gda_value_free (real_name);
 	if (short_name)	gda_value_free (short_name);
 	if (full_name)	gda_value_free (full_name);
 	if (owner) gda_value_free (owner);
@@ -788,30 +831,16 @@
 	return TRUE;
 }
 
-/**
- * gda_meta_struct_get_db_object
- * @mstruct: a #GdaMetaStruct object
- * @catalog: the catalog the object belongs to (as a G_TYPE_STRING GValue), or %NULL
- * @schema: the schema the object belongs to (as a G_TYPE_STRING GValue), or %NULL
- * @name: the object's name (as a G_TYPE_STRING GValue), not %NULL
- *
- * Tries to locate the #GdaMetaDbObject structure representing the database object named after
- * @catalog, @schema and @name.
- *
- * If one or both of @catalog and @schema are %NULL, and more than one database object matches the name, then
- * the return value is also %NULL.
- *
- * Returns: the #GdaMetaDbObject or %NULL if not found
+/*
+ * Same as gda_meta_struct_get_db_object except that @catalog, @schema and @name are ready to be
+ * compared (no need to double quote)
  */
-GdaMetaDbObject *
-gda_meta_struct_get_db_object (GdaMetaStruct *mstruct, const GValue *catalog, const GValue *schema, const GValue *name)
+static GdaMetaDbObject *
+_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 (GDA_IS_META_STRUCT (mstruct), NULL);
-	g_return_val_if_fail (name && (G_VALUE_TYPE (name) == G_TYPE_STRING), NULL);
-
 	if (catalog && schema) {
 		g_return_val_if_fail (G_VALUE_TYPE (catalog) == G_TYPE_STRING, NULL);
 		g_return_val_if_fail (G_VALUE_TYPE (schema) == G_TYPE_STRING, NULL);
@@ -861,6 +890,50 @@
 }
 
 /**
+ * gda_meta_struct_get_db_object
+ * @mstruct: a #GdaMetaStruct object
+ * @catalog: the catalog the object belongs to (as a G_TYPE_STRING GValue), or %NULL
+ * @schema: the schema the object belongs to (as a G_TYPE_STRING GValue), or %NULL
+ * @name: the object's name (as a G_TYPE_STRING GValue), not %NULL
+ *
+ * Tries to locate the #GdaMetaDbObject structure representing the database object named after
+ * @catalog, @schema and @name.
+ *
+ * If one or both of @catalog and @schema are %NULL, and more than one database object matches the name, then
+ * the return value is also %NULL.
+ *
+ * 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)
+{
+	GdaMetaDbObject *dbo;
+	GValue *icatalog = NULL, *ischema = NULL, *iname = NULL; /* GValue with identifiers ready to be compared */
+
+	g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), NULL);
+	g_return_val_if_fail (name && (G_VALUE_TYPE (name) == G_TYPE_STRING), NULL);
+	g_return_val_if_fail (!catalog || (catalog && schema), 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);
+
+	/* prepare identifiers */
+	g_value_take_string ((iname = gda_value_new (G_TYPE_STRING)), _identifier_unquote (g_value_dup_string (name)));
+	if (catalog)
+		g_value_take_string ((icatalog = gda_value_new (G_TYPE_STRING)), 
+				     _identifier_unquote (g_value_dup_string (catalog)));
+	if (schema) 
+		g_value_take_string ((ischema = gda_value_new (G_TYPE_STRING)), 
+				     _identifier_unquote (g_value_dup_string (schema)));
+
+	dbo = _meta_struct_get_db_object (mstruct, icatalog, ischema, iname);
+	if (icatalog) gda_value_free (icatalog);
+	if (ischema) gda_value_free (ischema);
+	gda_value_free (iname);
+
+	return dbo;
+}
+
+/**
  * gda_meta_struct_get_table_column
  * @mstruct: a #GdaMetaStruct object
  * @table: the #GdaMetaTable structure to find the column for
@@ -1250,18 +1323,21 @@
  next:
 	{
 		/* treat the case where name is in fact <schema>.<name> */
-		const gchar *sname;
-		gchar *ptr;
-		sname = g_value_get_string (name);
-		for (ptr = (gchar *) sname; *ptr && (*ptr != '.'); ptr++);
-		if (*ptr == '.') {
-			gchar *tmp = g_strdup (sname);
+		gchar *obj_schema;
+		gchar *obj_name;
+		if (_split_identifier_string (g_strdup ((gchar *) g_value_get_string (name)), &obj_schema, &obj_name)) {
 			GValue *sv, *nv;
 			gboolean retval;
-			ptr = tmp + (ptr - sname);
-			*ptr = 0;
-			g_value_set_string ((sv = gda_value_new (G_TYPE_STRING)), tmp);
-			g_value_set_string ((nv = gda_value_new (G_TYPE_STRING)), ptr + 1);
+			if (!obj_schema) {
+				g_free (obj_name);
+				return FALSE;
+			}
+			if (!obj_name) {
+				g_free (obj_schema);
+				return FALSE;
+			}
+			g_value_take_string ((sv = gda_value_new (G_TYPE_STRING)), _identifier_unquote (obj_schema));
+			g_value_take_string ((nv = gda_value_new (G_TYPE_STRING)), _identifier_unquote (obj_name));
 			retval = determine_db_object_from_schema_and_name (mstruct, store, in_out_type, out_catalog, 
 									   out_short_name, out_full_name, out_owner, 
 									   sv, nv);
@@ -1273,7 +1349,6 @@
 				gda_value_free (sv);
 				gda_value_free (nv);
 			}
-			g_free (tmp);
 			return retval;
 		}
 	}

Modified: trunk/libgda/gda-meta-struct.h
==============================================================================
--- trunk/libgda/gda-meta-struct.h	(original)
+++ trunk/libgda/gda-meta-struct.h	Tue Apr 15 09:26:32 2008
@@ -117,6 +117,10 @@
  * Struture to hold information about each object
  * which can be created in the internal GdaMetaStore's connection.
  * It is available for tables, views, triggers, ...
+ *
+ * Note: @obj_catalog, @obj_schema, @obj_name, @obj_short_name and @obj_full_name are case sensitive:
+ *       one must call _identifier_needs_quotes() to know is it is necessary to surround by double quotes
+ *       before using in an SQL statement
  */
 typedef struct {
 	GdaMetaDbObjectType     obj_type;

Modified: trunk/libgda/gda-quark-list.c
==============================================================================
--- trunk/libgda/gda-quark-list.c	(original)
+++ trunk/libgda/gda-quark-list.c	Tue Apr 15 09:26:32 2008
@@ -1,5 +1,5 @@
 /* GDA Common Library
- * Copyright (C) 1998 - 2007 The GNOME Foundation.
+ * Copyright (C) 1998 - 2008 The GNOME Foundation.
  *
  * Authors:
  *	Rodrigo Moya <rodrigo gnome-db org>
@@ -22,6 +22,7 @@
  */
 
 #include <libgda/gda-quark-list.h>
+#include <libgda/gda-util.h>
 #include <glib/ghash.h>
 #include <glib/gmem.h>
 #include <glib/gmessages.h>
@@ -84,9 +85,17 @@
 
 /**
  * gda_quark_list_new_from_string
- * @string: a connection string.
+ * @string: a string.
  *
- * Creates a new #GdaQuarkList given a connection string.
+ * Creates a new #GdaQuarkList given a string.
+ *
+ * @string must be a semi-colon separated list of "&lt;key&gt;=&lt;value&gt;" strings (for example
+ * "DB_NAME=notes;USERNAME=alfred"). Each key and value must respect the RFC 1738 recommendations: the
+ * <constant>&lt;&gt;&quot;#%{}|\^~[]&apos;`;/?:@=&amp;</constant> and space characters are replaced by 
+ * <constant>&quot;%%ab&quot;</constant> where
+ * <constant>ab</constant> is the hexadecimal number corresponding to the character (for example the
+ * "DB_NAME=notes;USERNAME=al%%20fred" string will specify a username as "al fred"). If this formalism
+ * is not respected, then some unexpected results may occur.
  *
  * Returns: the newly created #GdaQuarkList.
  */
@@ -158,17 +167,23 @@
 /**
  * gda_quark_list_add_from_string
  * @qlist: a #GdaQuarkList.
- * @string: a connection string.
+ * @string: a string.
  * @cleanup: whether to cleanup the previous content or not.
  *
+ * @string must be a semi-colon separated list of "&lt;key&gt;=&lt;value&gt;" strings (for example
+ * "DB_NAME=notes;USERNAME=alfred"). Each key and value must respect the RFC 1738 recommendations: the
+ * <constant>&lt;&gt;&quot;#%{}|\^~[]&apos;`;/?:@=&amp;</constant> and space characters are replaced by 
+ * <constant>&quot;%%ab&quot;</constant> where
+ * <constant>ab</constant> is the hexadecimal number corresponding to the character (for example the
+ * "DB_NAME=notes;USERNAME=al%%20fred" string will specify a username as "al fred"). If this formalism
+ * is not respected, then some unexpected results may occur.
+ *
  * Adds new key->value pairs from the given @string. If @cleanup is
  * set to %TRUE, the previous contents will be discarded before adding
  * the new pairs.
  */
 void
-gda_quark_list_add_from_string (GdaQuarkList *qlist,
-				const gchar *string,
-				gboolean cleanup)
+gda_quark_list_add_from_string (GdaQuarkList *qlist, const gchar *string, gboolean cleanup)
 {
 	gchar **arr;
 
@@ -189,10 +204,10 @@
 			if (pair && pair[0]) {
 				gchar *name = pair[0];
 				gchar *value = pair[1];
-				g_hash_table_insert (qlist->hash_table,
-						     (gpointer) g_strdup (name),
-						     (gpointer) g_strdup (value));
-				g_strfreev (pair);
+				gda_rfc1738_decode (name);
+				gda_rfc1738_decode (value);
+				g_hash_table_insert (qlist->hash_table, (gpointer) name, (gpointer) value);
+				g_free (pair);
 			}
 			n++;
 		}

Modified: trunk/libgda/gda-util.c
==============================================================================
--- trunk/libgda/gda-util.c	(original)
+++ trunk/libgda/gda-util.c	Tue Apr 15 09:26:32 2008
@@ -39,6 +39,7 @@
 #include <locale.h>
 #endif
 #include <libgda/sql-parser/gda-sql-statement.h>
+#include <sql-parser/gda-statement-struct-util.h>
 
 #include <libgda/binreloc/gda-binreloc.h>
 
@@ -998,3 +999,591 @@
 	}
 	return TRUE;
 }
+
+
+static char *copy_ident (const gchar *ident);
+static char *concat_ident (const gchar *prefix, const gchar *ident);
+
+static gchar *sql_start_words[] = {
+	"ALTER",
+	"SELECT",
+	"INSERT",
+	"DELETE",
+	"UPDATE",
+	"CREATE",
+	"DROP",
+	"ALTER",
+	"COMMENT",
+	"BEGIN",
+	"COMMIT",
+	"ROLLBACK"
+};
+
+static gchar *sql_middle_words[] = {
+	"FROM",
+	"INNER",
+	"JOIN",
+	"LEFT",
+	"OUTER",
+	"RIGHT",
+	"OUTER",
+	"WHERE",
+	"HAVING",
+	"LIMIT",
+	"AND",
+	"OR",
+	"NOT",
+	"SET"
+};
+
+/**
+ * gda_completion_list_get
+ * @cnc: a #GdaConnection object
+ * @sql: a partial SQL statement which is the context of the completion proposal
+ * @start: starting position within @sql of the "token" to complete (starts at 0)
+ * @end: ending position within @sql of the "token" to complete
+ *
+ * Creates an array of strings (terminated by a %NULL) corresponding to possible completions.
+ * If no completion is available, then the returned array contains just one NULL entry, and
+ * if it was not possible to try to compute a completions list, then %NULL is returned.
+ *
+ * Returns: a new array of strings, or %NULL (use g_strfreev() to free the returned array)
+ */
+gchar **
+gda_completion_list_get (GdaConnection *cnc, const gchar *sql, gint start, gint end)
+{
+	GArray *compl = NULL;
+	gchar *text;
+
+	if (!cnc) 
+		return NULL;
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+	if (end < start)
+		return NULL;
+
+	/* init */
+	compl = g_array_new (TRUE, TRUE, sizeof (gchar *));
+	text = g_new0 (gchar, end - start + 2);
+	memcpy (text, sql + start, end - start + 1);
+	text [end - start + 1] = 0;
+
+	if (start == 0) {
+		/* 
+		 * start of a statement => complete with SQL start of statement words 
+		 */
+		gint len;
+		gint i;
+		len = strlen (text);
+		for (i = 0; i < (sizeof (sql_start_words) / sizeof (gchar*)); i++) {
+			gint clen = strlen (sql_start_words[i]);
+			if (!g_ascii_strncasecmp (sql_start_words[i], text, MIN (clen, len))) {
+				gchar *str;
+				str = g_strdup (sql_start_words[i]);
+				g_array_append_val (compl, str);
+			}
+		}
+		goto compl_finished;
+	}
+	
+	if (!*text)
+		goto compl_finished;
+	
+	gchar *obj_schema, *obj_name;
+	GValue *schema_value = NULL;
+	
+	if (!_split_identifier_string (g_strdup (text), &obj_schema, &obj_name) && 
+	    !_split_identifier_string (g_strdup_printf ("%s\"", text), &obj_schema, &obj_name)) {
+		if (text [strlen(text) - 1] == '.') {
+			obj_schema = g_strdup (text);
+			obj_schema [strlen(text) - 1] = 0;
+			obj_name = g_strdup ("");
+		}
+		else
+			goto compl_finished;
+	}
+	
+	if (*obj_name == '"') 
+		_remove_quotes (obj_name);
+	
+	if (obj_schema) {
+		if (*obj_schema == '"') 
+			_remove_quotes (obj_schema);
+		g_value_take_string ((schema_value = gda_value_new (G_TYPE_STRING)), obj_schema);
+	}
+	
+	/*
+	 * complete with "table" or "schema.table"
+	 */
+	GdaDataModel *model;
+	GdaMetaStore *store;
+	store = gda_connection_get_meta_store (cnc);
+	if (schema_value)
+		model = gda_meta_store_extract (store, 
+						"SELECT table_name FROM _tables WHERE table_schema = ##schema::string", 
+						NULL, "schema", schema_value, NULL);
+	else
+		model = gda_meta_store_extract (store, 
+						"SELECT table_name FROM _tables WHERE table_short_name != table_full_name",
+						NULL);
+	if (model) {
+		gint i, nrows;
+		gint len = strlen (obj_name);
+		
+		nrows = gda_data_model_get_n_rows (model);
+		for (i = 0; i < nrows; i++) {
+			const gchar *tname;
+			tname = g_value_get_string (gda_data_model_get_value_at (model, 0, i));
+			if (!strncmp (tname, obj_name, len)) {
+				gchar *str;
+				if (schema_value) 
+					str = concat_ident (obj_schema, tname);
+				else
+					str = copy_ident (tname);
+				g_array_append_val (compl, str);
+			}
+		}
+		g_object_unref (model);
+	}
+	
+	/*
+	 * complete with "table.column"
+	 */
+	model = NULL;
+	if (!schema_value)
+		model = gda_meta_store_extract (store, 
+						"SELECT column_name FROM _columns", NULL);
+	if (model) {
+		gint i, nrows;
+		gint len = strlen (obj_name);
+		
+		nrows = gda_data_model_get_n_rows (model);
+		for (i = 0; i < nrows; i++) {
+			const gchar *cname;
+			cname = g_value_get_string (gda_data_model_get_value_at (model, 0, i));
+			if (!strncmp (cname, obj_name, len)) {
+				gchar *str;
+				str = copy_ident (cname);
+				g_array_append_val (compl, str);
+			}
+		}
+		g_object_unref (model);
+	}
+	
+	/*
+	 * complete with "schema.table"
+	 */
+	model = NULL;
+	if (! schema_value)
+		model = gda_meta_store_extract (store, "SELECT schema_name FROM _schemata", NULL);
+	if (model) {
+		gint i, nrows;
+		gint len = strlen (obj_name);
+		
+		nrows = gda_data_model_get_n_rows (model);
+		for (i = 0; i < nrows; i++) {
+			const gchar *tname;
+			tname = g_value_get_string (gda_data_model_get_value_at (model, 0, i));
+			if (!strncmp (tname, obj_name, len)) {
+				char *str;
+				GdaDataModel *m2;
+				str = copy_ident (tname);
+				
+				m2 = gda_meta_store_extract (store, 
+							     "SELECT table_name FROM _tables WHERE table_schema = ##schema::string", 
+							     NULL, "schema", gda_data_model_get_value_at (model, 0, i), 
+							     NULL);
+				if (m2) {
+					gint i2, nrows2;
+					nrows2 = gda_data_model_get_n_rows (m2);
+					for (i2 = 0; i2 < nrows2; i2++) {
+						gchar *str2;
+						tname = g_value_get_string (gda_data_model_get_value_at (m2, 0, i2));
+						str2 = concat_ident (str, tname);
+						g_array_append_val (compl, str2);
+					}
+					
+					g_object_unref (m2);
+				}
+				free (str);
+			}
+		}
+		g_object_unref (model);
+		if (compl->len > 0)
+			goto compl_finished;
+	}
+	
+	if (schema_value)
+		gda_value_free (schema_value);
+	g_free (obj_name);
+	
+	/* 
+	 * middle of a statement and no completion yet => complete with SQL statement words 
+	 */
+	{
+		gint len;
+		gint i;
+		len = strlen (text);
+		for (i = 0; i < (sizeof (sql_middle_words) / sizeof (gchar*)); i++) {
+			gint clen = strlen (sql_middle_words[i]);
+			if (!g_ascii_strncasecmp (sql_middle_words[i], text, MIN (clen, len))) {
+				gchar *str;
+				str = g_strdup (sql_middle_words[i]);
+				g_array_append_val (compl, str);
+			}
+		}
+	}
+	
+ compl_finished:
+	g_free (text);
+	if (compl) {
+		gchar **ptr;
+		ptr = (gchar**) compl->data;
+		g_array_free (compl, FALSE);
+		return ptr;
+	}
+	else
+		return NULL;
+}
+
+
+static char *
+copy_ident (const gchar *ident)
+{
+	char *str;
+	gint tlen = strlen (ident);
+	if (_identifier_needs_quotes (ident)) {
+		str = malloc (sizeof (char) * (tlen + 3));
+		*str = '"';
+		strcpy (str+1, ident);
+		str [tlen + 1] = '"';
+		str [tlen + 2] = 0;
+	}
+	else {
+		str = malloc (sizeof (char) * (tlen + 1));
+		strcpy (str, ident);		
+	}
+	return str;
+}
+
+static char *
+concat_ident (const char *prefix, const gchar *ident)
+{
+	char *str;
+	gint tlen = strlen (ident);
+	gint plen = 0;
+
+	if (prefix)
+		plen = strlen (prefix) + 1;
+
+	if (_identifier_needs_quotes (ident)) {
+		str = malloc (sizeof (char) * (plen + tlen + 3));
+		if (prefix) {
+			strcpy (str, prefix);
+			str [plen - 1] = '.';
+			str [plen] = '"';
+			strcpy (str + plen + 1, ident);
+		}
+		else {
+			*str = '"';
+			strcpy (str+1, ident);
+		}
+		str [plen + tlen + 1] = '"';
+		str [plen + tlen + 2] = 0;
+	}
+	else {
+		str = malloc (sizeof (char) * (plen + tlen + 1));
+		if (prefix) {
+			strcpy (str, prefix);
+			str [plen - 1] = '.';
+			strcpy (str + plen, ident);
+		}
+		else
+			strcpy (str, ident);
+	}
+	return str;
+}
+
+/*
+ *  RFC 1738 defines that these characters should be escaped, as well
+ *  any non-US-ASCII character or anything between 0x00 - 0x1F.
+ */
+static char rfc1738_unsafe_chars[] =
+{
+    (char) 0x3C,               /* < */
+    (char) 0x3E,               /* > */
+    (char) 0x22,               /* " */
+    (char) 0x23,               /* # */
+    (char) 0x25,               /* % */
+    (char) 0x7B,               /* { */
+    (char) 0x7D,               /* } */
+    (char) 0x7C,               /* | */
+    (char) 0x5C,               /* \ */
+    (char) 0x5E,               /* ^ */
+    (char) 0x7E,               /* ~ */
+    (char) 0x5B,               /* [ */
+    (char) 0x5D,               /* ] */
+    (char) 0x60,               /* ` */
+    (char) 0x27,               /* ' */
+    (char) 0x20                /* space */
+};
+
+static char rfc1738_reserved_chars[] =
+{
+    (char) 0x3b,               /* ; */
+    (char) 0x2f,               /* / */
+    (char) 0x3f,               /* ? */
+    (char) 0x3a,               /* : */
+    (char) 0x40,               /* @ */
+    (char) 0x3d,               /* = */
+    (char) 0x26                /* & */
+};
+
+/**
+ * gda_rfc1738_encode
+ * @string: a string to encode 
+ *
+ * Encodes @string using the RFC 1738 recommendations: the
+ * <constant>&lt;&gt;&quot;#%{}|\^~[]&apos;`;/?:@=&amp;</constant> and space characters are replaced by 
+ * <constant>&quot;%%ab&quot;</constant> where
+ * <constant>ab</constant> is the hexadecimal number corresponding to the character.
+ *
+ * Returns: a new string
+ */
+gchar *
+gda_rfc1738_encode (const gchar *string)
+{
+	gchar *ret, *wptr;
+	const gchar *rptr;
+	gint i;
+
+	if (!string)
+		return NULL;
+	if (!*string)
+		return g_strdup ("");
+
+	ret = g_new0 (gchar, (strlen (string) * 3) + 1);
+	for (wptr = ret, rptr = string; *rptr; rptr++) {
+		gboolean enc = FALSE;
+
+		/* RFC 1738 defines these chars as unsafe */
+		for (i = 0; i < sizeof (rfc1738_reserved_chars) / sizeof (char); i++) {
+			if (*rptr == rfc1738_reserved_chars [i]) {
+				enc = TRUE;
+				break;
+			}
+		}
+		if (!enc) {
+			for (i = 0; i < sizeof (rfc1738_unsafe_chars) / sizeof (char); i++) {
+				if (*rptr == rfc1738_unsafe_chars [i]) {
+					enc = TRUE;
+					break;
+				}
+			}
+		}
+		if (!enc) {
+			/* RFC 1738 says any control chars (0x00-0x1F) are encoded */
+			if ((unsigned char) *rptr <= (unsigned char) 0x1F) 
+				enc = TRUE;
+			/* RFC 1738 says 0x7f is encoded */
+			else if (*rptr == (char) 0x7F)
+				enc = TRUE;
+			/* RFC 1738 says any non-US-ASCII are encoded */
+			else if (((unsigned char) *rptr >= (unsigned char) 0x80))
+				enc = TRUE;
+		}
+
+		if (enc) {
+			sprintf (wptr, "%%%02x", (unsigned char) *rptr);
+			wptr += 3;
+		}
+		else {
+			*wptr = *rptr;
+			wptr++;
+		}
+	}
+	return ret;
+}
+
+/**
+ * gda_rfc1738_decode
+ * @string: a string to encode 
+ *
+ * Decodes @string using the RFC 1738 recommendations: the
+ * <constant>&lt;&gt;&quot;#%{}|\^~[]&apos;`;/?:@=&amp;</constant> and space characters are replaced by 
+ * <constant>&quot;%%ab&quot;</constant> where
+ * <constant>ab</constant> is the hexadecimal number corresponding to the character.
+ *
+ * @string should respect the RFC 1738 encoding. If this is not the case (for example if there
+ * is a "%2z" because 2z is not an hexadecimal value), then the part with the problem
+ * is not decoded, and the function returns FALSE.
+ *
+ * @string is decoded in place, no new string gets created.
+ *
+ * Returns: TRUE if no error occurred.
+ */
+gboolean
+gda_rfc1738_decode (gchar *string)
+{
+	gchar *wptr, *rptr;
+	gboolean retval = TRUE;
+
+	if (!string || !*string)
+		return TRUE;
+
+	for (wptr = rptr = string; *rptr; wptr++, rptr++) {
+		*wptr = *rptr;
+		if (*rptr == '%') {
+			rptr++;
+			if ((((*rptr >= 'A') && (*rptr <= 'F')) ||
+			     ((*rptr >= 'a') && (*rptr <= 'f')) ||
+			     ((*rptr >= '0') && (*rptr <= '9'))) &&
+			    (((rptr[1] >= 'A') && (rptr[1] <= 'F')) ||
+			     ((rptr[1] >= 'a') && (rptr[1] <= 'f')) ||
+			     ((rptr[1] >= '0') && (rptr[1] <= '9')))) {
+				*wptr = 0;
+				if ((*rptr >= 'A') && (*rptr <= 'F'))
+					*wptr = *rptr - 'A' + 10;
+				else if ((*rptr >= 'a') && (*rptr <= 'f'))
+					*wptr = *rptr - 'a' + 10;
+				else
+					*wptr = *rptr - '0';
+				rptr++;
+				*wptr = *wptr << 4; /* multiply by 16 */
+				if (((*rptr >= 'A') && (*rptr <= 'F')) ||
+				    ((*rptr >= 'a') && (*rptr <= 'f')) ||
+				    ((*rptr >= '0') && (*rptr <= '9'))) {
+					if ((*rptr >= 'A') && (*rptr <= 'F'))
+						*wptr += *rptr - 'A' + 10;
+					else if ((*rptr >= 'a') && (*rptr <= 'f'))
+						*wptr += *rptr - 'a' + 10;
+					else
+						*wptr += *rptr - '0';
+				}
+			}
+			else {
+				/* error */
+				retval = FALSE;
+				rptr--;
+			}
+		}
+	}
+	*wptr = 0;
+	return TRUE;
+}
+
+
+/**
+ * gda_dsn_split
+ * @string: a string in the "[&lt;username&gt;[:&lt;password&gt;] ]&lt;DSN&gt;" form
+ * @out_dsn: a place to store the new string containing the &lt;DSN&gt; part
+ * @out_username: a place to store the new string containing the &lt;username&gt; part
+ * @out_password: a place to store the new string containing the &lt;password&gt; part
+ * @error: a place to store errors, or %NULL
+ *
+ * Extract the DSN, username and password from @string. in @string, the various parts are strings
+ * which are expected to be encoded using an RFC 1738 compliant encoding. If they are specified, 
+ * the returned username and password strings are correclty decoded.
+ *
+ * @out_username and @out_password may be set to %NULL depending on @string's format.
+ */
+void
+gda_dsn_split (const gchar *string, gchar **out_dsn, gchar **out_username, gchar **out_password)
+{
+	const gchar *ptr;
+	g_return_if_fail (string);
+	g_return_if_fail (out_dsn);
+	g_return_if_fail (out_username);
+	g_return_if_fail (out_password);
+
+	*out_dsn = NULL;
+	*out_username = NULL;
+	*out_password = NULL;
+	for (ptr = string; *ptr; ptr++) {
+		if (*ptr == '@') {
+			const gchar *tmp = ptr;
+			*out_dsn = g_strdup (ptr+1);
+			for (ptr = string; ptr < tmp; ptr++) {
+				if (*ptr == ':') {
+					*out_username = g_strndup (string, ptr - string);
+					*out_password = g_strndup (ptr+1, tmp - ptr - 1);
+				}
+			}
+			if (!*out_username) 
+				*out_username = g_strndup (string, tmp - string);
+			break;
+		}
+	}
+	if (!*out_dsn)
+		*out_dsn = g_strdup (string);
+
+	/* RFC 1738 decode username and password strings */
+	gda_rfc1738_decode (*out_username);
+	gda_rfc1738_decode (*out_password);
+}
+
+/**
+ * gda_connection_string_split
+ * @string: a string in the "[&lt;provider&gt;://][&lt;username&gt;[:&lt;password&gt;] ]&lt;connection_params&gt;" form
+ * @out_cnc_params: a place to store the new string containing the &lt;connection_params&gt; part
+ * @out_provider: a place to store the new string containing the &lt;provider&gt; part
+ * @out_username: a place to store the new string containing the &lt;username&gt; part
+ * @out_password: a place to store the new string containing the &lt;password&gt; part
+ * @error: a place to store errors, or %NULL
+ *
+ * Extract the provider, connection parameters, username and password from @string. 
+ * in @string, the various parts are strings
+ * which are expected to be encoded using an RFC 1738 compliant encoding. If they are specified, 
+ * the returned provider, username and password strings are correclty decoded.
+ */
+void
+gda_connection_string_split (const gchar *string, gchar **out_cnc_params, gchar **out_provider, 
+			     gchar **out_username, gchar **out_password)
+{
+	const gchar *ptr;
+	const gchar *ap;
+	g_return_if_fail (string);
+	g_return_if_fail (out_cnc_params);
+	g_return_if_fail (out_provider);
+	g_return_if_fail (out_username);
+	g_return_if_fail (out_password);
+
+	*out_cnc_params = NULL;
+	*out_provider = NULL;
+	*out_username = NULL;
+	*out_password = NULL;
+	for (ap = ptr = string; *ptr; ptr++) {
+		if ((ap == string) && (*ptr == '/') && (ptr[1] == '/')) {
+			if ((ptr == string) || (ptr[-1] != ':')) {
+				g_free (*out_cnc_params); *out_cnc_params = NULL;
+				g_free (*out_provider); *out_provider = NULL;
+				g_free (*out_username); *out_username = NULL;
+				g_free (*out_password); *out_password = NULL;
+				return;
+			}
+			*out_provider = g_strndup (string, ptr - string - 1);
+			ap = ptr+2;
+			ptr++;
+		}
+
+		if (*ptr == '@') {
+			const gchar *tmp = ptr;
+			*out_cnc_params = g_strdup (ptr+1);
+			for (ptr = ap; ptr < tmp; ptr++) {
+				if (*ptr == ':') {
+					*out_username = g_strndup (ap, ptr - ap);
+					*out_password = g_strndup (ptr+1, tmp - ptr - 1);
+				}
+			}
+			if (!*out_username) 
+				*out_username = g_strndup (ap, tmp - ap);
+			break;
+		}
+	}
+	if (!*out_cnc_params)
+		*out_cnc_params = g_strdup (ap);
+
+	/* RFC 1738 decode provider, username and password strings */
+	gda_rfc1738_decode (*out_provider);
+	gda_rfc1738_decode (*out_username);
+	gda_rfc1738_decode (*out_password);
+}

Modified: trunk/libgda/gda-util.h
==============================================================================
--- trunk/libgda/gda-util.h	(original)
+++ trunk/libgda/gda-util.h	Tue Apr 15 09:26:32 2008
@@ -45,6 +45,7 @@
 gchar       *gda_default_unescape_string (const gchar *string);
 guint        gda_identifier_hash (const gchar *id);
 gboolean     gda_identifier_equal (const gchar *id1, const gchar *id2);
+gchar      **gda_completion_list_get (GdaConnection *cnc, const gchar *text, gint start, gint end);
 
 /*
  * Param & model utilities
@@ -67,6 +68,16 @@
 gboolean     gda_compute_dml_statements (GdaConnection *cnc, GdaStatement *select_stmt, gboolean require_pk, 
 					 GdaStatement **insert, GdaStatement **update, GdaStatement **delete, 
 					 GError **error);
+
+/*
+ * DSN and connection string manipulations
+ */
+gchar       *gda_rfc1738_encode          (const gchar *string);
+gboolean     gda_rfc1738_decode          (gchar *string);
+void         gda_dsn_split               (const gchar *string, gchar **out_dsn, 
+					  gchar **out_username, gchar **out_password);
+void         gda_connection_string_split (const gchar *string, gchar **out_cnc_params, gchar **out_provider, 
+					  gchar **out_username, gchar **out_password);
 G_END_DECLS
 
 #endif

Modified: trunk/libgda/sql-parser/gda-statement-struct-parts.c
==============================================================================
--- trunk/libgda/sql-parser/gda-statement-struct-parts.c	(original)
+++ trunk/libgda/sql-parser/gda-statement-struct-parts.c	Tue Apr 15 09:26:32 2008
@@ -32,6 +32,15 @@
  * Sql expression
  *
  */
+
+/**
+ * gda_sql_expr_new
+ * @parent: a #GdaSqlStatementInsert, #GdaSqlStatementUpdate, #GdaSqlSelectField, #GdaSqlSelectTarget, #GdaSqlOperation
+ * 
+ * Creates a new #GdaSqlField structure, using @parent as its parent part.
+ *
+ * Returns: a new #GdaSqlField structure.
+ */
 GdaSqlExpr *
 gda_sql_expr_new (GdaSqlAnyPart *parent)
 {
@@ -42,6 +51,13 @@
 	return expr;
 }
 
+/**
+ * gda_sql_expr_free
+ * @expr: a #GdaSqlExpr to be freed.
+ * 
+ * Frees a #GdaSqlExpr structure and its members.
+ *
+ */
 void
 gda_sql_expr_free (GdaSqlExpr *expr)
 {
@@ -69,6 +85,14 @@
 	g_free (expr);
 }
 
+/**
+ * gda_sql_expr_copy
+ * @expr: a #GdaSqlExpr
+ * 
+ * Creates a new #GdaSqlExpr structure initated with the values stored in @expr.
+ *
+ * Returns: a new #GdaSqlExpr structure.
+ */
 GdaSqlExpr *
 gda_sql_expr_copy (GdaSqlExpr *expr)
 {
@@ -110,6 +134,15 @@
 	return copy;
 }
 
+/**
+ * gda_sql_expr_serialize
+ * @expr: a #GdaSqlExpr structure
+ * 
+ * Creates a new string representing a field. You need to free the returned string
+ * using g_free();
+ *
+ * Returns: a new string with the name of the field or "null" in case @expr is invalid.
+ */
 gchar *
 gda_sql_expr_serialize (GdaSqlExpr *expr)
 {
@@ -174,6 +207,15 @@
 	return str;
 }
 
+/**
+ * gda_sql_expr_take_select
+ * @expr: a #GdaSqlExpr structure
+ * @stmt: a #GdaSqlStatement holding the #GdaSqlStatementSelect to take from
+ * 
+ * Sets the expression's parent to the #GdaSqlStatementSelect holded by @stmt. After
+ * calling this function @stmt is freed.
+ *
+ */
 void
 gda_sql_expr_take_select (GdaSqlExpr *expr, GdaSqlStatement *stmt)
 {
@@ -187,8 +229,13 @@
 	}
 }
 
-/*
- * Any Table's field
+/**
+ * gda_sql_field_new
+ * @parent: a #GdaSqlStatementSelect, #GdaSqlStatementInsert, #GdaSqlStatementDelete, #GdaSqlStatementUpdate
+ * 
+ * Creates a new #GdaSqlField structure, using @parent as its parent part.
+ *
+ * Returns: a new #GdaSqlField structure.
  */
 GdaSqlField *
 gda_sql_field_new (GdaSqlAnyPart *parent)
@@ -200,6 +247,13 @@
 	return field;
 }
 
+/**
+ * gda_sql_field_free
+ * @field: a #GdaSqlField to be freed.
+ * 
+ * Frees a #GdaSqlField structure and its members.
+ *
+ */
 void
 gda_sql_field_free (GdaSqlField *field)
 {
@@ -210,6 +264,14 @@
 	g_free (field);
 }
 
+/**
+ * gda_sql_field_copy
+ * @field: a #GdaSqlAnyPart
+ * 
+ * Creates a new GdaSqlField structure initated with the values stored in @field.
+ *
+ * Returns: a new #GdaSqlField structure.
+ */
 GdaSqlField *
 gda_sql_field_copy (GdaSqlField *field)
 {
@@ -224,6 +286,15 @@
 	return copy;
 }
 
+/**
+ * gda_sql_field_serialize
+ * @field: a #GdaSqlField structure
+ * 
+ * Creates a new string representing a field. You need to free the returned string
+ * using g_free();
+ *
+ * Returns: a new string with the name of the field or "null" in case @field is invalid.
+ */
 gchar *
 gda_sql_field_serialize (GdaSqlField *field)
 {
@@ -233,18 +304,31 @@
 		return _json_quote_string (field->field_name);
 }
 
+/**
+ * gda_sql_field_take_name
+ * @field: a #GdaSqlField structure
+ * @value: a #GValue holding a string to take from
+ * 
+ * Sets the field's name using the string holded by @value. When call, @value is freed using
+ * #gda_value_free().
+ *
+ */
 void
 gda_sql_field_take_name (GdaSqlField *field, GValue *value)
 {
 	if (value) {
 		field->field_name = g_value_dup_string (value);
-		g_value_reset (value);
-		g_free (value);
+		gda_value_free (value);
 	}
 }
 
-/*
- * Structure to hold one table
+/**
+ * gda_sql_table_new
+ * @parent: a #GdaSqlStatementSelect, #GdaSqlStatementInsert, #GdaSqlStatementDelete, #GdaSqlStatementUpdate
+ * 
+ * Creates a new #GdaSqlTable structure, using @parent as its parent part.
+ *
+ * Returns: a new #GdaSqlTable structure.
  */
 GdaSqlTable *
 gda_sql_table_new (GdaSqlAnyPart *parent)
@@ -256,6 +340,12 @@
 	return table;
 }
 
+/**
+ * gda_sql_table_free
+ * @table: a #GdaSqlTable structure to be freed
+ * 
+ * Frees a #GdaSqlTable structure and its members.
+ */
 void
 gda_sql_table_free (GdaSqlTable *table)
 {
@@ -266,6 +356,14 @@
 	g_free (table);
 }
 
+/**
+ * gda_sql_table_copy
+ * @table: a #GdaSqlTable structure to be copied
+ * 
+ * Creates a new #GdaSqlTable structure initated with the values stored in @table.
+ *
+ * Returns: a new #GdaSqlTable structure.
+ */
 GdaSqlTable *
 gda_sql_table_copy (GdaSqlTable *table)
 {
@@ -280,6 +378,15 @@
 	return copy;
 }
 
+/**
+ * gda_sql_table_serialize
+ * @field: a #GdaSqlTable structure
+ * 
+ * Creates a new string representing a table. You need to free the returned string
+ * using g_free();
+ *
+ * Returns: a new string with the name of the field or "null" in case @table is invalid.
+ */
 gchar *
 gda_sql_table_serialize (GdaSqlTable *table)
 {
@@ -289,21 +396,32 @@
 		return _json_quote_string (table->table_name);
 }
 
+/**
+ * gda_sql_table_take_name
+ * @field: a #GdaSqlTable structure
+ * @value: a #GValue holding a string to take from
+ * 
+ * Sets the table's name using the string holded by @value. When call, @value is freed using
+ * #gda_value_free().
+ *
+ */
 void
 gda_sql_table_take_name (GdaSqlTable *table, GValue *value)
 {
 	if (value) {
 		table->table_name = g_value_dup_string (value);
-		g_value_reset (value);
-		g_free (value);
+		gda_value_free (value);
 	}
 }
 
-
-/*
- * A function with any number of arguments
+/**
+ * gda_sql_function_new
+ * @parent: a #GdaSqlExpr structure
+ * 
+ * Creates a new #GdaSqlFunction structure initated.
+ *
+ * Returns: a new #GdaSqlFunction structure.
  */
-
 GdaSqlFunction *
 gda_sql_function_new (GdaSqlAnyPart *parent)
 {
@@ -314,6 +432,12 @@
 	return function;
 }
 
+/**
+ * gda_sql_function_free
+ * @function: a #GdaSqlFunction structure to be freed
+ * 
+ * Frees a #GdaSqlFunction structure and its members.
+ */
 void
 gda_sql_function_free (GdaSqlFunction *function)
 {
@@ -328,6 +452,14 @@
 	g_free (function);
 }
 
+/**
+ * gda_sql_function_copy
+ * @function: a #GdaSqlFunction structure to be copied
+ * 
+ * Creates a new #GdaSqlFunction structure initated with the values stored in @function.
+ *
+ * Returns: a new #GdaSqlFunction structure.
+ */
 GdaSqlFunction *
 gda_sql_function_copy (GdaSqlFunction *function)
 {
@@ -353,6 +485,15 @@
 	return copy;
 }
 
+/**
+ * gda_sql_function_serialize
+ * @function: a #GdaSqlFunction structure
+ * 
+ * Creates a new string representing a function. You need to free the returned string
+ * using g_free();
+ *
+ * Returns: a new string with the description of the function or "null" in case @function is invalid.
+ */
 gchar *
 gda_sql_function_serialize (GdaSqlFunction *function)
 {	
@@ -391,16 +532,33 @@
 	}
 }
 
+/**
+ * gda_sql_function_take_name
+ * @function: a #GdaSqlFunction structure
+ * @value: a #GValue holding a string to take from
+ * 
+ * Sets the function's name using the string holded by @value. When call, @value is freed using
+ * #gda_value_free().
+ *
+ */
 void
 gda_sql_function_take_name (GdaSqlFunction *function, GValue *value)
 {
 	if (value) {
 		function->function_name = g_value_dup_string (value);
-		g_value_reset (value);
-		g_free (value);
+		gda_value_free (value);
 	}
 }
 
+/**
+ * gda_sql_function_take_name
+ * @function: a #GdaSqlFunction structure
+ * @args: a #GSList to take from
+ * 
+ * Sets the function's arguments to point to @args, then sets the
+ * list's data elements' parent to @function.
+ *
+ */
 void gda_sql_function_take_args_list (GdaSqlFunction *function, GSList *args)
 {
 	GSList *list;
@@ -410,8 +568,13 @@
 		gda_sql_any_part_set_parent (list->data, function);
 }
 
-/*
- * An operation
+/**
+ * gda_sql_operation_new
+ * @parent: a #GdaSqlExpr structure
+ * 
+ * Creates a new #GdaSqlOperation structure and sets its parent to @parent.
+ *
+ * Returns: a new #GdaSqlOperation structure.
  */
 GdaSqlOperation *
 gda_sql_operation_new (GdaSqlAnyPart *parent)
@@ -423,6 +586,12 @@
 	return operation;
 }
 
+/**
+ * gda_sql_operation_free
+ * @operation: a #GdaSqlOperation structure to be freed
+ * 
+ * Frees a #GdaSqlOperation structure and its members.
+ */
 void
 gda_sql_operation_free (GdaSqlOperation *operation)
 {
@@ -435,6 +604,14 @@
 	g_free (operation);
 }
 
+/**
+ * gda_sql_operation_copy
+ * @operation: a #GdaSqlOperation structure to be copied
+ * 
+ * Creates a new #GdaSqlOperation structure initated with the values stored in @operation.
+ *
+ * Returns: a new #GdaSqlOperation structure.
+ */
 GdaSqlOperation *
 gda_sql_operation_copy (GdaSqlOperation *operation)
 {
@@ -456,6 +633,15 @@
 	return copy;
 }
 
+/**
+ * gda_sql_operation_serialize
+ * @operation: a #GdaSqlOperation structure
+ * 
+ * Creates a new string representing an operator. You need to free the returned string
+ * using g_free();
+ *
+ * Returns: a new string with the description of the operator or "null" in case @operation is invalid.
+ */
 gchar *
 gda_sql_operation_serialize (GdaSqlOperation *operation)
 {	
@@ -492,6 +678,15 @@
 	}
 }
 
+/**
+ * gda_sql_operation_operator_to_string
+ * @op: a #GdaSqlOperation structure
+ * 
+ * Returns a constant string representing a operator name. You don't need to free 
+ * the returned string.
+ *
+ * Returns: a string with the operator's name or NULL in case @op is invalid.
+ */
 const gchar *
 gda_sql_operation_operator_to_string (GdaSqlOperator op)
 {
@@ -562,6 +757,14 @@
 	}
 }
 
+/**
+ * gda_sql_operator_from_string
+ * @op: a #GdaSqlOperation structure
+ * 
+ * Returns #GdaSqlOperator that correspond with the string @op.
+ *
+ * Returns: #GdaSqlOperator
+ */
 GdaSqlOperator 
 gda_sql_operation_operator_from_string (const gchar *op)
 {
@@ -631,8 +834,13 @@
 	return 0;
 }
 
-/*
- * A CASE expression
+/**
+ * gda_sql_case_new
+ * @parent: a #GdaSqlExpr structure
+ * 
+ * Creates a new #GdaSqlCase structure and sets its parent to @parent.
+ *
+ * Returns: a new #GdaSqlCase structure.
  */
 GdaSqlCase *
 gda_sql_case_new (GdaSqlAnyPart *parent)
@@ -644,6 +852,12 @@
 	return sc;
 }
 
+/**
+ * gda_sql_case_free
+ * @sc: a #GdaSqlCase structure to be freed
+ * 
+ * Frees a #GdaSqlCase structure and its members.
+ */
 void
 gda_sql_case_free (GdaSqlCase *sc)
 {
@@ -662,6 +876,14 @@
 	g_free (sc);
 }
 
+/**
+ * gda_sql_case_copy
+ * @sc: a #GdaSqlCase structure to be copied
+ * 
+ * Creates a new #GdaSqlCase structure initated with the values stored in @sc.
+ *
+ * Returns: a new #GdaSqlCase structure.
+ */
 GdaSqlCase *
 gda_sql_case_copy (GdaSqlCase *sc)
 {
@@ -693,6 +915,15 @@
 	return copy;
 }
 
+/**
+ * gda_sql_case_serialize
+ * @sc: a #GdaSqlCase structure
+ * 
+ * Creates a new string representing a CASE clausure. You need to free the returned string
+ * using g_free();
+ *
+ * Returns: a new string with the description of the CASE clausure or "null" in case @sc is invalid.
+ */
 gchar *
 gda_sql_case_serialize (GdaSqlCase *sc)
 {	
@@ -741,8 +972,14 @@
 	}
 }
 
-/*
- * Any expression in a SELECT ... before the FROM
+/**
+ * gda_sql_select_field_new
+ * @parent: a #GdaSqlStatementSelect structure
+ * 
+ * Creates a new #GdaSqlSelectField structure and sets its parent to @parent. A
+ * #GdaSqlSelectField is any expression in SELECT statements before the FROM clausure.
+ *
+ * Returns: a new #GdaSqlSelectField structure.
  */
 GdaSqlSelectField *
 gda_sql_select_field_new (GdaSqlAnyPart *parent)
@@ -754,6 +991,12 @@
 	return field;
 }
 
+/**
+ * gda_sql_select_field_free
+ * @field: a #GdaSqlSelectField structure to be freed
+ * 
+ * Frees a #GdaSqlSelectField structure and its members.
+ */
 void
 gda_sql_select_field_free (GdaSqlSelectField *field)
 {
@@ -768,6 +1011,14 @@
 	g_free (field);
 }
 
+/**
+ * gda_sql_select_field_copy
+ * @field: a #GdaSqlSelectField structure to be copied
+ * 
+ * Creates a new #GdaSqlSelectField structure initated with the values stored in @field.
+ *
+ * Returns: a new #GdaSqlSelectField structure.
+ */
 GdaSqlSelectField *
 gda_sql_select_field_copy (GdaSqlSelectField *field)
 {
@@ -792,6 +1043,15 @@
 	return copy;
 }
 
+/**
+ * gda_sql_select_field_serialize
+ * @field: a #GdaSqlSelectField structure
+ * 
+ * Creates a new string representing an expresion used as field in a SELECT statement
+ * before the FROM clausure.
+ *
+ * Returns: a new string with the description of the expression or "null" in case @field is invalid.
+ */
 gchar *
 gda_sql_select_field_serialize (GdaSqlSelectField *field)
 {	
@@ -834,6 +1094,14 @@
 	}
 }
 
+/**
+ * gda_sql_select_field_take_expr
+ * @field: a #GdaSqlSelectField structure
+ * @expr: a #GdaSqlExpr to take from
+ * 
+ * Sets the expression field in the #GdaSqlSelectField structure to point to @expr
+ * and modify it to sets its parent to @field.
+ */
 void
 gda_sql_select_field_take_expr (GdaSqlSelectField *field, GdaSqlExpr *expr)
 {
@@ -844,6 +1112,15 @@
 		_split_identifier_string (g_value_dup_string (expr->value), &(field->table_name), &(field->field_name));
 }
 
+/**
+ * gda_sql_select_field_take_star_value
+ * @field: a #GdaSqlSelectField structure
+ * @value: a #GValue to take from
+ * 
+ * Sets the expression field's value in the #GdaSqlSelectField structure to point to @value;
+ * after this @field is the owner of @value.
+ *
+ */
 void
 gda_sql_select_field_take_star_value (GdaSqlSelectField *field, GValue *value)
 {
@@ -853,18 +1130,32 @@
 	}
 }
 
+/**
+ * gda_sql_select_field_take_alias
+ * @field: a #GdaSqlSelectField structure
+ * @alias: a #GValue to take from
+ * 
+ * Sets the 'as' field's string in the #GdaSqlSelectField structure. @alias is freed
+ * after call this function.
+ *
+ */
 void
 gda_sql_select_field_take_alias (GdaSqlSelectField *field, GValue *alias)
 {
 	if (alias) {
 		field->as = g_value_dup_string (alias);
-		g_value_reset (alias);
-		g_free (alias);
+		gda_value_free (alias);
 	}
 }
 
-/*
- * Any TARGET ... in a SELECT statement
+/**
+ * gda_sql_select_target_new
+ * @parent: a #GdaSqlSelectFrom
+ * 
+ * Creates a new #GdaSqlSelectTarget structure and sets its parent to @parent. A
+ * #GdaSqlSelectTarget is the table in a SELECT statement.
+ *
+ * Returns: a new #GdaSqlSelectTarget structure.
  */
 GdaSqlSelectTarget *
 gda_sql_select_target_new (GdaSqlAnyPart *parent)
@@ -876,6 +1167,12 @@
 	return target;
 }
 
+/**
+ * gda_sql_select_target_free
+ * @target: a #GdaSqlSelectTarget structure to be freed
+ * 
+ * Frees a #GdaSqlSelectTarget structure and its members.
+ */
 void
 gda_sql_select_target_free (GdaSqlSelectTarget *target)
 {
@@ -889,6 +1186,14 @@
 	g_free (target);
 }
 
+/**
+ * gda_sql_select_target_copy
+ * @target: a #GdaSqlSelectTarget structure to be copied
+ * 
+ * Creates a new #GdaSqlSelectTarget structure initated with the values stored in @target.
+ *
+ * Returns: a new #GdaSqlSelectTarget structure.
+ */
 GdaSqlSelectTarget *
 gda_sql_select_target_copy (GdaSqlSelectTarget *target)
 {
@@ -910,6 +1215,15 @@
 	return copy;
 }
 
+/**
+ * gda_sql_select_target_serialize
+ * @target: a #GdaSqlSelectTarget structure
+ * 
+ * Creates a new string representing a target used in a SELECT statement
+ * after the FROM clausure.
+ *
+ * Returns: a new string with the description of the expression or "null" in case @field is invalid.
+ */
 gchar *
 gda_sql_select_target_serialize (GdaSqlSelectTarget *target)
 {	
@@ -946,6 +1260,15 @@
 	}
 }
 
+/**
+ * gda_sql_select_target_take_table_name
+ * @target: a #GdaSqlSelectTarget structure
+ * @value: a #GValue to take from
+ * 
+ * Sets the target's name using the string stored in @value and the expression
+ * to set its value to point to value; after call this function the target owns
+ * @value, then you must not free it.
+ */
 void
 gda_sql_select_target_take_table_name (GdaSqlSelectTarget *target, GValue *value)
 {
@@ -956,6 +1279,14 @@
 	}
 }
 
+/**
+ * gda_sql_select_target_take_table_name
+ * @target: a #GdaSqlSelectTarget structure
+ * @stmt: a #GValue to take from
+ * 
+ * Sets the target to be a SELECT subquery setting target's expression to use
+ * @stmt; after call this function the target owns @stmt, then you must not free it.
+ */
 void
 gda_sql_select_target_take_select (GdaSqlSelectTarget *target, GdaSqlStatement *stmt)
 {
@@ -965,19 +1296,35 @@
 	}
 }
 
+/**
+ * gda_sql_select_target_take_table_alias
+ * @target: a #GdaSqlSelectTarget structure
+ * @alias: a #GValue holding the alias string to take from
+ * 
+ * Sets the target alias (AS) to the string holded by @alias; after call
+ * this function @alias is freed.
+ */
 void
 gda_sql_select_target_take_alias (GdaSqlSelectTarget *target, GValue *alias)
 {
 	if (alias) {
 		target->as = g_value_dup_string (alias);
-		g_value_reset (alias);
-		g_free (alias);
+		gda_value_free (alias);
 	}
 }
 
 /*
  * Any JOIN ... in a SELECT statement
  */
+
+/**
+ * gda_sql_select_join_new
+ * @parent: a #GdaSqlSelectFrom
+ * 
+ * Creates a new #GdaSqlSelectJoin structure and sets its parent to @parent.
+ *
+ * Returns: a new #GdaSqlSelectJoin structure
+ */
 GdaSqlSelectJoin *
 gda_sql_select_join_new (GdaSqlAnyPart *parent)
 {
@@ -988,6 +1335,12 @@
 	return join;
 }
 
+/**
+ * gda_sql_select_join_free
+ * @join: a #GdaSqlSelectJoin structure to be freed
+ * 
+ * Frees a #GdaSqlSelectJoin structure and its members.
+ */
 void
 gda_sql_select_join_free (GdaSqlSelectJoin *join)
 {
@@ -1000,6 +1353,14 @@
 	g_free (join);
 }
 
+/**
+ * gda_sql_select_join_copy
+ * @join: a #GdaSqlSelectJoin structure to be copied
+ * 
+ * Creates a new #GdaSqlSelectJoin structure initated with the values stored in @join.
+ *
+ * Returns: a new #GdaSqlSelectJoin structure.
+ */
 GdaSqlSelectJoin *
 gda_sql_select_join_copy (GdaSqlSelectJoin *join)
 {
@@ -1025,6 +1386,14 @@
 	return copy;
 }
 
+/**
+ * gda_sql_select_join_type_to_string
+ * @type: a #GdaSqlSelectJoinType structure to be copied
+ * 
+ * Creates a new string representing the join type.
+ *
+ * Returns: a string representing the Join type.
+ */
 const gchar *
 gda_sql_select_join_type_to_string (GdaSqlSelectJoinType type)
 {
@@ -1047,6 +1416,14 @@
 	}
 }
 
+/**
+ * gda_sql_select_join_serialize
+ * @join: a #GdaSqlSelectJoin structure
+ * 
+ * Creates a new string description of the join used in a SELECT statement.
+ *
+ * Returns: a new string with the description of the join or "null" in case @join is invalid.
+ */
 gchar *
 gda_sql_select_join_serialize (GdaSqlSelectJoin *join)
 {	
@@ -1099,6 +1476,15 @@
 /*
  * Any FROM ... in a SELECT statement
  */
+
+/**
+ * gda_sql_select_from_new
+ * @parent: a #GdaSqlStatementSelect
+ * 
+ * Creates a new #GdaSqlSelectFrom structure and sets its parent to @parent.
+ *
+ * Returns: a new #GdaSqlSelectFrom structure
+ */
 GdaSqlSelectFrom *
 gda_sql_select_from_new (GdaSqlAnyPart *parent)
 {
@@ -1109,6 +1495,12 @@
 	return from;
 }
 
+/**
+ * gda_sql_select_from_free
+ * @from: a #GdaSqlSelectFrom structure to be freed
+ * 
+ * Frees a #GdaSqlSelectFrom structure and its members.
+ */
 void
 gda_sql_select_from_free (GdaSqlSelectFrom *from)
 {
@@ -1126,6 +1518,14 @@
 	g_free (from);
 }
 
+/**
+ * gda_sql_select_from_copy
+ * @from: a #GdaSqlSelectFrom structure to be copied
+ * 
+ * Creates a new #GdaSqlSelectFrom structure initated with the values stored in @from.
+ *
+ * Returns: a new #GdaSqlSelectFrom structure.
+ */
 GdaSqlSelectFrom *
 gda_sql_select_from_copy (GdaSqlSelectFrom *from)
 {
@@ -1152,6 +1552,14 @@
 	return copy;
 }
 
+/**
+ * gda_sql_select_from_serialize
+ * @from: a #GdaSqlSelectFrom structure
+ * 
+ * Creates a new string description of the FROM clausure used in a SELECT statement.
+ *
+ * Returns: a new string with the description of the FROM or "null" in case @from is invalid.
+ */
 gchar *
 gda_sql_select_from_serialize (GdaSqlSelectFrom *from)
 {	
@@ -1199,6 +1607,14 @@
 	}
 }
 
+/**
+ * gda_sql_select_from_take_new_target
+ * @from: a #GdaSqlSelectFrom structure
+ * @target: a #GdaSqlSelectTarget to take from
+ * 
+ * Append @target to the targets in the FROM clausure and set @target's parent to
+ * @from; after call this function @from owns @target then you must not free it.
+ */
 void
 gda_sql_select_from_take_new_target (GdaSqlSelectFrom *from, GdaSqlSelectTarget *target)
 {
@@ -1206,6 +1622,14 @@
 	gda_sql_any_part_set_parent (target, from);
 }
 
+/**
+ * gda_sql_select_from_take_new_join
+ * @from: a #GdaSqlSelectFrom structure
+ * @join: a #GdaSqlSelectJoin to take from
+ * 
+ * Append @join to the joins in the FROM clausure and set @join's parent to
+ * @from; after call this function @from owns @join then you must not free it.
+ */
 void
 gda_sql_select_from_take_new_join  (GdaSqlSelectFrom *from, GdaSqlSelectJoin *join)
 {
@@ -1216,6 +1640,15 @@
 /*
  * Any expression in a SELECT ... after the ORDER BY
  */
+
+/**
+ * gda_sql_select_order_new
+ * @parent: a #GdaSqlStatementSelect
+ * 
+ * Creates a new #GdaSqlSelectOrder structure and sets its parent to @parent.
+ *
+ * Returns: a new #GdaSqlSelectOrder structure
+ */
 GdaSqlSelectOrder *
 gda_sql_select_order_new (GdaSqlAnyPart *parent)
 {
@@ -1226,6 +1659,12 @@
 	return order;
 }
 
+/**
+ * gda_sql_select_order_free
+ * @order: a #GdaSqlSelectOrder structure to be freed
+ * 
+ * Frees a #GdaSqlSelectOrder structure and its members.
+ */
 void
 gda_sql_select_order_free (GdaSqlSelectOrder *order)
 {
@@ -1237,6 +1676,14 @@
 	g_free (order);
 }
 
+/**
+ * gda_sql_select_order_copy
+ * @order: a #GdaSqlSelectOrder structure to be copied
+ * 
+ * Creates a new #GdaSqlSelectOrder structure initated with the values stored in @order.
+ *
+ * Returns: a new #GdaSqlSelectOrder structure.
+ */
 GdaSqlSelectOrder *
 gda_sql_select_order_copy (GdaSqlSelectOrder *order)
 {
@@ -1255,6 +1702,14 @@
 	return copy;
 }
 
+/**
+ * gda_sql_select_order_serialize
+ * @order: a #GdaSqlSelectOrder structure
+ * 
+ * Creates a new string description of the ORDER BY clausure used in a SELECT statement.
+ *
+ * Returns: a new string with the description of the ORDER BY or "null" in case @order is invalid.
+ */
 gchar *
 gda_sql_select_order_serialize (GdaSqlSelectOrder *order)
 {	

Modified: trunk/libgda/sql-parser/gda-statement-struct-util.c
==============================================================================
--- trunk/libgda/sql-parser/gda-statement-struct-util.c	(original)
+++ trunk/libgda/sql-parser/gda-statement-struct-util.c	Tue Apr 15 09:26:32 2008
@@ -83,9 +83,16 @@
 
 
         total = strlen (str);
-        g_assert (str[total-1] == delim);
-        g_memmove (str, str+1, total-2);
-        total -=2;
+        if (str[total-1] == delim) {
+		/* string is correclty terminated by a double quote */
+		g_memmove (str, str+1, total-2);
+		total -=2;
+	}
+	else {
+		/* string is _not_ correclty terminated by a double quote */
+		g_memmove (str, str+1, total-1);
+		total -=1;
+	}
         str[total] = 0;
 
         ptr = (gchar *) str;
@@ -265,6 +272,44 @@
 	return TRUE;
 }
 
+/**
+ * identifier_needs_quotes
+ */
+gboolean
+_identifier_needs_quotes (const gchar *str)
+{
+	const gchar *ptr;
+
+	g_return_val_if_fail (str, FALSE);
+	for (ptr = str; *ptr; ptr++) {
+		if (*ptr != g_ascii_tolower (*ptr))
+			return TRUE;
+	}
+	return FALSE;
+}
+
+/*
+ * Prepares @str to be compared:
+ * - if surrounded by double quotes, then just remove the quotes
+ * - otherwise convert to lower case
+ *
+ * WARNING: @str must NOT be a composed identifier (<part1>."<part2>" for example)
+ * 
+ * Returns: @str
+ */
+gchar *
+_identifier_unquote (gchar *str)
+{
+	if (*str == '"')
+		return _remove_quotes (str);
+	else {
+		gchar *ptr;
+		for (ptr = str; *ptr; ptr++)
+			*ptr = g_ascii_tolower (*ptr);
+		return str;
+	}
+}
+
 /*
  * Reuses @str and fills in @remain and @last
  *
@@ -281,7 +326,7 @@
  * if @str has the <part1>.<part2> form, then @last will contain <part2> and @remain will contain <part1>
  * if @str has the <part1> form, then @last will contain <part1> and @remain will contain NULL
  * 
- * Returns FALSE:
+ * Returns FALSE (in any case @str is also freed)
  * if @str is NULL:
  * if @str is "":
  * if @str is malformed:
@@ -305,10 +350,12 @@
 	}
 
 	len = strlen (str) - 1;
-	if (((str[len] == '"') && (str[len-1] == '.')) ||
-	    (str[len] == '.')) {
-		g_free (str);
-		return FALSE;
+	if (len > 1) {
+		if (((str[len] == '"') && (str[len-1] == '.')) ||
+		    (str[len] == '.')) {
+			g_free (str);
+			return FALSE;
+		}
 	}
 
 	if (((str[0] == '"') && (str[1] == '.')) ||

Modified: trunk/libgda/sql-parser/gda-statement-struct-util.h
==============================================================================
--- trunk/libgda/sql-parser/gda-statement-struct-util.h	(original)
+++ trunk/libgda/sql-parser/gda-statement-struct-util.h	Tue Apr 15 09:26:32 2008
@@ -1,5 +1,5 @@
 /* 
- * Copyright (C) 2007 Vivien Malerba
+ * Copyright (C) 2007 - 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
@@ -28,8 +28,11 @@
 gchar *_add_quotes (const gchar *str);
 
 gchar    *_json_quote_string (const gchar *str);
+
 gboolean  _string_is_identifier (const gchar *str);
+gboolean  _identifier_needs_quotes (const gchar *str);
 gboolean  _split_identifier_string (gchar *str, gchar **remain, gchar **last);
+gchar    *_identifier_unquote (gchar *str);
 
 /* to be removed, only here for debug */
 gchar *gda_sql_value_stringify (const GValue *value);

Modified: trunk/providers/mysql/gda-mysql-blob-op.c
==============================================================================
--- trunk/providers/mysql/gda-mysql-blob-op.c	(original)
+++ trunk/providers/mysql/gda-mysql-blob-op.c	Tue Apr 15 09:26:32 2008
@@ -165,7 +165,7 @@
 	bin = (GdaBinary *) blob;
 	if (bin->data) 
 		g_free (bin->data);
-	bin->data = g_new0 (gchar, size);
+	bin->data = g_new0 (guchar, size);
 	bin->binary_length = 0;
 
 	/* fetch blob data using C API into bin->data, and set bin->binary_length */

Modified: trunk/providers/postgres/gda-postgres-meta.c
==============================================================================
--- trunk/providers/postgres/gda-postgres-meta.c	(original)
+++ trunk/providers/postgres/gda-postgres-meta.c	Tue Apr 15 09:26:32 2008
@@ -129,10 +129,10 @@
 	"SELECT constraint_catalog, constraint_schema, constraint_name, table_catalog, table_schema, table_name, constraint_type, NULL, 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_catalog = ##cat::string AND table_schema = ##schema::string AND table_name = ##name::string AND constraint_name = ##name2::string",
 
 	/* I_STMT_REF_CONSTRAINTS */
-	"SELECT current_database(), nt.nspname, t.relname, c.conname, current_database(), nref.nspname, ref.relname, pkc.conname, CASE c.confmatchtype WHEN 'f'::\"char\" THEN 'FULL'::text WHEN 'p'::\"char\" THEN 'PARTIAL'::text WHEN 'u'::\"char\" THEN 'NONE'::text ELSE NULL::text END AS match_option, CASE c.confupdtype WHEN 'c'::\"char\" THEN 'CASCADE'::text WHEN 'n'::\"char\" THEN 'SET NULL'::text WHEN 'd'::\"char\" THEN 'SET DEFAULT'::text WHEN 'r'::\"char\" THEN 'RESTRICT'::text WHEN 'a'::\"char\" THEN 'NO ACTION'::text ELSE NULL::text END AS update_rule, CASE c.confdeltype WHEN 'c'::\"char\" THEN 'CASCADE'::text WHEN 'n'::\"char\" THEN 'SET NULL'::text WHEN 'd'::\"char\" THEN 'SET DEFAULT'::text WHEN 'r'::\"char\" THEN 'RESTRICT'::text WHEN 'a'::\"char\" THEN 'NO ACTION'::text ELSE NULL::text END AS delete_rule FROM pg_constraint c INNER JOIN pg_class t ON (c.conrelid=t.oid) INNER JOIN pg_namespace nt ON (nt.oid=t.relnamespace) INNER JOIN pg_class ref ON (c.confrelid=ref.oid) I
 NNER JOIN pg_namespace nref ON (nref.oid=ref.relnamespace) INNER JOIN pg_constraint pkc ON (c.confrelid = pkc.conrelid AND information_schema._pg_keysequal(c.confkey, pkc.conkey)) WHERE c.contype = 'f' AND current_database() = ##cat::string AND nt.nspname = ##schema::string AND t.relname = ##name::string AND c.conname = ##name2::string",
+	"SELECT current_database(), nt.nspname, t.relname, c.conname, current_database(), nref.nspname, ref.relname, pkc.conname, CASE c.confmatchtype WHEN 'f'::\"char\" THEN 'FULL'::text WHEN 'p'::\"char\" THEN 'PARTIAL'::text WHEN 'u'::\"char\" THEN 'NONE'::text ELSE NULL::text END AS match_option, CASE c.confupdtype WHEN 'c'::\"char\" THEN 'CASCADE'::text WHEN 'n'::\"char\" THEN 'SET NULL'::text WHEN 'd'::\"char\" THEN 'SET DEFAULT'::text WHEN 'r'::\"char\" THEN 'RESTRICT'::text WHEN 'a'::\"char\" THEN 'NO ACTION'::text ELSE NULL::text END AS update_rule, CASE c.confdeltype WHEN 'c'::\"char\" THEN 'CASCADE'::text WHEN 'n'::\"char\" THEN 'SET NULL'::text WHEN 'd'::\"char\" THEN 'SET DEFAULT'::text WHEN 'r'::\"char\" THEN 'RESTRICT'::text WHEN 'a'::\"char\" THEN 'NO ACTION'::text ELSE NULL::text END AS delete_rule FROM pg_constraint c INNER JOIN pg_class t ON (c.conrelid=t.oid) INNER JOIN pg_namespace nt ON (nt.oid=t.relnamespace) INNER JOIN pg_class ref ON (c.confrelid=ref.oid) I
 NNER JOIN pg_namespace nref ON (nref.oid=ref.relnamespace) INNER JOIN pg_constraint pkc ON (c.confrelid = pkc.conrelid AND information_schema._pg_keysequal(c.confkey, pkc.conkey) AND pkc.contype='p') WHERE c.contype = 'f' AND current_database() = ##cat::string AND nt.nspname = ##schema::string AND t.relname = ##name::string AND c.conname = ##name2::string",
 
 	/* I_STMT_REF_CONSTRAINTS_ALL */
-	"SELECT current_database(), nt.nspname, t.relname, c.conname, current_database(), nref.nspname, ref.relname, pkc.conname, CASE c.confmatchtype WHEN 'f'::\"char\" THEN 'FULL'::text WHEN 'p'::\"char\" THEN 'PARTIAL'::text WHEN 'u'::\"char\" THEN 'NONE'::text ELSE NULL::text END AS match_option, CASE c.confupdtype WHEN 'c'::\"char\" THEN 'CASCADE'::text WHEN 'n'::\"char\" THEN 'SET NULL'::text WHEN 'd'::\"char\" THEN 'SET DEFAULT'::text WHEN 'r'::\"char\" THEN 'RESTRICT'::text WHEN 'a'::\"char\" THEN 'NO ACTION'::text ELSE NULL::text END AS update_rule, CASE c.confdeltype WHEN 'c'::\"char\" THEN 'CASCADE'::text WHEN 'n'::\"char\" THEN 'SET NULL'::text WHEN 'd'::\"char\" THEN 'SET DEFAULT'::text WHEN 'r'::\"char\" THEN 'RESTRICT'::text WHEN 'a'::\"char\" THEN 'NO ACTION'::text ELSE NULL::text END AS delete_rule FROM pg_constraint c INNER JOIN pg_class t ON (c.conrelid=t.oid) INNER JOIN pg_namespace nt ON (nt.oid=t.relnamespace) INNER JOIN pg_class ref ON (c.confrelid=ref.oid) I
 NNER JOIN pg_namespace nref ON (nref.oid=ref.relnamespace) INNER JOIN pg_constraint pkc ON (c.confrelid = pkc.conrelid AND information_schema._pg_keysequal(c.confkey, pkc.conkey)) WHERE c.contype = 'f'",
+	"SELECT current_database(), nt.nspname, t.relname, c.conname, current_database(), nref.nspname, ref.relname, pkc.conname, CASE c.confmatchtype WHEN 'f'::\"char\" THEN 'FULL'::text WHEN 'p'::\"char\" THEN 'PARTIAL'::text WHEN 'u'::\"char\" THEN 'NONE'::text ELSE NULL::text END AS match_option, CASE c.confupdtype WHEN 'c'::\"char\" THEN 'CASCADE'::text WHEN 'n'::\"char\" THEN 'SET NULL'::text WHEN 'd'::\"char\" THEN 'SET DEFAULT'::text WHEN 'r'::\"char\" THEN 'RESTRICT'::text WHEN 'a'::\"char\" THEN 'NO ACTION'::text ELSE NULL::text END AS update_rule, CASE c.confdeltype WHEN 'c'::\"char\" THEN 'CASCADE'::text WHEN 'n'::\"char\" THEN 'SET NULL'::text WHEN 'd'::\"char\" THEN 'SET DEFAULT'::text WHEN 'r'::\"char\" THEN 'RESTRICT'::text WHEN 'a'::\"char\" THEN 'NO ACTION'::text ELSE NULL::text END AS delete_rule FROM pg_constraint c INNER JOIN pg_class t ON (c.conrelid=t.oid) INNER JOIN pg_namespace nt ON (nt.oid=t.relnamespace) INNER JOIN pg_class ref ON (c.confrelid=ref.oid) I
 NNER JOIN pg_namespace nref ON (nref.oid=ref.relnamespace) INNER JOIN pg_constraint pkc ON (c.confrelid = pkc.conrelid AND information_schema._pg_keysequal(c.confkey, pkc.conkey) AND pkc.contype='p') WHERE c.contype = 'f'",
 
 	/* I_STMT_KEY_COLUMN_USAGE */
 	"SELECT table_catalog, table_schema, table_name, constraint_name, column_name, ordinal_position FROM information_schema.key_column_usage WHERE table_catalog = ##cat::string AND table_schema = ##schema::string AND table_name = ##name::string AND constraint_name = ##name2::string",

Modified: trunk/providers/skel-implementation/capi/gda-capi-blob-op.c
==============================================================================
--- trunk/providers/skel-implementation/capi/gda-capi-blob-op.c	(original)
+++ trunk/providers/skel-implementation/capi/gda-capi-blob-op.c	Tue Apr 15 09:26:32 2008
@@ -159,7 +159,7 @@
 	bin = (GdaBinary *) blob;
 	if (bin->data) 
 		g_free (bin->data);
-	bin->data = g_new0 (gchar, size);
+	bin->data = g_new0 (guchar, size);
 	bin->binary_length = 0;
 
 	/* fetch blob data using C API into bin->data, and set bin->binary_length */

Modified: trunk/tools/command-exec.c
==============================================================================
--- trunk/tools/command-exec.c	(original)
+++ trunk/tools/command-exec.c	Tue Apr 15 09:26:32 2008
@@ -221,8 +221,6 @@
 			break;
 		case T_TEXTUAL:
 		case T_STRING:
-			local_ptr++;
-			local_nparsed -= 2;
 		default: {
 			gchar hold;
 			hold = local_ptr[local_nparsed];

Modified: trunk/tools/gda-sql.c
==============================================================================
--- trunk/tools/gda-sql.c	(original)
+++ trunk/tools/gda-sql.c	Tue Apr 15 09:26:32 2008
@@ -41,13 +41,12 @@
 #include <pwd.h>
 #endif
 
-/* options */
-gchar *pass = NULL;
-gchar *user = NULL;
+#ifdef HAVE_READLINE_READLINE_H
+#include <readline/readline.h>
+#endif
 
-gchar *dsn = NULL;
-gchar *direct = NULL;
-gchar *prov = NULL;
+/* options */
+gboolean ask_pass = FALSE;
 
 gchar *single_command = NULL;
 gchar *commandsfile = NULL;
@@ -57,13 +56,8 @@
 
 gchar *outfile = NULL;
 
-
 static GOptionEntry entries[] = {
-        { "cnc", 'c', 0, G_OPTION_ARG_STRING, &direct, "Direct connection string", "connection string"},
-        { "provider", 'p', 0, G_OPTION_ARG_STRING, &prov, "Provider name", "provider"},
-        { "dsn", 's', 0, G_OPTION_ARG_STRING, &dsn, "Data source", "DSN"},
-        { "user", 'U', 0, G_OPTION_ARG_STRING, &user, "Username", "username" },
-        { "password", 'P', 0, G_OPTION_ARG_STRING, &pass, "Password", "password" },
+        { "no-password-ask", 'p', 0, G_OPTION_ARG_NONE, &ask_pass, "Don't ast for a password when it is empty", NULL },
 
         { "output-file", 'o', 0, G_OPTION_ARG_STRING, &outfile, "Output file", "output file"},
         { "command", 'C', 0, G_OPTION_ARG_STRING, &single_command, "Run only single command (SQL or internal) and exit", "command" },
@@ -121,15 +115,14 @@
 GString *prompt = NULL;
 
 static gchar   *read_a_line (MainData *data);
-static char    *completion_func (const char *text, int state);
+static char   **completion_func (const char *text, int start, int end);
 static void     compute_prompt (MainData *data, GString *string, gboolean in_command);
 static gboolean set_output_file (MainData *data, const gchar *file, GError **error);
 static gboolean set_input_file (MainData *data, const gchar *file, GError **error);
 static void     output_data_model (MainData *data, GdaDataModel *model);
 static void     output_string (MainData *data, const gchar *str);
-static ConnectionSetting *open_connection (MainData *data, const gchar *cnc_name, const gchar *dsn,
-					   const gchar *provider, const gchar *direct, 
-					   const gchar *user, const gchar *pass, GError **error);
+static ConnectionSetting *open_connection (MainData *data, const gchar *cnc_name, const gchar *cnc_string,
+					   GError **error);
 static GdaDataModel *list_all_dsn (MainData *data);
 static GdaDataModel *list_all_providers (MainData *data);
 
@@ -149,7 +142,7 @@
 	GSList *list;
 	prompt = g_string_new ("");
 
-	context = g_option_context_new (_("Gda SQL console"));        
+	context = g_option_context_new (_("[DSN|connection string]..."));        
 	g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
         if (!g_option_context_parse (context, &argc, &argv, &error)) {
                 g_print ("Can't parse arguments: %s\n", error->message);
@@ -161,14 +154,7 @@
 	data = g_new0 (MainData, 1);
 	data->parameters = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
 	main_data = data;
-
-	/* test for command line or env. variable connection string */
-	if (!direct) {
-		if (argc >= 2)
-			direct = argv [1];
-		else 
-			direct = getenv ("GDA_SQL_CNC");
-	}
+	ask_pass = !ask_pass;
 
 	/* output file */
 	if (outfile) {
@@ -209,13 +195,6 @@
 			data->input_stream = stdin;
 	}
 
-	/* check connection parameters coherence */
-	if (direct && dsn) {
-                g_fprintf (stderr, _("DSN and connection string are exclusive\n"));
-		exit_status = EXIT_FAILURE;
-                goto cleanup;
-        }
-
 	/* welcome message */
 	if (!data->output_stream) {
 		g_print (_("Welcome to the GDA SQL console, version " PACKAGE_VERSION));
@@ -227,12 +206,43 @@
 			   "      or any query terminated by a semicolon\n\n"));
 	}
 
-        if (direct || dsn) {
+	/* open connections if specified */
+	gint i;
+	for (i = 1; i < argc; i++) {
 		/* open connection */
 		ConnectionSetting *cs;
-		cs = open_connection (data, NULL, dsn, prov, direct, user, pass, &error);
+		GdaDataSourceInfo *info = NULL;
+		gchar *str;
+
+                info = gda_config_get_dsn (argv[i]);
+		if (info)
+			str = g_strdup (info->name);
+		else
+			str = g_strdup_printf ("c%d", i-1);
+		if (!data->output_stream) 
+			g_print (_("Opening connection '%s' for: %s\n"), str, argv[i]);
+		cs = open_connection (data, str, argv[i], &error);
+		g_free (str);
 		if (!cs) {
-			g_print (_("Can't open connection: %s\n"), error && error->message ? error->message : _("No detail"));
+			g_print (_("Can't open connection %d: %s\n"), i,
+				 error && error->message ? error->message : _("No detail"));
+			exit_status = EXIT_FAILURE;
+			goto cleanup;
+		}
+	}
+	if (getenv ("GDA_SQL_CNC")) {
+		ConnectionSetting *cs;
+		gchar *str;
+		const gchar *envstr = getenv ("GDA_SQL_CNC");
+		str = g_strdup_printf ("c%d", i-1);
+		if (!data->output_stream) 
+			g_print (_("Opening connection '%s' for: %s (GDA_SQL_CNC environment variable)\n"), 
+				   str, envstr);
+		cs = open_connection (data, str, envstr, &error);
+		g_free (str);
+		if (!cs) {
+			g_print (_("Can't open connection defined by GDA_SQL_CNC: %s\n"),
+				 error && error->message ? error->message : _("No detail"));
 			exit_status = EXIT_FAILURE;
 			goto cleanup;
 		}
@@ -828,15 +838,11 @@
  * Open a connection
  */
 static ConnectionSetting*
-open_connection (MainData *data, const gchar *cnc_name, const gchar *dsn, 
-		 const gchar *provider, const gchar *direct, 
-		 const gchar *user, const gchar *pass,
-		 GError **error)
+open_connection (MainData *data, const gchar *cnc_name, const gchar *cnc_string, GError **error)
 {
 	GdaConnection *newcnc = NULL;
 	ConnectionSetting *cs = NULL;
 	static gint cncindex = 0;
-	gchar *auth_string = NULL;
 
 	if (cnc_name && ! connection_name_is_valid (cnc_name)) {
 		g_set_error (error, 0, 0,
@@ -844,40 +850,75 @@
 		return NULL;
 	}
 
-	if (user) {
-		if (pass)
-			auth_string = g_strdup_printf ("USERNAME=%s;PASSWORD=%s", user, pass);
-		else
-			auth_string = g_strdup_printf ("USERNAME=%s", user);
+	GdaDataSourceInfo *info;
+	gchar *user, *pass, *real_cnc, *real_provider, *real_auth_string = NULL;
+	gda_connection_string_split (cnc_string, &real_cnc, &real_provider, &user, &pass);
+	if (!real_cnc) {
+		g_free (user);
+		g_free (pass);
+		g_free (real_provider);
+		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR, 
+			     _("Malformed connection string '%s'"), cnc_string);
+		return NULL;
 	}
-	if (dsn) {
-                GdaDataSourceInfo *info = NULL;
-                info = gda_config_get_dsn (dsn);
-                if (!info) {
-			if (!direct)
-				g_set_error (error, 0, 0,
-					     _("DSN '%s' is not declared"), dsn);
+
+	if (ask_pass) {
+		if (user && !*user) {
+			gchar buf[80];
+			g_print (_("\tUsername for '%s': "), cnc_name);
+			if (scanf ("%80s", buf) == -1) {
+				g_free (real_cnc);
+				g_free (user);
+				g_free (pass);
+				g_free (real_provider);
+				g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR, 
+					     _("No username for '%s'"), cnc_string);
+				return NULL;
+			}
+			g_free (user);
+			user = g_strdup (buf);
 		}
-                else 
-                        newcnc = gda_connection_open_from_dsn (info->name, 
-							       auth_string ? auth_string : info->auth_string,
-							       0, error);
-        }
-        if (!newcnc && direct) {
-		/* test if @direct is not in fact a DSN, in which case use it as a DSN */
-		GdaDataSourceInfo *info = NULL;
-                info = gda_config_get_dsn (direct);
-		if (info) {
-			newcnc = gda_connection_open_from_dsn (info->name, 
-							       auth_string ? auth_string : info->auth_string,
-							       0, error);
-			dsn = direct;
-			direct = NULL;
+		if (pass && !*pass) {
+			gchar buf[80];
+			g_print (_("\tPassword for '%s': "), cnc_name);
+			if (scanf ("%80s", buf) == -1) {
+				g_free (real_cnc);
+				g_free (user);
+				g_free (pass);
+				g_free (real_provider);
+				g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR, 
+					     _("No password for '%s'"), cnc_string);
+				return NULL;
+			}
+			g_free (pass);
+			pass = g_strdup (buf);
+		}
+		if (user || pass) {
+			gchar *s1;
+			s1 = gda_rfc1738_encode (user);
+			if (pass) {
+				gchar *s2;
+				s2 = gda_rfc1738_encode (pass);
+				real_auth_string = g_strdup_printf ("USERNAME=%s;PASSWORD=%s", s1, s2);
+				g_free (s2);
+			}
+			else
+				real_auth_string = g_strdup_printf ("USERNAME=%s", s1);
+			g_free (s1);
 		}
-		else
-			newcnc = gda_connection_open_from_string (provider, direct, auth_string, 0, error);
 	}
-	g_free (auth_string);
+	
+	info = gda_config_get_dsn (real_cnc);
+	if (info && !real_provider)
+		newcnc = gda_connection_open_from_dsn (cnc_string, real_auth_string, 0, error);
+	else 
+		newcnc = gda_connection_open_from_string (NULL, cnc_string, real_auth_string, 0, error);
+	
+	g_free (real_cnc);
+	g_free (user);
+	g_free (pass);
+	g_free (real_provider);
+	g_free (real_auth_string);
 
 	if (newcnc) {
 		cs = g_new0 (ConnectionSetting, 1);
@@ -896,12 +937,12 @@
 		GdaMetaStore *store;
 		gboolean update_store = FALSE;
 
-		if (dsn) {
+		if (info) {
 			gchar *filename;
 #define LIBGDA_USER_CONFIG_DIR G_DIR_SEPARATOR_S ".libgda"
 			filename = g_strdup_printf ("%s%sgda-sql-%s.db", 
 						    g_get_home_dir (), LIBGDA_USER_CONFIG_DIR G_DIR_SEPARATOR_S,
-						    dsn);
+						    info->name);
 			if (! g_file_test (filename, G_FILE_TEST_EXISTS))
 				update_store = TRUE;
 			store = gda_meta_store_new_with_file (filename);
@@ -916,7 +957,7 @@
 		if (update_store) {
 			GError *lerror = NULL;
 			if (!data->output_stream) {
-				g_print (_("Getting database schema information, "
+				g_print (_("\tGetting database schema information, "
 					   "this may take some time... "));
 				fflush (stdout);
 			}
@@ -1654,7 +1695,7 @@
 				if (args[3])
 					pass = args[3];
 			}
-			cs = open_connection (data, args[0], args[1], NULL, args[1], user, pass, error);
+			cs = open_connection (data, args[0], args[1], error);
 			if (cs) {
 				GdaInternalCommandResult *res;
 				
@@ -2526,92 +2567,41 @@
 	return g_strsplit (str, " ", 3);
 }
 
-static char *
-completion_func (const char *text, int state)
+
+
+static char **
+completion_func (const char *text, int start, int end)
 {
-	static GArray *compl = NULL;
+#ifdef HAVE_READLINE_READLINE_H
+	ConnectionSetting *cs = main_data->current;
+	char **array;
+	gchar **gda_compl;
+	gint i, nb_compl;
 
-	if (state == 0) {
-		ConnectionSetting *cs = main_data->current;
-		/* clear any previous completion */
-		if (compl) {
-			/* don't free the contents of @array, it is freed by readline */
-			g_array_free (compl, TRUE);
-			compl = NULL;
-		}
-
-		/* compute list of possible completions. It's very simple at the moment */
-		if (!(*text)) {
-			/* no completion possible */
-		}
-		else if (cs) {
-			gchar *copy;
-
-			copy = g_strdup (text);
-			g_strchomp (copy);
-			if (*copy) {
-				const char *start;
-				gint nb_compl = 0;
-				for (start = copy + (strlen (copy) - 1); start > copy; start--)
-					if (g_ascii_isspace (*start)) {
-						start ++;
-						break;
-					}
-				GdaDataModel *model;
-				GdaMetaStore *store;
-				store = gda_connection_get_meta_store (cs->cnc);
-				model = gda_meta_store_extract (store, "SELECT table_schema, table_name FROM "
-								"_tables", NULL);
-				if (model) {
-					gint i, nrows;
-					gint len = strlen (start);
-					
-					compl = g_array_new (TRUE, TRUE, sizeof (char *));
-					nrows = gda_data_model_get_n_rows (model);
-					for (i = 0; i < nrows; i++) {
-						const gchar *tname;
-						tname = g_value_get_string (gda_data_model_get_value_at (model, 1, i));
-						if (!strncmp (tname, start, len)) {
-							char *str;
-							str = malloc (sizeof (char) * (strlen (tname) + 1));
-							strcpy (str, tname);
-							g_array_append_val (compl, str);
-							nb_compl++;
-						}
-					}
-					g_object_unref (model);
-				}
+	if (!cs)
+		return NULL;
+	gda_compl = gda_completion_list_get (cs->cnc, rl_line_buffer, start, end);
+	if (!gda_compl)
+		return NULL;
 
-				model = gda_meta_store_extract (store, "SELECT schema_name FROM "
-								"_schemata", NULL);
-				if (model) {
-					gint i, nrows;
-					gint len = strlen (start);
-					
-					compl = g_array_new (TRUE, TRUE, sizeof (char *));
-					nrows = gda_data_model_get_n_rows (model);
-					for (i = 0; i < nrows; i++) {
-						const gchar *tname;
-						tname = g_value_get_string (gda_data_model_get_value_at (model, 0, i));
-						if (!strncmp (tname, start, len)) {
-							char *str;
-							str = malloc (sizeof (char) * (strlen (tname) + 1));
-							strcpy (str, tname);
-							g_array_append_val (compl, str);
-							nb_compl++;
-						}
-					}
-					g_object_unref (model);
-				}
-			}
-			g_free (copy);
-		}
+	for (nb_compl = 0; gda_compl[nb_compl]; nb_compl++);
 
-		if (compl)
-			return g_array_index (compl, char*, 0);
-		else
-			return NULL;
-	}
-	else 
-		return g_array_index (compl, char*, state) ;
+	array = malloc (sizeof (char*) * (nb_compl + 1));
+	for (i = 0; i < nb_compl; i++) {
+		char *str;
+		gchar *gstr;
+		gint l;
+
+		gstr = gda_compl[i];
+		l = strlen (gstr) + 1;
+		str = malloc (sizeof (char) * l);
+		memcpy (str, gstr, l);
+		array[i] = str;
+	}
+	array[i] = NULL;
+	g_strfreev (gda_compl);
+	return array;
+#else
+	return NULL;
+#endif
 }

Modified: trunk/tools/tools-input.c
==============================================================================
--- trunk/tools/tools-input.c	(original)
+++ trunk/tools/tools-input.c	Tue Apr 15 09:26:32 2008
@@ -118,7 +118,8 @@
 set_completion_func (CompletionFunc func)
 {
 #ifdef HAVE_READLINE_READLINE_H	
-	rl_completion_entry_function = func;
+	rl_attempted_completion_function = func;
+	rl_basic_word_break_characters = " \t\n\\'` $><=;|&{(";
 #endif	
 }
 

Modified: trunk/tools/tools-input.h
==============================================================================
--- trunk/tools/tools-input.h	(original)
+++ trunk/tools/tools-input.h	Tue Apr 15 09:26:32 2008
@@ -25,7 +25,7 @@
 #include <stdio.h>
 #include <glib.h>
 
-typedef char *(*CompletionFunc) (const char *, int);
+typedef char **(*CompletionFunc) (const char *, int, int);
 
 gchar   *input_from_console (const gchar *prompt);
 gchar   *input_from_stream  (FILE *stream);



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