libgda r3279 - in trunk: . libgda libgda/sqlite tests/data-models tests/parser tests/providers tools



Author: vivien
Date: Fri Jan  9 20:40:50 2009
New Revision: 3279
URL: http://svn.gnome.org/viewvc/libgda?rev=3279&view=rev

Log:
2009-01-09  Vivien Malerba <malerba gnome-db org>

	* libgda/gda-util.[ch]: added gda_compute_select_statement_from_update()
	* libgda/sqlite/:
	  - added BLOB support for the SQLite provider
	  - report an error when getting a gint from a too big gint64 value
	* tests/: updated test data related to the gda_g_type_to_string() changes
	* configure.in
	* tools/:
	  - added a '-v' command line option to display version
	  - added a man page for gda-sql
	  - optionnally create symlink from "<prog>" to the "<prog>-4.0" program names


Added:
   trunk/libgda/sqlite/gda-sqlite-blob-op.c
   trunk/libgda/sqlite/gda-sqlite-blob-op.h
   trunk/tools/gda-sql.1.in
Modified:
   trunk/ChangeLog
   trunk/configure.in
   trunk/libgda/gda-util.c
   trunk/libgda/gda-util.h
   trunk/libgda/sqlite/Makefile.am
   trunk/libgda/sqlite/README
   trunk/libgda/sqlite/gda-sqlite-provider.c
   trunk/libgda/sqlite/gda-sqlite-pstmt.c
   trunk/libgda/sqlite/gda-sqlite-pstmt.h
   trunk/libgda/sqlite/gda-sqlite-recordset.c
   trunk/libgda/sqlite/utils.c
   trunk/tests/data-models/data1.xml
   trunk/tests/data-models/pmodel_data_customers.xml
   trunk/tests/data-models/pmodel_data_locations.xml
   trunk/tests/parser/testdata.xml
   trunk/tests/parser/testvalid.xml
   trunk/tests/providers/DATA_actor.xml
   trunk/tests/providers/DATA_film.xml
   trunk/tests/providers/DATA_film_actor.xml
   trunk/tests/providers/DATA_language.xml
   trunk/tests/providers/TYPES_SCHEMA_Mdb.xml
   trunk/tests/providers/TYPES_SCHEMA_MySQL.xml
   trunk/tests/providers/TYPES_SCHEMA_Oracle.xml
   trunk/tests/providers/TYPES_SCHEMA_PostgreSQL.xml
   trunk/tests/providers/TYPES_SCHEMA_SQLite.xml
   trunk/tools/   (props changed)
   trunk/tools/Makefile.am
   trunk/tools/gda-sql.c

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Fri Jan  9 20:40:50 2009
@@ -7,6 +7,7 @@
 AC_CONFIG_SRCDIR(libgda/libgda.h.in)
 AM_INIT_AUTOMAKE(1.8 -Wall no-define dist-bzip2)
 
+
 AC_SUBST(GDA_VERSION, major.minor.micro)
 
 # ABI version:
@@ -19,6 +20,9 @@
 AC_SUBST(GDA_ABI_VERSION, $LIBGDA_ABI_VERSION)
 LIBGDA_ABI_NAME="\\\"libgda-$LIBGDA_ABI_VERSION\\\""
 
+gdasysconfdir="$sysconfdir"
+AC_SUBST(gdasysconfdir)
+
 m4_undefine([major])
 m4_undefine([minor])
 m4_undefine([micro])
@@ -1445,6 +1449,12 @@
 fi
 AC_SUBST(REBUILD)
 
+#
+# enable setting the Gda SQL console as default version (makes a symlink)
+#
+AC_ARG_ENABLE(default-binary, [  --enable-default-binary install tools as the default binaries (default=yes)], , enable_default_binary=yes)
+AM_CONDITIONAL(DEFAULT_BINARY, test "x$enable_default_binary" = xyes)
+
 AC_SUBST(LIBGDA_CFLAGS)
 AC_SUBST(LIBGDA_LIBS)
 
@@ -1490,6 +1500,7 @@
 libgda-report/RML/trml2pdf/Makefile
 libgda-xslt/Makefile
 tools/Makefile
+tools/gda-sql-4.0.1:tools/gda-sql.1.in
 tools/binreloc/Makefile
 testing/Makefile
 tests/Makefile

Modified: trunk/libgda/gda-util.c
==============================================================================
--- trunk/libgda/gda-util.c	(original)
+++ trunk/libgda/gda-util.c	Fri Jan  9 20:40:50 2009
@@ -1035,6 +1035,57 @@
 }
 
 /**
+ * gda_compute_select_statement_from_update
+ * @update_stmt: an UPDATE statement
+ * @error: a place to store errors, or %NULL
+ *
+ * Computes a SELECT statement which selects all the rows the @update_stmt would update. Beware
+ * however that this GdaSqlStatement does not select anything (ie it would be rendered as "SELECT FROM ... WHERE ...")
+ * and before being useable, one needs to add some fields to actually select.
+ */
+GdaSqlStatement *
+gda_compute_select_statement_from_update (GdaStatement *update_stmt, GError **error)
+{
+	GdaSqlStatement *upd_stmt;
+	GdaSqlStatement *sel_stmt;
+	GdaSqlStatementUpdate *ust;
+	GdaSqlStatementSelect *sst;
+
+	g_return_val_if_fail (update_stmt, NULL);
+	g_object_get (G_OBJECT (update_stmt), "structure", &upd_stmt, NULL);
+	g_return_val_if_fail (upd_stmt, NULL);
+	g_return_val_if_fail (upd_stmt->stmt_type == GDA_SQL_STATEMENT_UPDATE, NULL);
+	
+	ust = (GdaSqlStatementUpdate*) upd_stmt->contents;
+	sst = g_new0 (GdaSqlStatementSelect, 1);
+
+	if (!ust->table || !ust->table->table_name) {
+		g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
+			     "%s", _("Missing table name in UPDATE statement"));
+		return NULL;
+	}
+
+	/* FROM */
+	GdaSqlSelectTarget *target;
+	sst->from = gda_sql_select_from_new (GDA_SQL_ANY_PART (sst));
+	target = gda_sql_select_target_new (GDA_SQL_ANY_PART (sst->from));
+	sst->from->targets = g_slist_prepend (NULL, target);
+	target->expr = gda_sql_expr_new (GDA_SQL_ANY_PART (target));
+	g_value_set_string ((target->expr->value = gda_value_new (G_TYPE_STRING)), ust->table->table_name);
+
+	/* WHERE */
+	sst->where_cond = gda_sql_expr_copy (ust->cond);
+	GDA_SQL_ANY_PART (sst->where_cond)->parent = GDA_SQL_ANY_PART (sst);
+
+	gda_sql_statement_free (upd_stmt);
+
+	sel_stmt = gda_sql_statement_new (GDA_SQL_STATEMENT_SELECT);
+	sel_stmt->contents = sst;
+
+	return sel_stmt;
+}
+
+/**
  * gda_identifier_hash
  * @id: an identifier string
  *

Modified: trunk/libgda/gda-util.h
==============================================================================
--- trunk/libgda/gda-util.h	(original)
+++ trunk/libgda/gda-util.h	Fri Jan  9 20:40:50 2009
@@ -67,11 +67,12 @@
 /*
  * Statement computation from meta store 
  */
-GdaSqlExpr  *gda_compute_unique_table_row_condition (GdaSqlStatementSelect *stsel, GdaMetaTable *mtable, 
-						     gboolean require_pk, GError **error);
-gboolean     gda_compute_dml_statements (GdaConnection *cnc, GdaStatement *select_stmt, gboolean require_pk, 
-					 GdaStatement **insert_stmt, GdaStatement **update_stmt, GdaStatement **delete_stmt, 
-					 GError **error);
+GdaSqlExpr      *gda_compute_unique_table_row_condition (GdaSqlStatementSelect *stsel, GdaMetaTable *mtable, 
+							 gboolean require_pk, GError **error);
+gboolean         gda_compute_dml_statements (GdaConnection *cnc, GdaStatement *select_stmt, gboolean require_pk, 
+					     GdaStatement **insert_stmt, GdaStatement **update_stmt, GdaStatement **delete_stmt, 
+					     GError **error);
+GdaSqlStatement *gda_compute_select_statement_from_update (GdaStatement *update_stmt, GError **error);
 
 /*
  * DSN and connection string manipulations

Modified: trunk/libgda/sqlite/Makefile.am
==============================================================================
--- trunk/libgda/sqlite/Makefile.am	(original)
+++ trunk/libgda/sqlite/Makefile.am	Fri Jan  9 20:40:50 2009
@@ -24,6 +24,8 @@
 sqliteheaders = gda-sqlite-provider.h
 libgda_sqlite_la_SOURCES = \
 	$(sqliteheaders) \
+	gda-sqlite-blob-op.c \
+	gda-sqlite-blob-op.h \
 	gda-sqlite-ddl.c \
 	gda-sqlite-ddl.h \
 	gda-sqlite-handler-bin.c \

Modified: trunk/libgda/sqlite/README
==============================================================================
--- trunk/libgda/sqlite/README	(original)
+++ trunk/libgda/sqlite/README	Fri Jan  9 20:40:50 2009
@@ -1,3 +1,6 @@
+Which version of SQLite is used:
+================================
+
 When embedded SQLITE is used:
 * HAVE_SQLITE is *not* defined
 * patch it to add the PRAGMA command
@@ -13,3 +16,34 @@
 1 - make SQLite implement the required PRAGMA (patch proposed)
 2 - don't use the required PRAGMA at all, and manage to intercept the sqlite3CreateFunc call
     when statically linked (=> modify the source code of SQLite) 
+
+
+
+
+BLOB handling in SQLite:
+========================
+
+SQLite now supports incremental I/O for BLOBS. Any data in any column can be accessed
+with this API.
+
+When writing a blob to the database:
+------------------------------------
+Opening a blob requires the following information:
+* the database name
+* the table name
+* the column name
+* the ROWID
+
+The first 3 pieces of information can be obtained from the INSERT or UPDATE statement
+itself.
+
+The ROWID can be obtained using sqlite3_last_insert_rowid() for an INSERT or must be queried
+for an UPDATE.
+
+When reading a blob from the database:
+--------------------------------------
+Opening a blob requires the following information:
+* the database name: use sqlite3_column_database_name()
+* the table name: use sqlite3_column_table_name()
+* the column name: use sqlite3_column_origin_name()
+* the ROWID: get it from the SELECT as the last row.

Added: trunk/libgda/sqlite/gda-sqlite-blob-op.c
==============================================================================
--- (empty file)
+++ trunk/libgda/sqlite/gda-sqlite-blob-op.c	Fri Jan  9 20:40:50 2009
@@ -0,0 +1,306 @@
+/* GDA Sqlite provider
+ * Copyright (C) 2009 The GNOME Foundation
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib/gi18n-lib.h>
+#include <string.h>
+#include <libgda/libgda.h>
+#include "gda-sqlite.h"
+#include "gda-sqlite-blob-op.h"
+#include <sql-parser/gda-sql-parser.h>
+
+struct _GdaSqliteBlobOpPrivate {
+	sqlite3_blob  *sblob;
+};
+
+static void gda_sqlite_blob_op_class_init (GdaSqliteBlobOpClass *klass);
+static void gda_sqlite_blob_op_init       (GdaSqliteBlobOp *blob,
+					   GdaSqliteBlobOpClass *klass);
+static void gda_sqlite_blob_op_finalize   (GObject *object);
+
+static glong gda_sqlite_blob_op_get_length (GdaBlobOp *op);
+static glong gda_sqlite_blob_op_read       (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size);
+static glong gda_sqlite_blob_op_write      (GdaBlobOp *op, GdaBlob *blob, glong offset);
+
+static GObjectClass *parent_class = NULL;
+
+/*
+ * Object init and finalize
+ */
+GType
+gda_sqlite_blob_op_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static GStaticMutex registering = G_STATIC_MUTEX_INIT;
+		static const GTypeInfo info = {
+			sizeof (GdaSqliteBlobOpClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) gda_sqlite_blob_op_class_init,
+			NULL,
+			NULL,
+			sizeof (GdaSqliteBlobOp),
+			0,
+			(GInstanceInitFunc) gda_sqlite_blob_op_init
+		};
+		g_static_mutex_lock (&registering);
+		if (type == 0)
+			type = g_type_register_static (GDA_TYPE_BLOB_OP, "GdaSqliteBlobOp", &info, 0);
+		g_static_mutex_unlock (&registering);
+	}
+	return type;
+}
+
+static void
+gda_sqlite_blob_op_init (GdaSqliteBlobOp *op, GdaSqliteBlobOpClass *klass)
+{
+	g_return_if_fail (GDA_IS_SQLITE_BLOB_OP (op));
+
+	op->priv = g_new0 (GdaSqliteBlobOpPrivate, 1);
+	op->priv->sblob = NULL;
+}
+
+static void
+gda_sqlite_blob_op_class_init (GdaSqliteBlobOpClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	GdaBlobOpClass *blob_class = GDA_BLOB_OP_CLASS (klass);
+
+	parent_class = g_type_class_peek_parent (klass);
+
+	object_class->finalize = gda_sqlite_blob_op_finalize;
+	blob_class->get_length = gda_sqlite_blob_op_get_length;
+	blob_class->read = gda_sqlite_blob_op_read;
+	blob_class->write = gda_sqlite_blob_op_write;
+}
+
+static void
+gda_sqlite_blob_op_finalize (GObject * object)
+{
+	GdaSqliteBlobOp *bop = (GdaSqliteBlobOp *) object;
+
+	g_return_if_fail (GDA_IS_SQLITE_BLOB_OP (bop));
+
+	/* free specific information */
+	if (bop->priv->sblob)
+		sqlite3_blob_close (bop->priv->sblob);
+	g_free (bop->priv);
+	bop->priv = NULL;
+
+	parent_class->finalize (object);
+}
+
+GdaBlobOp *
+gda_sqlite_blob_op_new (SqliteConnectionData *cdata, const gchar *db_name, const gchar *table_name,
+			const gchar *column_name, sqlite3_int64 rowid)
+{
+	GdaSqliteBlobOp *bop = NULL;
+	int rc;
+	sqlite3_blob *sblob;
+	gchar *db, *table;
+	gboolean free_strings = TRUE;
+
+	g_return_val_if_fail (table_name, NULL);
+	g_return_val_if_fail (column_name, NULL);
+
+	if (db_name) {
+		db = (gchar *) db_name;
+		table = (gchar *) table_name;
+		free_strings = FALSE;
+	}
+	else if (! _split_identifier_string (g_strdup (table_name), &db, &table))
+		return NULL;
+
+	rc = sqlite3_blob_open (cdata->connection, db ? db : "main", table, column_name, rowid,
+				1, /* Read & Write */
+				&(sblob));
+	if (rc != SQLITE_OK) {
+		/*g_print ("ERROR: %s\n", sqlite3_errmsg (cdata->connection));*/
+		goto out;
+	}
+
+	bop = g_object_new (GDA_TYPE_SQLITE_BLOB_OP, NULL);
+	bop->priv->sblob = sblob;
+
+ out:
+	if (free_strings) {
+		g_free (db);
+		g_free (table);
+	}
+	return (GdaBlobOp*) bop;
+}
+
+/*
+ * Get length request
+ */
+static glong
+gda_sqlite_blob_op_get_length (GdaBlobOp *op)
+{
+	GdaSqliteBlobOp *bop;
+	int len;
+
+	g_return_val_if_fail (GDA_IS_SQLITE_BLOB_OP (op), -1);
+	bop = GDA_SQLITE_BLOB_OP (op);
+	g_return_val_if_fail (bop->priv, -1);
+	g_return_val_if_fail (bop->priv->sblob, -1);
+
+	len = sqlite3_blob_bytes (bop->priv->sblob);
+	return len >= 0 ? len : 0;
+}
+
+/*
+ * Blob read request
+ */
+static glong
+gda_sqlite_blob_op_read (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size)
+{
+	GdaSqliteBlobOp *bop;
+	GdaBinary *bin;
+	int rc;
+
+	g_return_val_if_fail (GDA_IS_SQLITE_BLOB_OP (op), -1);
+	bop = GDA_SQLITE_BLOB_OP (op);
+	g_return_val_if_fail (bop->priv, -1);
+	g_return_val_if_fail (bop->priv->sblob, -1);
+	if (offset >= G_MAXINT)
+		return -1;
+	g_return_val_if_fail (blob, -1);
+
+	if (offset > G_MAXINT)
+		return -1;
+	if (size > G_MAXINT)
+		return -1;
+
+	bin = (GdaBinary *) blob;
+	if (bin->data) 
+		g_free (bin->data);
+	bin->data = g_new0 (guchar, size);
+	bin->binary_length = 0;
+
+	/* fetch blob data using C API into bin->data, and set bin->binary_length */
+	int rsize;
+	int len;
+
+	len = sqlite3_blob_bytes (bop->priv->sblob);
+	if (len < 0)
+		return -1;
+	else if (len == 0)
+		return 0;
+		
+	rsize = (int) size;
+	if (offset >= len)
+		return -1;
+
+	if (len - offset < rsize)
+		rsize = len - offset;
+
+	rc = sqlite3_blob_read (bop->priv->sblob, bin->data, rsize, offset);
+	if (rc != SQLITE_OK) {
+		g_free (bin->data);
+		bin->data = NULL;
+		return -1;
+	}
+	bin->binary_length = rsize;
+
+	return bin->binary_length;
+}
+
+/*
+ * Blob write request
+ */
+static glong
+gda_sqlite_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset)
+{
+	GdaSqliteBlobOp *bop;
+	GdaBinary *bin;
+	glong nbwritten = -1;
+	int len;
+
+	g_return_val_if_fail (GDA_IS_SQLITE_BLOB_OP (op), -1);
+	bop = GDA_SQLITE_BLOB_OP (op);
+	g_return_val_if_fail (bop->priv, -1);
+	g_return_val_if_fail (bop->priv->sblob, -1);
+	g_return_val_if_fail (blob, -1);
+
+	len = sqlite3_blob_bytes (bop->priv->sblob);
+	if (len < 0)
+		return -1;
+
+	if (blob->op && (blob->op != op)) {
+		/* use data through blob->op */
+		#define buf_size 16384
+		gint nread = 0;
+		GdaBlob *tmpblob = g_new0 (GdaBlob, 1);
+		tmpblob->op = blob->op;
+
+		nbwritten = 0;
+
+		for (nread = gda_blob_op_read (tmpblob->op, tmpblob, nbwritten, buf_size);
+		     nread > 0;
+		     nread = gda_blob_op_read (tmpblob->op, tmpblob, nbwritten, buf_size)) {
+			int tmp_written;
+			int rc;
+			int wlen;
+			
+			if (nread + offset + nbwritten > len)
+				wlen = 	len - offset - nbwritten;
+			else
+				wlen = nread;
+
+			rc = sqlite3_blob_write (bop->priv->sblob, ((GdaBinary *)tmpblob)->data, wlen, offset + nbwritten);
+			if (rc != SQLITE_OK)
+				tmp_written = -1;
+			else
+				tmp_written = wlen;
+			
+			if (tmp_written < 0) {
+				/* treat error */
+				gda_blob_free ((gpointer) tmpblob);
+				return -1;
+			}
+			nbwritten += tmp_written;
+			if (nread < buf_size)
+				/* nothing more to read */
+				break;
+		}
+		gda_blob_free ((gpointer) tmpblob);
+	}
+	else {
+		/* write blob using bin->data and bin->binary_length */
+		int rc;
+		int wlen;
+		bin = (GdaBinary *) blob;
+		if (bin->binary_length + offset > len)
+			wlen = 	len - offset;
+		else
+			wlen = bin->binary_length;
+
+		rc = sqlite3_blob_write (bop->priv->sblob, bin->data, wlen, offset);
+		if (rc != SQLITE_OK)
+			nbwritten = -1;
+		else
+			nbwritten = wlen;
+	}
+
+	return nbwritten;
+}

Added: trunk/libgda/sqlite/gda-sqlite-blob-op.h
==============================================================================
--- (empty file)
+++ trunk/libgda/sqlite/gda-sqlite-blob-op.h	Fri Jan  9 20:40:50 2009
@@ -0,0 +1,56 @@
+/* GDA Sqlite provider
+ * Copyright (C) 2009 The GNOME Foundation
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GDA_SQLITE_BLOB_OP_H__
+#define __GDA_SQLITE_BLOB_OP_H__
+
+#include <libgda/gda-blob-op.h>
+
+G_BEGIN_DECLS
+
+#define GDA_TYPE_SQLITE_BLOB_OP            (gda_sqlite_blob_op_get_type())
+#define GDA_SQLITE_BLOB_OP(obj)            (G_TYPE_CHECK_INSTANCE_CAST (obj, GDA_TYPE_SQLITE_BLOB_OP, GdaSqliteBlobOp))
+#define GDA_SQLITE_BLOB_OP_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST (klass, GDA_TYPE_SQLITE_BLOB_OP, GdaSqliteBlobOpClass))
+#define GDA_IS_SQLITE_BLOB_OP(obj)         (G_TYPE_CHECK_INSTANCE_TYPE (obj, GDA_TYPE_SQLITE_BLOB_OP))
+#define GDA_IS_SQLITE_BLOB_OP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDA_TYPE_SQLITE_BLOB_OP))
+
+typedef struct _GdaSqliteBlobOp        GdaSqliteBlobOp;
+typedef struct _GdaSqliteBlobOpClass   GdaSqliteBlobOpClass;
+typedef struct _GdaSqliteBlobOpPrivate GdaSqliteBlobOpPrivate;
+
+struct _GdaSqliteBlobOp {
+	GdaBlobOp             parent;
+	GdaSqliteBlobOpPrivate *priv;
+};
+
+struct _GdaSqliteBlobOpClass {
+	GdaBlobOpClass        parent_class;
+};
+
+GType         gda_sqlite_blob_op_get_type     (void) G_GNUC_CONST;
+GdaBlobOp    *gda_sqlite_blob_op_new          (SqliteConnectionData *cdata, const gchar *db_name, const gchar *table_name,
+					       const gchar *column_name, sqlite3_int64 rowid);
+
+G_END_DECLS
+
+#endif
+

Modified: trunk/libgda/sqlite/gda-sqlite-provider.c
==============================================================================
--- trunk/libgda/sqlite/gda-sqlite-provider.c	(original)
+++ trunk/libgda/sqlite/gda-sqlite-provider.c	Fri Jan  9 20:40:50 2009
@@ -1,5 +1,5 @@
 /* GDA SQLite provider
- * Copyright (C) 1998 - 2008 The GNOME Foundation.
+ * Copyright (C) 1998 - 2009 The GNOME Foundation.
  *
  * AUTHORS:
  *	Rodrigo Moya <rodrigo gnome-db org>
@@ -37,6 +37,7 @@
 #include "gda-sqlite-ddl.h"
 #include "gda-sqlite-meta.h"
 #include "gda-sqlite-handler-bin.h"
+#include "gda-sqlite-blob-op.h"
 #include <libgda/gda-connection-private.h>
 #include <libgda/binreloc/gda-binreloc.h>
 #include <libgda/gda-set.h>
@@ -56,6 +57,141 @@
 static GHashTable *db_connections_hash = NULL;
 #endif
 
+/* TMP */
+typedef struct {
+	GdaSqlStatement *stmt;
+	gchar   *db;
+	gchar   *table;
+	gchar   *column;
+	GdaBlob *blob;
+} PendingBlob;
+
+static PendingBlob*
+make_pending_blob (GdaStatement *stmt, GdaHolder *holder, GError **error)
+{
+	PendingBlob *pb = NULL;
+	GdaSqlStatement *sqlst;
+	const gchar *hname;
+
+	g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
+	g_return_val_if_fail (GDA_IS_HOLDER (holder), NULL);
+	hname = gda_holder_get_id (holder);
+	g_return_val_if_fail (hname && *hname, NULL);
+
+	g_object_get (G_OBJECT (stmt), "structure", &sqlst, NULL);
+	g_return_val_if_fail (sqlst, NULL);
+
+	switch (sqlst->stmt_type) {
+	case GDA_SQL_STATEMENT_INSERT: {
+		GdaSqlStatementInsert *istmt = (GdaSqlStatementInsert*) sqlst->contents;
+		gint pos = -1;
+		GSList *vll;
+		for (vll = istmt->values_list; vll && (pos == -1); vll = vll->next) {
+			GSList *vlist;
+			gint p;
+			for (p = 0, vlist = (GSList *) vll->data; 
+			     vlist; 
+			     p++, vlist = vlist->next) {
+				GdaSqlExpr *expr = (GdaSqlExpr *) vlist->data;
+				if (!expr->param_spec)
+					continue;
+				if (expr->param_spec->name && 
+				    !strcmp (expr->param_spec->name, hname)) {
+					pos = p;
+					break;
+				}
+			}
+		}
+		if (pos == -1) {
+			g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+				     GDA_SERVER_PROVIDER_INTERNAL_ERROR,
+				     _("Parameter '%s' not found is statement"), hname);
+			goto out;
+		}
+		GdaSqlField *field;
+		field = g_slist_nth_data (istmt->fields_list, pos);
+		if (!field) {
+			g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+				     GDA_SERVER_PROVIDER_INTERNAL_ERROR,
+				     _("Parameter '%s' does not correspond to a table's column"),
+				     hname);
+			goto out;
+		}
+		pb = g_new0 (PendingBlob, 1);
+		pb->table = istmt->table->table_name;
+		pb->column = field->field_name;
+		break;
+	}
+	case GDA_SQL_STATEMENT_UPDATE: {
+		GdaSqlStatementUpdate *ustmt = (GdaSqlStatementUpdate*) sqlst->contents;
+		gint pos = -1;
+		GSList *vlist;
+		gint p;
+		for (p = 0, vlist = ustmt->expr_list; 
+		     vlist; 
+		     p++, vlist = vlist->next) {
+			GdaSqlExpr *expr = (GdaSqlExpr *) vlist->data;
+			if (!expr->param_spec)
+				continue;
+			if (expr->param_spec->name && 
+			    !strcmp (expr->param_spec->name, hname)) {
+				pos = p;
+				break;
+			}
+		}
+		if (pos == -1) {
+			g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+				     GDA_SERVER_PROVIDER_INTERNAL_ERROR,
+				     _("Parameter '%s' not found is statement"), hname);
+			goto out;
+		}
+		GdaSqlField *field;
+		field = g_slist_nth_data (ustmt->fields_list, pos);
+		if (!field) {
+			g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+				     GDA_SERVER_PROVIDER_INTERNAL_ERROR,
+				     _("Parameter '%s' does not correspond to a table's column"),
+				     hname);
+			goto out;
+		}
+		pb = g_new0 (PendingBlob, 1);
+		pb->table = ustmt->table->table_name;
+		pb->column = field->field_name;
+		break;
+	}
+	default:
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+			     GDA_SERVER_PROVIDER_NON_SUPPORTED_ERROR,
+			     "%s",_("Binding a BLOB for this type of statement is not supported"));
+		goto out;
+	}
+
+ out:
+	if (pb)
+		pb->stmt = sqlst;
+	else
+		gda_sql_statement_free (sqlst);
+	return pb;
+}
+
+static void
+pending_blobs_free_list (GSList *blist)
+{
+	if (!blist)
+		return;
+	GSList *l;
+	for (l = blist; l; l = l->next) {
+		PendingBlob *pb = (PendingBlob*) l->data;
+		if (pb->stmt)
+			gda_sql_statement_free (pb->stmt);
+		g_free (pb);
+	}
+
+	g_slist_free (blist);
+}
+
+/* TMP */
+
 /*
  * GObject methods
  */
@@ -1592,6 +1728,95 @@
 	}
 }
 
+/*
+ * Creates a new GdaStatement, as a copy of @stmt, and adds new OID columns, one for each table involved
+ * in the SELECT
+ * The GHashTable created (as @out_hash) contains:
+ *  - key = table name
+ *  - value = column number in the SELECT (use GPOINTER_TO_INT)
+ *
+ * This step is required for BLOBs which needs to table's ROWID to be opened. The extra columns
+ * won't appear in the final result set.
+ */
+static GdaStatement *
+add_oid_columns (GdaStatement *stmt, GHashTable **out_hash, gint *out_nb_cols_added)
+{
+	GHashTable *hash = NULL;
+	GdaStatement *nstmt;
+	GdaSqlStatement *sqlst;
+	GdaSqlStatementSelect *sst;
+	gint nb_cols_added = 0;
+	gint add_index;
+	
+	*out_hash = NULL;
+	*out_nb_cols_added = 0;
+
+	GdaSqlStatementType type;
+	type = gda_statement_get_statement_type (stmt);
+	if (type == GDA_SQL_STATEMENT_COMPOUND) {
+		TO_IMPLEMENT;
+		return g_object_ref (stmt);
+	}
+	else if (type != GDA_SQL_STATEMENT_SELECT) {
+		return g_object_ref (stmt);
+	}
+
+	g_object_get (G_OBJECT (stmt), "structure", &sqlst, NULL);
+	g_assert (sqlst);
+	hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+	sst = (GdaSqlStatementSelect*) sqlst->contents;
+	
+	if (!sst->from) {
+		gda_sql_statement_free (sqlst);
+		return g_object_ref (stmt);
+	}
+
+	add_index = g_slist_length (sst->expr_list);
+	GSList *list;
+	for (list = sst->from->targets; list; list = list->next) {
+		GdaSqlSelectTarget *target = (GdaSqlSelectTarget*) list->data;
+		GdaSqlSelectField *field;
+
+		if (!target->table_name)
+			continue;
+
+		/* add a field */
+		field = gda_sql_select_field_new (GDA_SQL_ANY_PART (sst));
+		sst->expr_list = g_slist_append (sst->expr_list, field);
+		
+		field->expr = gda_sql_expr_new (GDA_SQL_ANY_PART (field));
+		
+		gchar *str;
+		const gchar *name;
+		if (target->as)
+			name = target->as;
+		else
+			name = target->table_name;
+		if (gda_sql_identifier_needs_quotes (name)) {
+			gchar *tmp;
+			tmp = gda_sql_identifier_add_quotes (target->table_name);
+			str = g_strdup_printf ("%s.rowid", tmp);
+			g_free (tmp);
+		}
+		else
+			str = g_strdup_printf ("%s.rowid", name);
+		g_value_take_string ((field->expr->value = gda_value_new (G_TYPE_STRING)), str);
+		
+		/* add to hash table */
+		g_hash_table_insert (hash, g_strdup (name), GINT_TO_POINTER (add_index));
+		nb_cols_added ++;
+	}
+	
+	/* prepare return */
+	nstmt = (GdaStatement*) g_object_new (GDA_TYPE_STATEMENT, "structure", sqlst, NULL);
+	gda_sql_statement_free (sqlst);
+	
+	*out_hash = hash;
+	*out_nb_cols_added = nb_cols_added;
+
+	return nstmt;
+}
+
 static GdaSqlitePStmt *
 real_prepare (GdaServerProvider *provider, GdaConnection *cnc, GdaStatement *stmt, GError **error)
 {
@@ -1603,6 +1828,10 @@
 	GdaSqlitePStmt *ps;
 	GdaSet *params = NULL;
 	GSList *used_params = NULL;
+	
+	GdaStatement *real_stmt;
+	GHashTable *hash;
+	gint nb_rows_added;
 
 	/* get SQLite's private data */
 	cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data (cnc);
@@ -1613,7 +1842,8 @@
 	if (! gda_statement_get_parameters (stmt, &params, error))
 		return NULL;
 
-	sql = gda_sqlite_provider_statement_to_sql (provider, cnc, stmt, params, GDA_STATEMENT_SQL_PARAMS_AS_QMARK,
+	real_stmt = add_oid_columns (stmt, &hash, &nb_rows_added);
+	sql = gda_sqlite_provider_statement_to_sql (provider, cnc, real_stmt, params, GDA_STATEMENT_SQL_PARAMS_AS_QMARK,
 						    &used_params, error);
 	if (!sql) 
 		goto out_err;
@@ -1658,9 +1888,14 @@
 	gda_pstmt_set_gda_statement (_GDA_PSTMT (ps), stmt);
 	_GDA_PSTMT (ps)->param_ids = param_ids;
 	_GDA_PSTMT (ps)->sql = sql;
+	ps->rowid_hash = hash;
+	ps->nb_rowid_columns = nb_rows_added;
 	return ps;
 
  out_err:
+	if (hash)
+		g_hash_table_destroy (hash);
+	g_object_unref (real_stmt);
 	if (used_params)
 		g_slist_free (used_params);
 	if (params)
@@ -1721,7 +1956,7 @@
 	where->cond = cond;
 	cond->operator_type = GDA_SQL_OPERATOR_TYPE_EQ;
 	expr = gda_sql_expr_new (GDA_SQL_ANY_PART (cond));
-	g_value_set_string ((value = gda_value_new (G_TYPE_STRING)), "_rowid_");
+	g_value_set_string ((value = gda_value_new (G_TYPE_STRING)), "rowid");
 	expr->value = value;
 	cond->operands = g_slist_append (NULL, expr);
 	gchar *str;
@@ -1806,6 +2041,151 @@
 	}
 }
 
+/* 
+ * This function opens any blob which has been inserted or updated as a ZERO blob (the blob currently
+ * only contains zeros) and fills its contents with the blob passed as parameter when executing the statement.
+ *
+ * @blobs_list is freed here
+ */
+static GdaConnectionEvent *
+fill_blob_data (GdaConnection *cnc, GdaSet *params, 
+		SqliteConnectionData *cdata, GdaSqlitePStmt *pstmt, GSList *blobs_list, GError **error)
+{
+	if (!blobs_list)
+		/* nothing to do */
+		return NULL;
+
+	const gchar *str = NULL;
+	GdaStatement *stmt;
+	sqlite3_int64 rowid = -1;
+	GdaDataModel *model = NULL;
+	GError *lerror = NULL;
+
+	/* get single ROWID or a list of ROWID */
+	stmt = gda_pstmt_get_gda_statement (GDA_PSTMT (pstmt));
+	if (!stmt) {
+		g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR,
+			     GDA_SERVER_PROVIDER_INTERNAL_ERROR, "%s",
+			     _("Prepared statement has no associated GdaStatement"));
+		goto blobs_out;
+	}
+	if (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_INSERT) {
+		rowid = sqlite3_last_insert_rowid (cdata->connection);
+	}
+	else if (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_UPDATE) {
+		GdaSqlStatement *sel_stmt;
+		GdaSqlStatementSelect *sst;
+		sel_stmt = gda_compute_select_statement_from_update (stmt, &lerror);
+		if (!sel_stmt) 
+			goto blobs_out;
+		sst = (GdaSqlStatementSelect*) sel_stmt->contents;
+		GdaSqlSelectField *oidfield;
+		oidfield = gda_sql_select_field_new (GDA_SQL_ANY_PART (sst));
+		sst->expr_list = g_slist_prepend (NULL, oidfield);
+		oidfield->expr = gda_sql_expr_new (GDA_SQL_ANY_PART (oidfield));
+		g_value_set_string ((oidfield->expr->value = gda_value_new (G_TYPE_STRING)), "rowid");
+
+		GdaStatement *select;
+		select = (GdaStatement *) g_object_new (GDA_TYPE_STATEMENT, "structure", sel_stmt, NULL);
+		gda_sql_statement_free (sel_stmt);
+		model = gda_connection_statement_execute_select (cnc, select, params, &lerror);
+		if (!model) {
+			g_object_unref (select);
+			goto blobs_out;
+		}
+		g_object_unref (select);
+	}
+
+	/* actual blob filling */
+	GSList *list;
+	for (list = blobs_list; list; list = list->next) {
+		PendingBlob *pb = (PendingBlob*) list->data;
+		
+		if (rowid >= 0) {
+			/*g_print ("Filling BLOB @ %s.%s.%s, rowID %ld\n", pb->db, pb->table, pb->column, rowid);*/
+			GdaSqliteBlobOp *bop;
+			bop = (GdaSqliteBlobOp*) gda_sqlite_blob_op_new (cdata, pb->db, pb->table, pb->column, rowid);
+			if (!bop) {
+				str =  _("Can't create SQLite BLOB handle");
+				goto blobs_out;
+			}
+			if (gda_blob_op_write (GDA_BLOB_OP (bop), pb->blob, 0) < 0) {
+				str =  _("Can't write to SQLite's BLOB");
+				g_object_unref (bop);
+				goto blobs_out;
+			}
+			g_object_unref (bop);
+		}
+		else if (model) {
+			gint nrows, i;
+			nrows = gda_data_model_get_n_rows (model);
+			for (i = 0; i < nrows; i++) {
+				const GValue *cvalue;
+				cvalue = gda_data_model_get_value_at (model, 0, i, &lerror);
+				if (!cvalue) {
+					g_object_unref (model);
+					goto blobs_out;
+				}
+				rowid = g_value_get_int64 (cvalue);
+				GdaSqliteBlobOp *bop;
+				bop = (GdaSqliteBlobOp*) gda_sqlite_blob_op_new (cdata, pb->db, pb->table, pb->column, rowid);
+				if (!bop) {
+					str =  _("Can't create SQLite BLOB handle");
+					g_object_unref (model);
+					goto blobs_out;
+				}
+				if (gda_blob_op_write (GDA_BLOB_OP (bop), pb->blob, 0) < 0) {
+					str =  _("Can't write to SQLite's BLOB");
+					g_object_unref (bop);
+					g_object_unref (model);
+					goto blobs_out;
+				}
+				g_object_unref (bop);
+			}
+			g_object_unref (model);
+		}
+		else
+			str = _("Can't identify the ROWID of the blob to fill");
+	}
+		
+ blobs_out:
+	pending_blobs_free_list (blobs_list);
+
+	if (str) {
+		GdaConnectionEvent *event;
+		event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+		gda_connection_event_set_description (event, str);
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+			     GDA_SERVER_PROVIDER_DATA_ERROR, "%s", str);
+		return event;
+	}
+	if (lerror) {
+		GdaConnectionEvent *event;
+		event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+		gda_connection_event_set_description (event, lerror->message ? lerror->message : _("No detail"));
+		g_propagate_error (error, lerror);
+		return event;
+	}
+	return NULL;
+}
+
+static gboolean
+check_transaction_started (GdaConnection *cnc, gboolean *out_started)
+{
+        GdaTransactionStatus *trans;
+
+        trans = gda_connection_get_transaction_status (cnc);
+        if (!trans) {
+                if (!gda_connection_begin_transaction (cnc, NULL,
+                                                       GDA_TRANSACTION_ISOLATION_UNKNOWN, NULL))
+                        return FALSE;
+                else
+                        *out_started = TRUE;
+        }
+        return TRUE;
+}
+
+
 /*
  * Execute statement request
  */
@@ -1890,6 +2270,7 @@
 			/* create a SQLitePreparedStatement */
 			ps = gda_sqlite_pstmt_new (sqlite_stmt);
 			_GDA_PSTMT (ps)->sql = sql;
+
 			new_ps = TRUE;
 		}
 		else
@@ -1945,6 +2326,9 @@
 	GSList *list;
 	GdaConnectionEvent *event = NULL;
 	int i;
+	GSList *blobs_list = NULL; /* list of PendingBlob structures */
+	gboolean transaction_started = FALSE;
+
 	for (i = 1, list = _GDA_PSTMT (ps)->param_ids; list; list = list->next, i++) {
 		const gchar *pname = (gchar *) list->data;
 		GdaHolder *h = NULL;		
@@ -2036,10 +2420,56 @@
 		else if (G_VALUE_TYPE (value) == G_TYPE_UCHAR)
 			sqlite3_bind_int (ps->sqlite_stmt, i, g_value_get_uchar (value));
 		else if (G_VALUE_TYPE (value) == GDA_TYPE_BLOB) {
-			TO_IMPLEMENT; /* use sqlite3_bind_zeroblob () */
-			GdaBinary *bin = (GdaBinary *) gda_value_get_blob (value);
-			sqlite3_bind_blob (ps->sqlite_stmt, i, 
-					   bin->data, bin->binary_length, SQLITE_TRANSIENT);
+			gulong blob_len;
+			GdaBlob *blob = (GdaBlob*) gda_value_get_blob (value);
+			const gchar *str = NULL;
+
+			/* Start a transaction if necessary */
+                        if (!check_transaction_started (cnc, &transaction_started))
+				str = _("Cannot start transaction");
+			else {
+				/* force reading the complete BLOB into memory */
+				if (blob->op)
+					blob_len = gda_blob_op_get_length (blob->op);
+				else
+					blob_len = ((GdaBinary*) blob)->binary_length;
+				if (blob_len < 0) 
+					str = _("Can't get BLOB's length");
+				else if (blob_len >= G_MAXINT)
+					str = _("BLOB is too big");
+			}
+				
+			if (str) {
+				event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+				gda_connection_event_set_description (event, str);
+				g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+					     GDA_SERVER_PROVIDER_DATA_ERROR, "%s", str);
+				break;
+			}
+
+			PendingBlob *pb;
+			GError *lerror = NULL;
+			pb = make_pending_blob (stmt, h, &lerror);
+			if (!pb) {
+				event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+				gda_connection_event_set_description (event, 
+				   lerror && lerror->message ? lerror->message : _("No detail"));
+								      
+				g_propagate_error (error, lerror);
+				break;
+			}
+			pb->blob = blob;
+			blobs_list = g_slist_prepend (blobs_list, pb);
+
+			if (sqlite3_bind_zeroblob (ps->sqlite_stmt, i, (int) blob_len) !=
+			    SQLITE_OK) {
+				event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+				gda_connection_event_set_description (event, 
+				   lerror && lerror->message ? lerror->message : _("No detail"));
+								      
+				g_propagate_error (error, lerror);
+				break;				
+			}
 		}
 		else if (G_VALUE_TYPE (value) == GDA_TYPE_BINARY) {
 			GdaBinary *bin = (GdaBinary *) gda_value_get_binary (value);
@@ -2096,6 +2526,9 @@
 		gda_connection_add_event (cnc, event);
 		if (new_ps)
 			g_object_unref (ps);
+		pending_blobs_free_list (blobs_list);
+		if (transaction_started)
+                        gda_connection_rollback_transaction (cnc, NULL, NULL);
 		return NULL;
 	}
 	
@@ -2124,6 +2557,9 @@
 			g_object_unref (ps);
 		if (allow_noparam)
 			g_object_set (data_model, "auto-reset", TRUE, NULL);
+		pending_blobs_free_list (blobs_list);
+		if (transaction_started)
+			gda_connection_commit_transaction (cnc, NULL, NULL);
 		return data_model;
         }
 	else {
@@ -2146,6 +2582,9 @@
 				gda_connection_internal_statement_executed (cnc, stmt, params, event);
 				if (new_ps)
 					g_object_unref (ps);
+				pending_blobs_free_list (blobs_list);
+				if (transaction_started)
+					gda_connection_rollback_transaction (cnc, NULL, NULL);
 				return NULL;
                         }
 			else {
@@ -2154,46 +2593,52 @@
 				TO_IMPLEMENT;
 				if (new_ps)
 					g_object_unref (ps);
+				pending_blobs_free_list (blobs_list);
+				if (transaction_started)
+					gda_connection_rollback_transaction (cnc, NULL, NULL);
 				return NULL;
 			}
                 }
                 else {
+			/* fill blobs's data */
+			event = fill_blob_data (cnc, params, cdata, ps, blobs_list, error);
+			if (event) {
+				/* an error occurred */
+				if (new_ps)
+					g_object_unref (ps);
+				if (transaction_started)
+					gda_connection_rollback_transaction (cnc, NULL, NULL);
+				return NULL;
+			}
+			
 			GObject *set;
 			gchar *str = NULL;
-
-			event = NULL;
 			set = (GObject*) gda_set_new_inline (1, "IMPACTED_ROWS", G_TYPE_INT, changes, NULL);
                         if (! g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "DELETE", 6))
                                 str = g_strdup_printf ("DELETE %d (see SQLite documentation for a \"DELETE * FROM table\" query)",
                                                        changes);
-                        else {
-                                if (! g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "INSERT", 6)) {
-					sqlite3_int64 last_id;
-					last_id = sqlite3_last_insert_rowid (handle);
-                                        str = g_strdup_printf ("INSERT %lld %d", last_id, changes);
-					if (last_inserted_row)
-						*last_inserted_row = make_last_inserted_set (cnc, stmt, last_id);
+                        else if (! g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "INSERT", 6)) {
+				sqlite3_int64 last_id;
+				last_id = sqlite3_last_insert_rowid (handle);
+				str = g_strdup_printf ("INSERT %lld %d", last_id, changes);
+				if (last_inserted_row)
+					*last_inserted_row = make_last_inserted_set (cnc, stmt, last_id);
+			}
+			else if (!g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "UPDATE", 6))
+				str = g_strdup_printf ("UPDATE %d", changes);
+			else if (*(_GDA_PSTMT (ps)->sql)) {
+				gchar *tmp = g_ascii_strup (_GDA_PSTMT (ps)->sql, -1);
+				for (str = tmp; *str && (*str != ' ') && (*str != '\t') &&
+					     (*str != '\n'); str++);
+				*str = 0;
+				if (changes > 0) {
+					str = g_strdup_printf ("%s %d", tmp,
+							       changes);
+					g_free (tmp);
 				}
-                                else {
-                                        if (!g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "DELETE", 6))
-                                                str = g_strdup_printf ("DELETE %d", changes);
-                                        else {
-                                                if (*(_GDA_PSTMT (ps)->sql)) {
-                                                        gchar *tmp = g_ascii_strup (_GDA_PSTMT (ps)->sql, -1);
-                                                        for (str = tmp; *str && (*str != ' ') && (*str != '\t') &&
-                                                                     (*str != '\n'); str++);
-                                                        *str = 0;
-                                                        if (changes > 0) {
-                                                                str = g_strdup_printf ("%s %d", tmp,
-                                                                                       changes);
-                                                                g_free (tmp);
-                                                        }
-                                                        else
-                                                                str = tmp;
-                                                }
-                                        }
-                                }
-                        }
+				else
+					str = tmp;
+			}
 			if (str) {
                                 event = gda_connection_event_new (GDA_CONNECTION_EVENT_NOTICE);
                                 gda_connection_event_set_description (event, str);
@@ -2203,6 +2648,8 @@
 			gda_connection_internal_statement_executed (cnc, stmt, params, event);
 			if (new_ps)
 				g_object_unref (ps);
+			if (transaction_started)
+				gda_connection_commit_transaction (cnc, NULL, NULL);
 			return set;
 		}
 	}

Modified: trunk/libgda/sqlite/gda-sqlite-pstmt.c
==============================================================================
--- trunk/libgda/sqlite/gda-sqlite-pstmt.c	(original)
+++ trunk/libgda/sqlite/gda-sqlite-pstmt.c	Fri Jan  9 20:40:50 2009
@@ -1,5 +1,5 @@
 /* GDA library
- * Copyright (C) 2008 The GNOME Foundation.
+ * Copyright (C) 2008 - 2009 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -78,6 +78,8 @@
 	g_return_if_fail (GDA_IS_PSTMT (pstmt));
 	pstmt->sqlite_stmt = NULL;
 	pstmt->stmt_used = FALSE;
+	pstmt->rowid_hash = NULL;
+	pstmt->nb_rowid_columns = 0;
 }
 
 static void
@@ -91,6 +93,9 @@
 	if (pstmt->sqlite_stmt) 
 		sqlite3_finalize (pstmt->sqlite_stmt);
 
+	if (pstmt->rowid_hash)
+		g_hash_table_destroy (pstmt->rowid_hash);
+
 	/* chain to parent class */
 	parent_class->finalize (object);
 }

Modified: trunk/libgda/sqlite/gda-sqlite-pstmt.h
==============================================================================
--- trunk/libgda/sqlite/gda-sqlite-pstmt.h	(original)
+++ trunk/libgda/sqlite/gda-sqlite-pstmt.h	Fri Jan  9 20:40:50 2009
@@ -1,5 +1,5 @@
 /* GDA common library
- * Copyright (C) 2008 The GNOME Foundation.
+ * Copyright (C) 2008 - 2009 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -46,7 +46,9 @@
 
 	sqlite3_stmt   *sqlite_stmt;
 	gboolean        stmt_used; /* TRUE if a recorset already uses this prepared statement,
-				    necessary because only one recordset can use sqlite_stmt at a time */
+				    * necessary because only one recordset can use sqlite_stmt at a time */
+	GHashTable      *rowid_hash;
+	gint             nb_rowid_columns;
 };
 
 struct _GdaSqlitePStmtClass {

Modified: trunk/libgda/sqlite/gda-sqlite-recordset.c
==============================================================================
--- trunk/libgda/sqlite/gda-sqlite-recordset.c	(original)
+++ trunk/libgda/sqlite/gda-sqlite-recordset.c	Fri Jan  9 20:40:50 2009
@@ -1,5 +1,5 @@
 /* GDA SQLite provider
- * Copyright (C) 1998 - 2008 The GNOME Foundation.
+ * Copyright (C) 1998 - 2009 The GNOME Foundation.
  *
  * AUTHORS:
  *	   Rodrigo Moya <rodrigo gnome-db org>
@@ -28,6 +28,7 @@
 #include "gda-sqlite.h"
 #include "gda-sqlite-recordset.h"
 #include "gda-sqlite-provider.h"
+#include "gda-sqlite-blob-op.h"
 #include <libgda/gda-util.h>
 #include <libgda/gda-connection-private.h>
 
@@ -200,8 +201,8 @@
                 _gda_sqlite_compute_types_hash (cdata);
 
         /* make sure @ps reports the correct number of columns */
-	if (_GDA_PSTMT (ps)->ncols < 0) 
-		_GDA_PSTMT (ps)->ncols = sqlite3_column_count (ps->sqlite_stmt);
+	if (_GDA_PSTMT (ps)->ncols < 0)
+		_GDA_PSTMT (ps)->ncols = sqlite3_column_count (ps->sqlite_stmt) - ps->nb_rowid_columns;
 
         /* completing ps */
 	g_assert (! ps->stmt_used);
@@ -275,11 +276,17 @@
 	if (_GDA_PSTMT (ps)->types [colnum] != GDA_TYPE_NULL)
 		return _GDA_PSTMT (ps)->types [colnum];
 	
-	ctype = sqlite3_column_decltype (ps->sqlite_stmt, colnum);
-	if (ctype)
-		gtype = GPOINTER_TO_INT (g_hash_table_lookup (cdata->types, ctype));
-	if (gtype == GDA_TYPE_NULL) 
-		gtype = _gda_sqlite_compute_g_type (sqlite3_column_type (ps->sqlite_stmt, colnum));
+	ctype = sqlite3_column_origin_name (ps->sqlite_stmt, colnum);
+	if (ctype && !strcmp (ctype, "rowid"))
+		gtype = G_TYPE_INT64;
+	else {
+		ctype = sqlite3_column_decltype (ps->sqlite_stmt, colnum);
+		
+		if (ctype)
+			gtype = GPOINTER_TO_INT (g_hash_table_lookup (cdata->types, ctype));
+		if (gtype == GDA_TYPE_NULL) 
+			gtype = _gda_sqlite_compute_g_type (sqlite3_column_type (ps->sqlite_stmt, colnum));
+	}
 
 	return gtype;
 }
@@ -337,8 +344,20 @@
 				
 				if (type == GDA_TYPE_NULL)
 					;
-				else if (type == G_TYPE_INT)
-					g_value_set_int (value, sqlite3_column_int (ps->sqlite_stmt, col));
+				else if (type == G_TYPE_INT) {
+					gint64 i;
+					i = sqlite3_column_int (ps->sqlite_stmt, col);
+					if ((i > G_MAXINT) || (i < G_MININT)) {
+						g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+							     GDA_SERVER_PROVIDER_DATA_ERROR,
+							     "%s", _("Integer value is too big"));
+						has_error = TRUE;
+						break;
+					}
+					g_value_set_int (value, (gint) i);
+				}
+				else if (type == G_TYPE_INT64)
+					g_value_set_int64 (value, sqlite3_column_int64 (ps->sqlite_stmt, col));
 				else if (type == G_TYPE_DOUBLE)
 					g_value_set_double (value, sqlite3_column_double (ps->sqlite_stmt, col));
 				else if (type == G_TYPE_STRING)
@@ -357,6 +376,46 @@
 						bin->binary_length = 0;
 					gda_value_take_binary (value, bin);
 				}
+				else if (type == GDA_TYPE_BLOB) {
+					GdaBlobOp *bop = NULL;
+					gint oidcol = 0;
+
+					if (ps->rowid_hash) {
+						const char *ctable;
+						ctable = sqlite3_column_name (ps->sqlite_stmt, col);
+						if (ctable)
+							oidcol = GPOINTER_TO_INT (g_hash_table_lookup (ps->rowid_hash,
+												       ctable));
+						if (oidcol == 0) {
+							ctable = sqlite3_column_table_name (ps->sqlite_stmt, col);
+							if (ctable)
+								oidcol = GPOINTER_TO_INT (g_hash_table_lookup (ps->rowid_hash, 
+													       ctable));
+						}
+					}
+					if (oidcol != 0) {
+						gint64 rowid;
+						rowid = sqlite3_column_int64 (ps->sqlite_stmt, oidcol);
+						bop = gda_sqlite_blob_op_new (cdata,
+									      sqlite3_column_database_name (ps->sqlite_stmt, col),
+									      sqlite3_column_table_name (ps->sqlite_stmt, col),
+									      sqlite3_column_origin_name (ps->sqlite_stmt, col),
+									      rowid);
+					}
+					if (!bop) {
+						g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+							     GDA_SERVER_PROVIDER_DATA_ERROR,
+							     "%s", _("Unable to open BLOB"));
+						has_error = TRUE;
+						break;
+					}
+					else {
+						GdaBlob *blob;
+						blob = g_new0 (GdaBlob, 1);
+						blob->op = bop;
+						gda_value_take_blob (value, blob);
+					}
+				}
 				else if (type == G_TYPE_BOOLEAN)
 					g_value_set_boolean (value, sqlite3_column_int (ps->sqlite_stmt, col) == 0 ? FALSE : TRUE);
 				else if (type == G_TYPE_DATE) {

Modified: trunk/libgda/sqlite/utils.c
==============================================================================
--- trunk/libgda/sqlite/utils.c	(original)
+++ trunk/libgda/sqlite/utils.c	Fri Jan  9 20:40:50 2009
@@ -1,5 +1,5 @@
 /* GNOME DB Postgres Provider
- * Copyright (C) 1998 - 2006 The GNOME Foundation
+ * Copyright (C) 1998 - 2009 The GNOME Foundation
  *
  * AUTHORS:
  *         Gonzalo Paniagua Javier <gonzalo gnome-db org>
@@ -65,7 +65,8 @@
 	g_hash_table_insert (types, g_strdup ("real"), GINT_TO_POINTER (G_TYPE_DOUBLE));
 	g_hash_table_insert (types, g_strdup ("text"), GINT_TO_POINTER (G_TYPE_STRING));
 	g_hash_table_insert (types, g_strdup ("string"), GINT_TO_POINTER (G_TYPE_STRING));
-	g_hash_table_insert (types, g_strdup ("blob"), GINT_TO_POINTER (GDA_TYPE_BINARY));
+	g_hash_table_insert (types, g_strdup ("binary"), GINT_TO_POINTER (GDA_TYPE_BINARY));
+	g_hash_table_insert (types, g_strdup ("blob"), GINT_TO_POINTER (GDA_TYPE_BLOB));
 }
 
 GType
@@ -80,7 +81,7 @@
 	case SQLITE_TEXT:
 		return G_TYPE_STRING;
 	case SQLITE_BLOB:
-		return GDA_TYPE_BINARY;
+		return GDA_TYPE_BLOB;
 	case SQLITE_NULL:
 		return GDA_TYPE_NULL;
 	default:

Modified: trunk/tests/data-models/data1.xml
==============================================================================
--- trunk/tests/data-models/data1.xml	(original)
+++ trunk/tests/data-models/data1.xml	Fri Jan  9 20:40:50 2009
@@ -1,15 +1,15 @@
 <?xml version="1.0"?>
 <gda_array id="FIELDS_A" name="Table's columns">
-  <gda_array_field id="COLUMN_NAME" name="Field name" title="Field name" gdatype="gchararray"/>
-  <gda_array_field id="COLUMN_TYPE" name="Data type" title="Data type" gdatype="gchararray"/>
+  <gda_array_field id="COLUMN_NAME" name="Field name" title="Field name" gdatype="string"/>
+  <gda_array_field id="COLUMN_TYPE" name="Data type" title="Data type" gdatype="string"/>
   <gda_array_field id="COLUMN_SIZE" name="Size" title="Size" gdatype="guint" nullok="TRUE"/>
   <gda_array_field id="COLUMN_SCALE" name="Scale" title="Scale" gdatype="guint" nullok="TRUE"/>
-  <gda_array_field id="COLUMN_NNUL" name="Not NULL" title="Not NULL" gdatype="gboolean"/>
-  <gda_array_field id="COLUMN_AUTOINC" name="Auto increment" title="Auto increment" gdatype="gboolean"/>
-  <gda_array_field id="COLUMN_UNIQUE" name="Unique" title="Unique" gdatype="gboolean"/>
-  <gda_array_field id="COLUMN_PKEY" name="Primary key" title="Primary key" gdatype="gboolean"/>
-  <gda_array_field id="COLUMN_DEFAULT" name="Default" title="Default" gdatype="gchararray"/>
-  <gda_array_field id="COLUMN_CHECK" name="Check" title="Check" gdatype="gchararray"/>
+  <gda_array_field id="COLUMN_NNUL" name="Not NULL" title="Not NULL" gdatype="boolean"/>
+  <gda_array_field id="COLUMN_AUTOINC" name="Auto increment" title="Auto increment" gdatype="boolean"/>
+  <gda_array_field id="COLUMN_UNIQUE" name="Unique" title="Unique" gdatype="boolean"/>
+  <gda_array_field id="COLUMN_PKEY" name="Primary key" title="Primary key" gdatype="boolean"/>
+  <gda_array_field id="COLUMN_DEFAULT" name="Default" title="Default" gdatype="string"/>
+  <gda_array_field id="COLUMN_CHECK" name="Check" title="Check" gdatype="string"/>
   <gda_array_data>
     <gda_array_row>
       <gda_value>id</gda_value>

Modified: trunk/tests/data-models/pmodel_data_customers.xml
==============================================================================
--- trunk/tests/data-models/pmodel_data_customers.xml	(original)
+++ trunk/tests/data-models/pmodel_data_customers.xml	Fri Jan  9 20:40:50 2009
@@ -1,11 +1,11 @@
 <?xml version="1.0"?>
 <gda_array id="EXPORT" name="Exported Data">
-  <gda_array_field id="FI0" name="id" title="id" gdatype="gint"/>
-  <gda_array_field id="FI1" name="name" title="name" gdatype="gchararray"/>
-  <gda_array_field id="FI2" name="last_update" title="last_update" gdatype="GdaTimestamp"/>
-  <gda_array_field id="FI3" name="default_served_by" title="default_served_by" gdatype="gint" nullok="TRUE"/>
-  <gda_array_field id="FI4" name="country" title="country" gdatype="gchararray" nullok="TRUE"/>
-  <gda_array_field id="FI5" name="city" title="city" gdatype="gchararray" nullok="TRUE"/>
+  <gda_array_field id="FI0" name="id" title="id" gdatype="int"/>
+  <gda_array_field id="FI1" name="name" title="name" gdatype="string"/>
+  <gda_array_field id="FI2" name="last_update" title="last_update" gdatype="timestamp"/>
+  <gda_array_field id="FI3" name="default_served_by" title="default_served_by" gdatype="int" nullok="TRUE"/>
+  <gda_array_field id="FI4" name="country" title="country" gdatype="string" nullok="TRUE"/>
+  <gda_array_field id="FI5" name="city" title="city" gdatype="string" nullok="TRUE"/>
   <gda_array_data>
     <gda_array_row>
       <gda_value>2</gda_value>

Modified: trunk/tests/data-models/pmodel_data_locations.xml
==============================================================================
--- trunk/tests/data-models/pmodel_data_locations.xml	(original)
+++ trunk/tests/data-models/pmodel_data_locations.xml	Fri Jan  9 20:40:50 2009
@@ -1,8 +1,8 @@
 <?xml version="1.0"?>
 <gda_array id="EXPORT" name="Exported Data">
-  <gda_array_field id="FI0" name="country" title="country" gdatype="gchararray"/>
-  <gda_array_field id="FI1" name="city" title="city" gdatype="gchararray"/>
-  <gda_array_field id="FI2" name="shortcut" title="shortcut" gdatype="gchararray"/>
+  <gda_array_field id="FI0" name="country" title="country" gdatype="string"/>
+  <gda_array_field id="FI1" name="city" title="city" gdatype="string"/>
+  <gda_array_field id="FI2" name="shortcut" title="shortcut" gdatype="string"/>
   <gda_array_data>
     <gda_array_row>
       <gda_value>FR</gda_value>

Modified: trunk/tests/parser/testdata.xml
==============================================================================
--- trunk/tests/parser/testdata.xml	(original)
+++ trunk/tests/parser/testdata.xml	Fri Jan  9 20:40:50 2009
@@ -24,12 +24,12 @@
 
   <test id="3">
     <sql>##pname::gint</sql>
-    <expected>{"statements":[{"statement":{"sql":"##pname::gint","stmt_type":"UNKNOWN","contents":[{"value":null,"param_spec":{"name":"pname","descr":null,"type":"gint","is_param":true,"nullok":false}}]}}]}</expected>
+    <expected>{"statements":[{"statement":{"sql":"##pname::gint","stmt_type":"UNKNOWN","contents":[{"value":null,"param_spec":{"name":"pname","descr":null,"type":"int","is_param":true,"nullok":false}}]}}]}</expected>
   </test>
 
   <test id="4">
     <sql>##pname::gint::null</sql>
-    <expected>{"statements":[{"statement":{"sql":"##pname::gint::null","stmt_type":"UNKNOWN","contents":[{"value":null,"param_spec":{"name":"pname","descr":null,"type":"gint","is_param":true,"nullok":true}}]}}]}</expected>
+    <expected>{"statements":[{"statement":{"sql":"##pname::gint::null","stmt_type":"UNKNOWN","contents":[{"value":null,"param_spec":{"name":"pname","descr":null,"type":"int","is_param":true,"nullok":true}}]}}]}</expected>
   </test>
 
   <!-- Extendend param notation, unspec value -->
@@ -45,7 +45,7 @@
 
   <test id="7">
     <sql>## /* type:gint */</sql>
-    <expected>{"statements":[{"statement":{"sql":"## \/* type:gint *\/","stmt_type":"UNKNOWN","contents":[{"value":null,"param_spec":{"name":null,"descr":null,"type":"gint","is_param":true,"nullok":false}}]}}]}</expected>
+    <expected>{"statements":[{"statement":{"sql":"## \/* type:gint *\/","stmt_type":"UNKNOWN","contents":[{"value":null,"param_spec":{"name":null,"descr":null,"type":"int","is_param":true,"nullok":false}}]}}]}</expected>
   </test>
 
   <test id="8">
@@ -97,13 +97,13 @@
   <!-- Extendend param notation, with value -->
   <test id="17">
     <sql>12 /* type:gint name:myparam */</sql>
-    <expected>{"statements":[{"statement":{"sql":"12 \/* type:gint name:myparam *\/","stmt_type":"UNKNOWN","contents":[{"value":"12","param_spec":{"name":"myparam","descr":null,"type":"gint","is_param":true,"nullok":false}}]}}]}</expected>
+    <expected>{"statements":[{"statement":{"sql":"12 \/* type:gint name:myparam *\/","stmt_type":"UNKNOWN","contents":[{"value":"12","param_spec":{"name":"myparam","descr":null,"type":"int","is_param":true,"nullok":false}}]}}]}</expected>
   </test>
 
 
   <test id="18">
     <sql>'A string' /* name:'A string param' type:'gchararray' */</sql>
-    <expected>{"statements":[{"statement":{"sql":"'A string' \/* name:'A string param' type:'gchararray' *\/","stmt_type":"UNKNOWN","contents":[{"value":"'A string'","param_spec":{"name":"A string param","descr":null,"type":"gchararray","is_param":true,"nullok":false}}]}}]}</expected>
+    <expected>{"statements":[{"statement":{"sql":"'A string' \/* name:'A string param' type:'gchararray' *\/","stmt_type":"UNKNOWN","contents":[{"value":"'A string'","param_spec":{"name":"A string param","descr":null,"type":"string","is_param":true,"nullok":false}}]}}]}</expected>
   </test>
 
   <!-- multiple parts in single statement -->
@@ -860,7 +860,7 @@
 
   <test id="2229">
     <sql>select * from table limit ##limval::gint</sql>
-    <expected>{"statements":[{"statement":{"sql":"select * from table limit ##limval::gint","stmt_type":"SELECT","contents":{"distinct":"false","fields":[{"expr":{"value":"*"}}],"from":{"targets":[{"expr":{"value":"table"},"table_name":"table"}]},"limit":{"value":null,"param_spec":{"name":"limval","descr":null,"type":"gint","is_param":true,"nullok":false}}}}}]}</expected>
+    <expected>{"statements":[{"statement":{"sql":"select * from table limit ##limval::gint","stmt_type":"SELECT","contents":{"distinct":"false","fields":[{"expr":{"value":"*"}}],"from":{"targets":[{"expr":{"value":"table"},"table_name":"table"}]},"limit":{"value":null,"param_spec":{"name":"limval","descr":null,"type":"int","is_param":true,"nullok":false}}}}}]}</expected>
   </test>
 
   <test id="2230">

Modified: trunk/tests/parser/testvalid.xml
==============================================================================
--- trunk/tests/parser/testvalid.xml	(original)
+++ trunk/tests/parser/testvalid.xml	Fri Jan  9 20:40:50 2009
@@ -58,26 +58,26 @@
   <test id="pre3">
     <sql valid="t">SELECT * FROM sales_orga</sql>
     <normalized>{"statement":{"sql":"SELECT * FROM sales_orga","stmt_type":"SELECT","contents":{"distinct":"false","fields":[{"expr":{"value":"id_salesrep"},"field_name":"id_salesrep"},{"expr":{"value":"id_role"},"field_name":"id_role"},{"expr":{"value":"note"},"field_name":"note"}],"from":{"targets":[{"expr":{"value":"sales_orga"},"table_name":"sales_orga"}]}}}}</normalized>
-    <insert>{"statement":{"sql":null,"stmt_type":"INSERT","contents":{"table":"sales_orga","fields":["id_salesrep","id_role","note"],"values":[[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"gint","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"gint","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+2","descr":null,"type":"gchararray","is_param":false,"nullok":true}}]]}}}</insert>
+    <insert>{"statement":{"sql":null,"stmt_type":"INSERT","contents":{"table":"sales_orga","fields":["id_salesrep","id_role","note"],"values":[[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"int","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"int","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+2","descr":null,"type":"string","is_param":false,"nullok":true}}]]}}}</insert>
     <update/>
     <delete/>
   </test>
 
   <test id="0">
     <sql valid="t">SELECT id, name FROM customers</sql>
-    <insert>{"statement":{"sql":null,"stmt_type":"INSERT","contents":{"table":"customers","fields":["id","name"],"values":[[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"gint","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"gchararray","is_param":false,"nullok":false}}]]}}}</insert>
-    <update>{"statement":{"sql":null,"stmt_type":"UPDATE","contents":{"table":"customers","fields":["id","name"],"expressions":[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"gint","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"gchararray","is_param":false,"nullok":false}}],"condition":{"operation":{"operator":"=","operand0":{"value":"id"},"operand1":{"value":null,"param_spec":{"name":"-0","descr":null,"type":"gint","is_param":false,"nullok":false}}}}}}}</update>
-    <delete>{"statement":{"sql":null,"stmt_type":"DELETE","contents":{"table":"customers","condition":{"operation":{"operator":"=","operand0":{"value":"id"},"operand1":{"value":null,"param_spec":{"name":"-0","descr":null,"type":"gint","is_param":false,"nullok":false}}}}}}}</delete>
+    <insert>{"statement":{"sql":null,"stmt_type":"INSERT","contents":{"table":"customers","fields":["id","name"],"values":[[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"int","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"string","is_param":false,"nullok":false}}]]}}}</insert>
+    <update>{"statement":{"sql":null,"stmt_type":"UPDATE","contents":{"table":"customers","fields":["id","name"],"expressions":[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"int","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"string","is_param":false,"nullok":false}}],"condition":{"operation":{"operator":"=","operand0":{"value":"id"},"operand1":{"value":null,"param_spec":{"name":"-0","descr":null,"type":"int","is_param":false,"nullok":false}}}}}}}</update>
+    <delete>{"statement":{"sql":null,"stmt_type":"DELETE","contents":{"table":"customers","condition":{"operation":{"operator":"=","operand0":{"value":"id"},"operand1":{"value":null,"param_spec":{"name":"-0","descr":null,"type":"int","is_param":false,"nullok":false}}}}}}}</delete>
   </test>
 
   <test id="0.1">
     <sql valid="t">SELECT id, 3.14, name FROM customers</sql>
-    <insert>{"statement":{"sql":null,"stmt_type":"INSERT","contents":{"table":"customers","fields":["id","name"],"values":[[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"gint","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+2","descr":null,"type":"gchararray","is_param":false,"nullok":false}}]]}}}</insert>
+    <insert>{"statement":{"sql":null,"stmt_type":"INSERT","contents":{"table":"customers","fields":["id","name"],"values":[[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"int","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+2","descr":null,"type":"string","is_param":false,"nullok":false}}]]}}}</insert>
   </test>
 
   <test id="0.2">
     <sql valid="t">SELECT id, 3.14, name, id FROM customers</sql>
-    <insert>{"statement":{"sql":null,"stmt_type":"INSERT","contents":{"table":"customers","fields":["id","name"],"values":[[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"gint","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+2","descr":null,"type":"gchararray","is_param":false,"nullok":false}}]]}}}</insert>
+    <insert>{"statement":{"sql":null,"stmt_type":"INSERT","contents":{"table":"customers","fields":["id","name"],"values":[[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"int","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+2","descr":null,"type":"string","is_param":false,"nullok":false}}]]}}}</insert>
   </test>
 
   <test id="0.3">
@@ -99,15 +99,15 @@
   <test id="N1">
     <sql valid="t">SELECT name, *, city FROM customers</sql>
     <normalized>{"statement":{"sql":"SELECT name, *, city FROM customers","stmt_type":"SELECT","contents":{"distinct":"false","fields":[{"expr":{"value":"name"},"field_name":"name"},{"expr":{"value":"id"},"field_name":"id"},{"expr":{"value":"name"},"field_name":"name"},{"expr":{"value":"default_served_by"},"field_name":"default_served_by"},{"expr":{"value":"country"},"field_name":"country"},{"expr":{"value":"city"},"field_name":"city"},{"expr":{"value":"city"},"field_name":"city"}],"from":{"targets":[{"expr":{"value":"customers"},"table_name":"customers"}]}}}}</normalized>
-    <insert>{"statement":{"sql":null,"stmt_type":"INSERT","contents":{"table":"customers","fields":["name","id","default_served_by","country","city"],"values":[[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"gchararray","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"gint","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+3","descr":null,"type":"gint","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+4","descr":null,"type":"gchararray","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+5","descr":null,"type":"gchararray","is_param":false,"nullok":true}}]]}}}</insert>
-    <update>{"statement":{"sql":null,"stmt_type":"UPDATE","contents":{"table":"customers","fields":["name","id","default_served_by","country","city"],"expressions":[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"gchararray","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"gint","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+3","descr":null,"type":"gint","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+4","descr":null,"type":"gchararray","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+5","descr":null,"type":"gchararray","is_param":false,"nullok":true}}],"condition":{"operation":{"operator":"=","operand0":{"value":"id"},"operand1":{"value":null,"param_spec":{"name":"-1","descr":null,"type":"gint","is_param":false,"nullok":false}}}}}}}</update>
-    <delete>{"statement":{"sql":null,"stmt_type":"DELETE","contents":{"table":"customers","condition":{"operation":{"operator":"=","operand0":{"value":"id"},"operand1":{"value":null,"param_spec":{"name":"-1","descr":null,"type":"gint","is_param":false,"nullok":false}}}}}}}</delete>
+    <insert>{"statement":{"sql":null,"stmt_type":"INSERT","contents":{"table":"customers","fields":["name","id","default_served_by","country","city"],"values":[[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"string","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"int","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+3","descr":null,"type":"int","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+4","descr":null,"type":"string","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+5","descr":null,"type":"string","is_param":false,"nullok":true}}]]}}}</insert>
+    <update>{"statement":{"sql":null,"stmt_type":"UPDATE","contents":{"table":"customers","fields":["name","id","default_served_by","country","city"],"expressions":[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"string","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"int","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+3","descr":null,"type":"int","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+4","descr":null,"type":"string","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+5","descr":null,"type":"string","is_param":false,"nullok":true}}],"condition":{"operation":{"operator":"=","operand0":{"value":"id"},"operand1":{"value":null,"param_spec":{"name":"-1","descr":null,"type":"int","is_param":false,"nullok":false}}}}}}}</update>
+    <delete>{"statement":{"sql":null,"stmt_type":"DELETE","contents":{"table":"customers","condition":{"operation":{"operator":"=","operand0":{"value":"id"},"operand1":{"value":null,"param_spec":{"name":"-1","descr":null,"type":"int","is_param":false,"nullok":false}}}}}}}</delete>
   </test>
 
   <test id="N2">
     <sql valid="t">SELECT s.* FROM sales_orga as s</sql>
     <normalized>{"statement":{"sql":"SELECT s.* FROM sales_orga as s","stmt_type":"SELECT","contents":{"distinct":"false","fields":[{"expr":{"value":"s.id_salesrep"},"field_name":"id_salesrep","table_name":"s"},{"expr":{"value":"s.id_role"},"field_name":"id_role","table_name":"s"},{"expr":{"value":"s.note"},"field_name":"note","table_name":"s"}],"from":{"targets":[{"expr":{"value":"sales_orga"},"table_name":"sales_orga","as":"s"}]}}}}</normalized>
-    <insert>{"statement":{"sql":null,"stmt_type":"INSERT","contents":{"table":"sales_orga","fields":["id_salesrep","id_role","note"],"values":[[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"gint","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"gint","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+2","descr":null,"type":"gchararray","is_param":false,"nullok":true}}]]}}}</insert>
+    <insert>{"statement":{"sql":null,"stmt_type":"INSERT","contents":{"table":"sales_orga","fields":["id_salesrep","id_role","note"],"values":[[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"int","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"int","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+2","descr":null,"type":"string","is_param":false,"nullok":true}}]]}}}</insert>
     <update></update>
     <delete></delete>
     <update needpk="f"></update>
@@ -117,25 +117,25 @@
   <test id="N3">
     <sql valid="t">SELECT "name", c.*, "id" FROM customers as c</sql>
     <normalized>{"statement":{"sql":"SELECT \"name\", c.*, \"id\" FROM customers as c","stmt_type":"SELECT","contents":{"distinct":"false","fields":[{"expr":{"value":"\"name\""},"field_name":"\"name\""},{"expr":{"value":"c.id"},"field_name":"id","table_name":"c"},{"expr":{"value":"c.name"},"field_name":"name","table_name":"c"},{"expr":{"value":"c.default_served_by"},"field_name":"default_served_by","table_name":"c"},{"expr":{"value":"c.country"},"field_name":"country","table_name":"c"},{"expr":{"value":"c.city"},"field_name":"city","table_name":"c"},{"expr":{"value":"\"id\""},"field_name":"\"id\""}],"from":{"targets":[{"expr":{"value":"customers"},"table_name":"customers","as":"c"}]}}}}</normalized>
-    <insert>{"statement":{"sql":null,"stmt_type":"INSERT","contents":{"table":"customers","fields":["\"name\"","id","default_served_by","country","city"],"values":[[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"gchararray","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"gint","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+3","descr":null,"type":"gint","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+4","descr":null,"type":"gchararray","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+5","descr":null,"type":"gchararray","is_param":false,"nullok":true}}]]}}}</insert>
-    <update>{"statement":{"sql":null,"stmt_type":"UPDATE","contents":{"table":"customers","fields":["\"name\"","id","default_served_by","country","city"],"expressions":[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"gchararray","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"gint","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+3","descr":null,"type":"gint","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+4","descr":null,"type":"gchararray","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+5","descr":null,"type":"gchararray","is_param":false,"nullok":true}}],"condition":{"operation":{"operator":"=","operand0":{"value":"id"},"operand1":{"value":null,"param_spec":{"name":"-1","descr":null,"type":"gint","is_param":false,"nullok":false}}}}}}}</update>
-    <delete>{"statement":{"sql":null,"stmt_type":"DELETE","contents":{"table":"customers","condition":{"operation":{"operator":"=","operand0":{"value":"id"},"operand1":{"value":null,"param_spec":{"name":"-1","descr":null,"type":"gint","is_param":false,"nullok":false}}}}}}}</delete>
+    <insert>{"statement":{"sql":null,"stmt_type":"INSERT","contents":{"table":"customers","fields":["\"name\"","id","default_served_by","country","city"],"values":[[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"string","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"int","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+3","descr":null,"type":"int","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+4","descr":null,"type":"string","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+5","descr":null,"type":"string","is_param":false,"nullok":true}}]]}}}</insert>
+    <update>{"statement":{"sql":null,"stmt_type":"UPDATE","contents":{"table":"customers","fields":["\"name\"","id","default_served_by","country","city"],"expressions":[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"string","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"int","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+3","descr":null,"type":"int","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+4","descr":null,"type":"string","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+5","descr":null,"type":"string","is_param":false,"nullok":true}}],"condition":{"operation":{"operator":"=","operand0":{"value":"id"},"operand1":{"value":null,"param_spec":{"name":"-1","descr":null,"type":"int","is_param":false,"nullok":false}}}}}}}</update>
+    <delete>{"statement":{"sql":null,"stmt_type":"DELETE","contents":{"table":"customers","condition":{"operation":{"operator":"=","operand0":{"value":"id"},"operand1":{"value":null,"param_spec":{"name":"-1","descr":null,"type":"int","is_param":false,"nullok":false}}}}}}}</delete>
   </test>
 
   <test id="N4">
     <sql valid="t">SELECT "name", "customers".*, "id" FROM customers as c</sql>
     <normalized>{"statement":{"sql":"SELECT \"name\", \"customers\".*, \"id\" FROM customers as c","stmt_type":"SELECT","contents":{"distinct":"false","fields":[{"expr":{"value":"\"name\""},"field_name":"\"name\""},{"expr":{"value":"\"customers\".id"},"field_name":"id","table_name":"\"customers\""},{"expr":{"value":"\"customers\".name"},"field_name":"name","table_name":"\"customers\""},{"expr":{"value":"\"customers\".default_served_by"},"field_name":"default_served_by","table_name":"\"customers\""},{"expr":{"value":"\"customers\".country"},"field_name":"country","table_name":"\"customers\""},{"expr":{"value":"\"customers\".city"},"field_name":"city","table_name":"\"customers\""},{"expr":{"value":"\"id\""},"field_name":"\"id\""}],"from":{"targets":[{"expr":{"value":"customers"},"table_name":"customers","as":"c"}]}}}}</normalized>
-    <insert>{"statement":{"sql":null,"stmt_type":"INSERT","contents":{"table":"customers","fields":["\"name\"","id","default_served_by","country","city"],"values":[[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"gchararray","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"gint","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+3","descr":null,"type":"gint","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+4","descr":null,"type":"gchararray","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+5","descr":null,"type":"gchararray","is_param":false,"nullok":true}}]]}}}</insert>
-    <update>{"statement":{"sql":null,"stmt_type":"UPDATE","contents":{"table":"customers","fields":["\"name\"","id","default_served_by","country","city"],"expressions":[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"gchararray","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"gint","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+3","descr":null,"type":"gint","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+4","descr":null,"type":"gchararray","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+5","descr":null,"type":"gchararray","is_param":false,"nullok":true}}],"condition":{"operation":{"operator":"=","operand0":{"value":"id"},"operand1":{"value":null,"param_spec":{"name":"-1","descr":null,"type":"gint","is_param":false,"nullok":false}}}}}}}</update>
-    <delete>{"statement":{"sql":null,"stmt_type":"DELETE","contents":{"table":"customers","condition":{"operation":{"operator":"=","operand0":{"value":"id"},"operand1":{"value":null,"param_spec":{"name":"-1","descr":null,"type":"gint","is_param":false,"nullok":false}}}}}}}</delete>
+    <insert>{"statement":{"sql":null,"stmt_type":"INSERT","contents":{"table":"customers","fields":["\"name\"","id","default_served_by","country","city"],"values":[[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"string","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"int","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+3","descr":null,"type":"int","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+4","descr":null,"type":"string","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+5","descr":null,"type":"string","is_param":false,"nullok":true}}]]}}}</insert>
+    <update>{"statement":{"sql":null,"stmt_type":"UPDATE","contents":{"table":"customers","fields":["\"name\"","id","default_served_by","country","city"],"expressions":[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"string","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"int","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+3","descr":null,"type":"int","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+4","descr":null,"type":"string","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+5","descr":null,"type":"string","is_param":false,"nullok":true}}],"condition":{"operation":{"operator":"=","operand0":{"value":"id"},"operand1":{"value":null,"param_spec":{"name":"-1","descr":null,"type":"int","is_param":false,"nullok":false}}}}}}}</update>
+    <delete>{"statement":{"sql":null,"stmt_type":"DELETE","contents":{"table":"customers","condition":{"operation":{"operator":"=","operand0":{"value":"id"},"operand1":{"value":null,"param_spec":{"name":"-1","descr":null,"type":"int","is_param":false,"nullok":false}}}}}}}</delete>
   </test>
 
   <test id="N5">
     <sql valid="t">SELECT NaMe, c."*", ID FROM customers as c</sql>
     <normalized>{"statement":{"sql":"SELECT NaMe, c.\"*\", ID FROM customers as c","stmt_type":"SELECT","contents":{"distinct":"false","fields":[{"expr":{"value":"NaMe"},"field_name":"NaMe"},{"expr":{"value":"c.id"},"field_name":"id","table_name":"c"},{"expr":{"value":"c.name"},"field_name":"name","table_name":"c"},{"expr":{"value":"c.default_served_by"},"field_name":"default_served_by","table_name":"c"},{"expr":{"value":"c.country"},"field_name":"country","table_name":"c"},{"expr":{"value":"c.city"},"field_name":"city","table_name":"c"},{"expr":{"value":"ID"},"field_name":"ID"}],"from":{"targets":[{"expr":{"value":"customers"},"table_name":"customers","as":"c"}]}}}}</normalized>
-    <insert>{"statement":{"sql":null,"stmt_type":"INSERT","contents":{"table":"customers","fields":["NaMe","id","default_served_by","country","city"],"values":[[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"gchararray","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"gint","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+3","descr":null,"type":"gint","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+4","descr":null,"type":"gchararray","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+5","descr":null,"type":"gchararray","is_param":false,"nullok":true}}]]}}}</insert>
-    <update>{"statement":{"sql":null,"stmt_type":"UPDATE","contents":{"table":"customers","fields":["NaMe","id","default_served_by","country","city"],"expressions":[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"gchararray","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"gint","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+3","descr":null,"type":"gint","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+4","descr":null,"type":"gchararray","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+5","descr":null,"type":"gchararray","is_param":false,"nullok":true}}],"condition":{"operation":{"operator":"=","operand0":{"value":"id"},"operand1":{"value":null,"param_spec":{"name":"-1","descr":null,"type":"gint","is_param":false,"nullok":false}}}}}}}</update>
-    <delete>{"statement":{"sql":null,"stmt_type":"DELETE","contents":{"table":"customers","condition":{"operation":{"operator":"=","operand0":{"value":"id"},"operand1":{"value":null,"param_spec":{"name":"-1","descr":null,"type":"gint","is_param":false,"nullok":false}}}}}}}</delete>
+    <insert>{"statement":{"sql":null,"stmt_type":"INSERT","contents":{"table":"customers","fields":["NaMe","id","default_served_by","country","city"],"values":[[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"string","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"int","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+3","descr":null,"type":"int","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+4","descr":null,"type":"string","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+5","descr":null,"type":"string","is_param":false,"nullok":true}}]]}}}</insert>
+    <update>{"statement":{"sql":null,"stmt_type":"UPDATE","contents":{"table":"customers","fields":["NaMe","id","default_served_by","country","city"],"expressions":[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"string","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"int","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+3","descr":null,"type":"int","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+4","descr":null,"type":"string","is_param":false,"nullok":true}},{"value":null,"param_spec":{"name":"+5","descr":null,"type":"string","is_param":false,"nullok":true}}],"condition":{"operation":{"operator":"=","operand0":{"value":"id"},"operand1":{"value":null,"param_spec":{"name":"-1","descr":null,"type":"int","is_param":false,"nullok":false}}}}}}}</update>
+    <delete>{"statement":{"sql":null,"stmt_type":"DELETE","contents":{"table":"customers","condition":{"operation":{"operator":"=","operand0":{"value":"id"},"operand1":{"value":null,"param_spec":{"name":"-1","descr":null,"type":"int","is_param":false,"nullok":false}}}}}}}</delete>
   </test>
 
 </testdata>

Modified: trunk/tests/providers/DATA_actor.xml
==============================================================================
--- trunk/tests/providers/DATA_actor.xml	(original)
+++ trunk/tests/providers/DATA_actor.xml	Fri Jan  9 20:40:50 2009
@@ -1,9 +1,9 @@
 <?xml version="1.0"?>
 <gda_array id="EXPORT" name="Exported Data">
-  <gda_array_field id="FI0" name="actor_id" title="actor_id" gdatype="gint" nullok="TRUE"/>
-  <gda_array_field id="FI1" name="first_name" title="first_name" gdatype="gchararray" nullok="TRUE"/>
-  <gda_array_field id="FI2" name="last_name" title="last_name" gdatype="gchararray" nullok="TRUE"/>
-  <gda_array_field id="FI3" name="last_update" title="last_update" gdatype="GdaTimestamp" nullok="TRUE"/>
+  <gda_array_field id="FI0" name="actor_id" title="actor_id" gdatype="int" nullok="TRUE"/>
+  <gda_array_field id="FI1" name="first_name" title="first_name" gdatype="string" nullok="TRUE"/>
+  <gda_array_field id="FI2" name="last_name" title="last_name" gdatype="string" nullok="TRUE"/>
+  <gda_array_field id="FI3" name="last_update" title="last_update" gdatype="timestamp" nullok="TRUE"/>
   <gda_array_data>
     <gda_array_row>
       <gda_value>1</gda_value>

Modified: trunk/tests/providers/DATA_film.xml
==============================================================================
--- trunk/tests/providers/DATA_film.xml	(original)
+++ trunk/tests/providers/DATA_film.xml	Fri Jan  9 20:40:50 2009
@@ -1,18 +1,18 @@
 <?xml version="1.0"?>
 <gda_array id="EXPORT" name="Exported Data">
-  <gda_array_field id="FI0" name="film_id" title="film_id" gdatype="gint" nullok="TRUE"/>
-  <gda_array_field id="FI1" name="title" title="title" gdatype="gchararray" nullok="TRUE"/>
-  <gda_array_field id="FI2" name="description" title="description" gdatype="gchararray" nullok="TRUE"/>
-  <gda_array_field id="FI3" name="release_year" title="release_year" gdatype="gint" nullok="TRUE"/>
+  <gda_array_field id="FI0" name="film_id" title="film_id" gdatype="int" nullok="TRUE"/>
+  <gda_array_field id="FI1" name="title" title="title" gdatype="string" nullok="TRUE"/>
+  <gda_array_field id="FI2" name="description" title="description" gdatype="string" nullok="TRUE"/>
+  <gda_array_field id="FI3" name="release_year" title="release_year" gdatype="int" nullok="TRUE"/>
   <gda_array_field id="FI4" name="language_id" title="language_id" gdatype="GdaShort" nullok="TRUE"/>
   <gda_array_field id="FI5" name="original_language_id" title="original_language_id" gdatype="GdaShort" nullok="TRUE"/>
   <gda_array_field id="FI6" name="rental_duration" title="rental_duration" gdatype="GdaShort" nullok="TRUE"/>
   <gda_array_field id="FI7" name="rental_rate" title="rental_rate" gdatype="GdaNumeric" nullok="TRUE"/>
   <gda_array_field id="FI8" name="length" title="length" gdatype="GdaShort" nullok="TRUE"/>
   <gda_array_field id="FI9" name="replacement_cost" title="replacement_cost" gdatype="GdaNumeric" nullok="TRUE"/>
-  <gda_array_field id="FI10" name="rating" title="rating" gdatype="gchararray" nullok="TRUE"/>
-  <gda_array_field id="FI11" name="last_update" title="last_update" gdatype="GdaTimestamp" nullok="TRUE"/>
-  <gda_array_field id="FI12" name="special_features" title="special_features" gdatype="gchararray" nullok="TRUE"/>
+  <gda_array_field id="FI10" name="rating" title="rating" gdatype="string" nullok="TRUE"/>
+  <gda_array_field id="FI11" name="last_update" title="last_update" gdatype="timestamp" nullok="TRUE"/>
+  <gda_array_field id="FI12" name="special_features" title="special_features" gdatype="string" nullok="TRUE"/>
   <gda_array_data>
     <gda_array_row>
       <gda_value>1</gda_value>

Modified: trunk/tests/providers/DATA_film_actor.xml
==============================================================================
--- trunk/tests/providers/DATA_film_actor.xml	(original)
+++ trunk/tests/providers/DATA_film_actor.xml	Fri Jan  9 20:40:50 2009
@@ -2,7 +2,7 @@
 <gda_array id="EXPORT" name="Exported Data">
   <gda_array_field id="FI0" name="actor_id" title="actor_id" gdatype="GdaShort" nullok="TRUE"/>
   <gda_array_field id="FI1" name="film_id" title="film_id" gdatype="GdaShort" nullok="TRUE"/>
-  <gda_array_field id="FI2" name="last_update" title="last_update" gdatype="GdaTimestamp" nullok="TRUE"/>
+  <gda_array_field id="FI2" name="last_update" title="last_update" gdatype="timestamp" nullok="TRUE"/>
   <gda_array_data>
     <gda_array_row>
       <gda_value>1</gda_value>

Modified: trunk/tests/providers/DATA_language.xml
==============================================================================
--- trunk/tests/providers/DATA_language.xml	(original)
+++ trunk/tests/providers/DATA_language.xml	Fri Jan  9 20:40:50 2009
@@ -1,8 +1,8 @@
 <?xml version="1.0"?>
 <gda_array id="EXPORT" name="Exported Data">
-  <gda_array_field id="FI0" name="language_id" title="language_id" gdatype="gint" nullok="TRUE"/>
-  <gda_array_field id="FI1" name="name" title="name" gdatype="gchararray" nullok="TRUE"/>
-  <gda_array_field id="FI2" name="last_update" title="last_update" gdatype="GdaTimestamp" nullok="TRUE"/>
+  <gda_array_field id="FI0" name="language_id" title="language_id" gdatype="int" nullok="TRUE"/>
+  <gda_array_field id="FI1" name="name" title="name" gdatype="string" nullok="TRUE"/>
+  <gda_array_field id="FI2" name="last_update" title="last_update" gdatype="timestamp" nullok="TRUE"/>
   <gda_array_data>
     <gda_array_row>
       <gda_value>1</gda_value>

Modified: trunk/tests/providers/TYPES_SCHEMA_Mdb.xml
==============================================================================
--- trunk/tests/providers/TYPES_SCHEMA_Mdb.xml	(original)
+++ trunk/tests/providers/TYPES_SCHEMA_Mdb.xml	Fri Jan  9 20:40:50 2009
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
 <gda_array id="EXPORT" name="Exported Data">
-  <gda_array_field id="FI0" name="Type" title="Type" gdatype="gchararray" nullok="TRUE"/>
-  <gda_array_field id="FI1" name="Owner" title="Owner" gdatype="gchararray" nullok="TRUE"/>
-  <gda_array_field id="FI2" name="Comments" title="Comments" gdatype="gchararray" nullok="TRUE"/>
+  <gda_array_field id="FI0" name="Type" title="Type" gdatype="string" nullok="TRUE"/>
+  <gda_array_field id="FI1" name="Owner" title="Owner" gdatype="string" nullok="TRUE"/>
+  <gda_array_field id="FI2" name="Comments" title="Comments" gdatype="string" nullok="TRUE"/>
   <gda_array_field id="FI3" name="GDA type" title="GDA type" gdatype="gulong" nullok="TRUE"/>
-  <gda_array_field id="FI4" name="Synonyms" title="Synonyms" gdatype="gchararray" nullok="TRUE"/>
+  <gda_array_field id="FI4" name="Synonyms" title="Synonyms" gdatype="string" nullok="TRUE"/>
   <gda_array_data>
     <gda_array_row>
       <gda_value>boolean</gda_value>

Modified: trunk/tests/providers/TYPES_SCHEMA_MySQL.xml
==============================================================================
--- trunk/tests/providers/TYPES_SCHEMA_MySQL.xml	(original)
+++ trunk/tests/providers/TYPES_SCHEMA_MySQL.xml	Fri Jan  9 20:40:50 2009
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
 <gda_array id="EXPORT" name="Exported Data">
-  <gda_array_field id="FI0" name="Type" title="Type" gdatype="gchararray" nullok="TRUE"/>
-  <gda_array_field id="FI1" name="Owner" title="Owner" gdatype="gchararray" nullok="TRUE"/>
-  <gda_array_field id="FI2" name="Comments" title="Comments" gdatype="gchararray" nullok="TRUE"/>
+  <gda_array_field id="FI0" name="Type" title="Type" gdatype="string" nullok="TRUE"/>
+  <gda_array_field id="FI1" name="Owner" title="Owner" gdatype="string" nullok="TRUE"/>
+  <gda_array_field id="FI2" name="Comments" title="Comments" gdatype="string" nullok="TRUE"/>
   <gda_array_field id="FI3" name="GDA type" title="GDA type" gdatype="gulong" nullok="TRUE"/>
-  <gda_array_field id="FI4" name="Synonyms" title="Synonyms" gdatype="gchararray" nullok="TRUE"/>
+  <gda_array_field id="FI4" name="Synonyms" title="Synonyms" gdatype="string" nullok="TRUE"/>
   <gda_array_data>
     <gda_array_row>
       <gda_value>bool</gda_value>

Modified: trunk/tests/providers/TYPES_SCHEMA_Oracle.xml
==============================================================================
--- trunk/tests/providers/TYPES_SCHEMA_Oracle.xml	(original)
+++ trunk/tests/providers/TYPES_SCHEMA_Oracle.xml	Fri Jan  9 20:40:50 2009
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
 <gda_array id="EXPORT" name="Exported Data">
-  <gda_array_field id="FI0" name="Type" title="Type" gdatype="gchararray" nullok="TRUE"/>
-  <gda_array_field id="FI1" name="Owner" title="Owner" gdatype="gchararray" nullok="TRUE"/>
-  <gda_array_field id="FI2" name="Comments" title="Comments" gdatype="gchararray" nullok="TRUE"/>
+  <gda_array_field id="FI0" name="Type" title="Type" gdatype="string" nullok="TRUE"/>
+  <gda_array_field id="FI1" name="Owner" title="Owner" gdatype="string" nullok="TRUE"/>
+  <gda_array_field id="FI2" name="Comments" title="Comments" gdatype="string" nullok="TRUE"/>
   <gda_array_field id="FI3" name="GDA type" title="GDA type" gdatype="gulong" nullok="TRUE"/>
-  <gda_array_field id="FI4" name="Synonyms" title="Synonyms" gdatype="gchararray" nullok="TRUE"/>
+  <gda_array_field id="FI4" name="Synonyms" title="Synonyms" gdatype="string" nullok="TRUE"/>
   <gda_array_data>
     <gda_array_row>
       <gda_value>BFILE</gda_value>

Modified: trunk/tests/providers/TYPES_SCHEMA_PostgreSQL.xml
==============================================================================
--- trunk/tests/providers/TYPES_SCHEMA_PostgreSQL.xml	(original)
+++ trunk/tests/providers/TYPES_SCHEMA_PostgreSQL.xml	Fri Jan  9 20:40:50 2009
@@ -1,8 +1,8 @@
 <?xml version="1.0"?>
 <gda_array id="EXPORT" name="Exported Data">
-  <gda_array_field id="FI0" name="short_type_name" title="short_type_name" gdatype="gchararray" nullok="TRUE"/>
-  <gda_array_field id="FI1" name="gtype" title="gtype" gdatype="gchararray" nullok="TRUE"/>
-  <gda_array_field id="FI2" name="comments" title="comments" gdatype="gchararray" nullok="TRUE"/>
+  <gda_array_field id="FI0" name="short_type_name" title="short_type_name" gdatype="string" nullok="TRUE"/>
+  <gda_array_field id="FI1" name="gtype" title="gtype" gdatype="string" nullok="TRUE"/>
+  <gda_array_field id="FI2" name="comments" title="comments" gdatype="string" nullok="TRUE"/>
   <gda_array_field id="FI3" name="synonyms" title="synonyms" gdatype="null" nullok="TRUE"/>
   <gda_array_data>
     <gda_array_row>

Modified: trunk/tests/providers/TYPES_SCHEMA_SQLite.xml
==============================================================================
--- trunk/tests/providers/TYPES_SCHEMA_SQLite.xml	(original)
+++ trunk/tests/providers/TYPES_SCHEMA_SQLite.xml	Fri Jan  9 20:40:50 2009
@@ -1,9 +1,9 @@
 <?xml version="1.0"?>
 <gda_array id="EXPORT" name="Exported Data">
-  <gda_array_field id="FI0" name="short_type_name" title="short_type_name" gdatype="gchararray" nullok="TRUE"/>
-  <gda_array_field id="FI1" name="gtype" title="gtype" gdatype="gchararray" nullok="TRUE"/>
-  <gda_array_field id="FI2" name="comments" title="comments" gdatype="gchararray" nullok="TRUE"/>
-  <gda_array_field id="FI3" name="synonyms" title="synonyms" gdatype="gchararray" nullok="TRUE"/>
+  <gda_array_field id="FI0" name="short_type_name" title="short_type_name" gdatype="string" nullok="TRUE"/>
+  <gda_array_field id="FI1" name="gtype" title="gtype" gdatype="string" nullok="TRUE"/>
+  <gda_array_field id="FI2" name="comments" title="comments" gdatype="string" nullok="TRUE"/>
+  <gda_array_field id="FI3" name="synonyms" title="synonyms" gdatype="string" nullok="TRUE"/>
   <gda_array_data>
     <gda_array_row>
       <gda_value>blob</gda_value>

Modified: trunk/tools/Makefile.am
==============================================================================
--- trunk/tools/Makefile.am	(original)
+++ trunk/tools/Makefile.am	Fri Jan  9 20:40:50 2009
@@ -90,3 +90,51 @@
 
 EXTRA_DIST = gda-sql.ico \
 	$(webdata_DATA)
+
+mans = \
+	gda-sql-4.0.1
+
+man_MANS = \
+	$(mans)
+
+install-data-hook:
+if DEFAULT_BINARY
+	@list='$(mans)'; \
+	for i in $$list; do \
+	  s=`echo $$i | sed -e 's/.*\\(.\\)$$/\1/'`; \
+	  n=`echo $$i | sed -e 's/-[^-]*$$//'`; \
+	  f="$$n.$$s"; \
+	  echo "cd $(DESTDIR)$(mandir)/man$$s"; \
+	  cd $(DESTDIR)$(mandir)/man$$s; \
+	  echo "rm -f $$f"; \
+	  rm -f $$f; \
+	  echo "ln -s $$i $$f"; \
+	  ln -s $$i $$f; \
+	done
+endif
+
+uninstall-local:
+if DEFAULT_BINARY
+	@list='$(mans)'; \
+	for i in $$list; do \
+	  s=`echo $$i | sed -e 's/.*\\(.\\)$$/\1/'`; \
+	  n=`echo $$i | sed -e 's/-[^-]*$$//'`; \
+	  f="$$n.$$s"; \
+	  echo " rm -f $(DESTDIR)$(mandir)/man$$s/$$f"; \
+	  rm -f $(DESTDIR)$(mandir)/man$$s/$$f; \
+	done
+endif
+
+install-exec-hook:
+if DEFAULT_BINARY
+	cd $(DESTDIR)$(bindir) \
+	&& rm -f gda-list-config$(EXEEXT) gda-sql$(EXEEXT) gda-list-server-op$(EXEEXT) \
+	&& $(LN_S) gda-list-config-4.0$(EXEEXT) gda-list-config$(EXEEXT) \
+	&& $(LN_S) gda-sql-4.0$(EXEEXT) gda-sql$(EXEEXT) \
+	&& $(LN_S) gda-list-server-op-4.0$(EXEEXT) gda-list-server-op$(EXEEXT)
+endif
+
+uninstall-local:
+if DEFAULT_BINARY
+	rm -f $(DESTDIR)$(bindir)/gda-list-config$(EXEEXT) $(DESTDIR)$(bindir)/gda-sql$(EXEEXT) $(DESTDIR)$(bindir)/gda-list-server-op$(EXEEXT)
+endif
\ No newline at end of file

Added: trunk/tools/gda-sql.1.in
==============================================================================
--- (empty file)
+++ trunk/tools/gda-sql.1.in	Fri Jan  9 20:40:50 2009
@@ -0,0 +1,294 @@
+.TH gda-sql 1 "January 09 2009" "Version @PACKAGE_VERSION@" "LIBGDA Manual Pages"
+
+.SH NAME
+gda-sql - an SQL console based on Libgda
+
+.SH SYNOPSIS
+.B gda-sql
+[\-\-help] [-v] [\-\-version]
+[\-p] [\-\-no\-password\-ask]
+[\-o] [\-\-output\-file \fI<filename>\fP]
+[\-C] [\-\-command]
+[\-f] [\-\-commands\-file \fI<filename>\fP]
+[\-i] [\-\-interractive]
+[\-l] [\-\-list\-dsn]
+[\-L] [\-\-list\-providers]
+[\-s] [\-\-http\-port \fI<port>\fP]
+[\-t] [\-\-http\-token \fI<token phrase>\fP] ...
+
+.SH DESCRIPTION
+.PP
+gda-sql is an SQL console based on the \fILibgda\fP library.
+.PP
+It enables you to type in queries interactively, issue them to be executed by a connection, and see the
+query results.
+.PP
+Several connections can be opened at the same time, allowing you to switch the active connection to any
+opened connection. When starting, gda-sql opens a connection for each connection specified on the command
+line (plus optionnally one corresponding to the \fBGDA_SQL_CNC\fP environment variable). The prompt
+indicates the current connection used when executing commands.
+
+.PP
+Alternatively, input can be from a file.
+In addition, it provides a number of meta-commands and various shell-like features to facilitate writing
+scripts and automating a wide variety of tasks.
+
+
+
+.SH OPTIONS
+.l
+gda-sql accepts the following options:
+.TP 8
+.B  \-\-help
+Show command\-line options.
+.TP 8
+.B \-p, \-\-no\-password\-ask
+Don't ask for a password when it is empty.
+.TP 8
+.B \-o, \-\-output\-file \fI<filename>\fP
+Specifies a file to which outputs are redirected.
+.TP 8
+.B \-C, \-\-command
+Run only single command (SQL or internal) and exit.
+.TP 8
+.B \-f, \-\-commands\-file \fI<filename>\fP
+Execute commands from \fI<filename>\fP, then exit (except if \-i specified).
+.TP 8
+.B \-i, \-\-interractive
+Keep the console opened after executing a file (used with the \-f option).
+.TP 8
+.B \-l, \-\-list\-dsn
+List configured data sources and exit.
+.TP 8
+.B \-l, \-\-list\-providers
+List installed database providers and exit
+.TP 8
+.B \-s, \-\-http\-port \fI<port>\fP
+Starts the embedded HTTP server on port \fI<port>\fP
+.TP 8
+.B \-t, \-\-http\-token \fI<token phrase>\fP
+Requires HTTP clients to authenticate by providing the \fI<token phrase>\fP
+(empty phrase by default)
+
+
+
+.SH ENVIRONMENT
+gda-sql respects a number of environment variables.
+.PP
+.TP 8
+.B GDA_SQL_CNC
+to define a connection to systematically be opened when the program starts.
+.TP 8
+.B PAGER
+to define a text pager program to use (by default determined by the system).
+.TP 8
+.B GDA_NO_PAGER
+to specify that no text pager should be used.
+.TP 8
+.B GDA_SQL_EDITOR EDITOR VISUAL
+to define a text editor to be used (variables are examined in this order).
+.TP 8
+.B GDA_SQL_VIEWER_PNG
+to define a PNG viewer.
+.TP 8
+.B GDA_SQL_VIEWER_PDF
+to define a PDF viewer.
+.TP 8
+.B GDA_SQL_HISTFILE
+to define the history file name to use (by default .gdasql_history), set to NO_HISTORY
+to disable history logging.
+
+.TP 0
+gda-sql can be compiled with support for binary relocatibility.
+This will cause data, plug-ins and configuration files to be searched
+relative to the location of the gda-sql executable file.
+
+
+.SH FILES
+gda-sql stores data source definitions (DSN) in Libgda defined files 
+(\fB$HOME\fP/.libgda/config and @gdasysconfdir@/libgda- GDA_ABI_VERSION@/config
+where ${prefix} is typically /usr).
+
+For each connection defined by a DSN, the meta data is stored in a
+\fB$HOME\fP/.libgda/gda-sql-<DSN>.db file.
+
+
+.SH SQL commands
+You can run any SQL understood by the database engine of the current connection.
+Additionnally SQL statement can contain variables expressed as \fI##<name>::<type>\fP
+where \fI<name>\fP is the variable's name and \fI<type>\fP is its declared type (which
+can be "int", "string", "boolean", "time", "date", "timestamp" (and other types defined
+by GLib's syntax).
+
+Use the \fI.set\fP internal command to set variable's values.
+
+.SH Internal commands
+In addition to SQL commands, gda-sql supports internal commands which differ from SQL
+commands because they start with the "." or "\\" character. These commands are:
+
+.IP \fB.?\fP
+Lists all internal commands
+.IP \fB.bind\fP
+Bind two or more connections into a single new one (allowing SQL commands to be executed across multiple
+connections). \fB.bind <CNC_NAME> <CNC_NAME1> <CNC_NAME2> [<CNC_NAME> ...]\fP creates a new connection named
+\fI<CNC_NAME>\fP which binds the tables of the \fI<CNC_NAME1>\fP, \fI<CNC_NAME2>\fP and any other
+connection specified.
+.IP \fB.c\fP
+Opens a connection or sets the current connection.
+
+\fB.c <CNC_NAME> <DSN_NAME> [USER [PASSWORD]]\fP opens a connection internally known as \fI<CNC_NAME>\fP,
+using the specified DSN.
+
+\fB.c <CNC_NAME> <CNC_DEFINITION> [USER [PASSWORD]] \fP opens a connection internally known as \fI<CNC_NAME>\fP,
+using a connection specified by \fI<CNC_DEFINITION>\fP which is similar to the \fI<DSN_DEFINITION>\fP parameter
+of the \fB.lc\fP command.
+
+\fB.c <CNC_NAME>\fP sets the current connection to the connection known as \fI<CNC_NAME>\fP.
+
+\fB.c ~\fP or \fB.c ~<CNC_NAME>\fP set the current connection to the meta data corresponding to the
+current connection (for the first notation) or to the meta data corresponding to the \fI<CNC_NAME>\fP
+connection.
+.IP \fB.close\fP
+Closes a connection. Full syntax is: \fB.close <CNC_NAME>\fP.
+.IP \fB.cd\fP
+Changes the current working directory. Full syntax is: \fB.cd <DIR_NAME>\fP.
+.IP \fB.copyright\fP
+Displays copyright information.
+.IP \fB.d\fP
+Lists all database objects if no argument is provided. \fB.d <OBJ_NAME>\fP gives details about
+the specified object and \fB.d <SCHEMA>.*\fP lists all objects in specified schema.
+.IP \fB.dn\fP
+Lists all schemas if no argument is provided. \fB.d <SCHEMA_NAME>\fP lists specified schema.
+.IP \fB.dt\fP
+Lists all tables if no argument is provided. \fB.d <TABLE_NAME>\fP lists specified table.
+.IP \fB.dv\fP
+Lists all views if no argument is provided. \fB.d <VIEW_NAME>\fP lists specified view.
+.IP \fB.e\fP
+Edits the query buffer with external editor, if no argument is provided. \fB.e <FILE_NAME>\fP
+edits the specified file name. The external editor can be specified using environment variables.
+.IP \fB.echo\fP
+Sends output to stdout, full command is: \fB.echo [<TEXT>]\fP.
+.IP \fB.export\fP
+Exports internal parameter or table's value to the FILE file. Internal parameters are named values
+used when SQL statement containing variables are executed.
+
+\fB.export <NAME> <FILE_NAME>\fP exports the contents of the \fI<NAME>\fP parameter to the specified
+file.
+
+\fB.export <TABLE> <COLUMN> <ROW_CONDITION> <FILE_NAME>\fP exports the value of the \fI<TABLE>\fP
+table, column \fI<COLUMN>\fP for the row selected by \fI<ROW_CONDITION>\fP to the specified
+file. This is most usefull to export BLOBs.
+.IP \fB.g\fP
+Executes the contents of the query buffer, if no parameter is provided. \fB.g <QUERY_BUFFER_NAME>\fP
+Executes the contents of the specified query buffer. A named query buffer is created using the
+\fB.qs\fP command.
+.IP \fB.graph\fP
+Creates a graph of tables showing their relations (based on foreign key constraints). If no argument
+is provided, the graph lists all tables. \fB.graph <TABLE_NAME> [<TABLE_NAME>...]\fP creates a graph
+listing the specified tables.
+
+The generated graph is created as the "gdaph.dot" file. If the \fBGDA_SQL_VIEWER_PNG\fP or \fBGDA_SQL_VIEWER_PDF\fP
+environment variables are set and if the "dot" program (from GraphViz) is found, then the graph is displayed (if
+a display is available).
+.IP \fB.H\fP
+Set output format. Full syntax is: \fB.H [HTML|XML|CSV|DEFAULT]\fP.
+.IP \fB.http\fP
+Starts/stops the embedded HTTP server. Full syntax is \fB.http [<port> [<authentication_token>]]\fP, where
+\fI<authentication_token>\fP is an optional token phrase which HTTP clients are required to send to authenticate.
+.IP \fB.i\fP
+Executes commands from file the specified file: \fB.i <FILE_NAME>\fP.
+.IP \fB.l\fP
+Lists all data sources if no argument is provided. \fB.l <DSN>\fP lists information about
+the specified DSN.
+.IP \fB.lp\fP
+Lists all available database providers if no argument is provided. \fB.lp <provider>\fP lists
+information about the specified provider.
+.IP \fB.lc\fP
+Declares a DSN. Full syntax is: \fB.lc <DSN_NAME> <DSN_DEFINITION> [<DESCRIPTION>]\fP.
+The \fI<DSN_DEFINITION>\fP format is: \fI<provider>://[<username>[:<password>] ]<connection_params>\fP
+where \fI<connection_params>\fP is a semi-colon (";") separated list of <key>=<value> pairs
+where \fI<key>\fP is defined when using \fB.lp <provider>\fP (if \fI<value>\fP contains
+non alphanumeric characters, they should be represented as specified by the RFC 1738).
+
+If a DSN with a similar name already exists, it is first removed.
+
+For example: ".lc mydsn PostgreSQL://HOST=moon;DB_NAME=mydb".
+.IP \fB.lr\fP
+Removes a DSN declaration. Full syntax is: \fB.lc <DSN_NAME>\fP.
+.IP \fB.meta\fP
+Updates the current connection's meta data (use this command after having modified the
+database's schema).
+.IP \fB.o\fP
+Sends output to a file or |pipe. Full syntax is: \fB.o <FILE_NAME>\fP or \fB.o |<COMMAND>\fP.
+.IP \fB.q\fP
+Quits the application.
+.IP \fB.qecho\fP
+Sends output to the output stream (stdout). Full syntax is: \fB.qecho <TEXT>\fP.
+.IP \fB.qa\fP
+Lists all saved query buffers in dictionary.
+.IP \fB.qd\fP
+Deletes a query buffer from the dictionary. Full syntax is: \fB.qd <QUERY_BUFFER_NAME>\fP
+.IP \fB.ql\fP
+Loads query buffer from dictionary into the current query buffer.
+Full syntax is: \fB.ql <QUERY_BUFFER_NAME>\fP.
+.IP \fB.qp\fP
+Shows the contents of the current query buffer.
+.IP \fB.qr\fP
+Resets the query buffer to empty if no argument is provided. \fB.qr <FILE _NAME>\fP loads
+the specified file into the query buffer.
+.IP \fB.qs\fP
+Saves query buffer to dictionary, full syntax is \fB.qs <QUERY_BUFFER_NAME>\fP. This creates
+a new query buffer with the specified name in the dictionary, containing the current query
+buffer.
+.IP \fB.qw\fP
+Writes the query buffer to the specified file, full syntax is \fB.qw <FILE_NAME>\fP.
+.IP \fB.s\fP
+Show commands history. \fB.s <FILE_NAME>\fP saves command history to specified file.
+.IP \fB.set\fP
+Sets, shows or lists internal parameters.
+
+\fB.set\fP lists all the defined internal parameters.
+
+\fB.set <NAME> <VALUE>\fP (re)defines the internal parameter named \fI<NAME>\fP to the
+specified value (which can be the \fI_null_\fP literal to set it to NULL).
+
+\fB.set <NAME>\fP shows the contents of the internal parameter named \fI<NAME>\fP.
+.IP \fB.setex\fP
+Set internal parameter as the contents of the FILE file or from an existing table's 
+value.
+
+\fB.setex <NAME> <FILE_NAME>\fP (re)defines the the internal parameter named \fI<NAME>\fP
+with the contents of the specified file name.
+
+\fB.setex <NAME> <TABLE> <COLUMN> <ROW_CONDITION>\fP (re)defines the the internal parameter named \fI<NAME>\fP
+with the value of the \fI<TABLE>\fP table, column \fI<COLUMN>\fP for the row selected by \fI<ROW_CONDITION>\fP.This is most usefull to export BLOBs.
+.IP \fB.unset\fP
+Unset (delete) internal parameter.
+
+\fB.unset\fP unsets all the internal parameters.
+
+\fB.unset <NAME>\fP unsets the internal parameter named \fI<NAME>\fP.
+.SH SUGGESTIONS AND BUG REPORTS
+Any bugs found should be reported to the online bug-tracking system
+available on the web at http://bugzilla.gnome.org/. Before reporting
+bugs, please check to see if the bug has already been reported.
+
+When reporting bugs, it is important to include a reliable way to
+reproduce the bug, version number of gda-sql, OS name
+and version, and any relevant hardware specs. If a bug is causing a
+crash, it is very useful if a stack trace can be provided. And of
+course, patches to rectify the bug are even better.
+
+
+.SH OTHER INFO
+Consult the Libgda's home page at http://www.gnome-db.org/.
+
+.SH AUTHORS
+Vivien Malerba (for Libgda's authors, please consult the AUTORS file
+within the Libgda's sources)
+
+
+.SH "SEE ALSO"
+.BR psql (1),
+.BR mysql (1),
+.BR sqlite3 (1)

Modified: trunk/tools/gda-sql.c
==============================================================================
--- trunk/tools/gda-sql.c	(original)
+++ trunk/tools/gda-sql.c	Fri Jan  9 20:40:50 2009
@@ -54,6 +54,7 @@
 #endif
 
 /* options */
+gboolean show_version = FALSE;
 gboolean ask_pass = FALSE;
 
 gchar *single_command = NULL;
@@ -72,6 +73,7 @@
 #endif
 
 static GOptionEntry entries[] = {
+	{ "version", 'v', 0, G_OPTION_ARG_NONE, &show_version, "Show version information and exit", NULL },	
         { "no-password-ask", 'p', 0, G_OPTION_ARG_NONE, &ask_pass, "Don't ask for a password when it is empty", NULL },
 
         { "output-file", 'o', 0, G_OPTION_ARG_STRING, &outfile, "Output file", "output file"},
@@ -82,7 +84,7 @@
         { "list-providers", 'L', 0, G_OPTION_ARG_NONE, &list_providers, "List installed database providers and exit", NULL },
 #ifdef HAVE_LIBSOUP
 	{ "http-port", 's', 0, G_OPTION_ARG_INT, &http_port, "Run embedded HTTP server on specified port", "port" },
-	{ "http-token", 't', 0, G_OPTION_ARG_STRING, &auth_token, "Authentication token (required to authenticate clients)", "token" },
+	{ "http-token", 't', 0, G_OPTION_ARG_STRING, &auth_token, "Authentication token (required to authenticate clients)", "token phrase" },
 #endif
         { NULL }
 };
@@ -166,6 +168,11 @@
         }
         g_option_context_free (context);
 
+	if (show_version) {
+		g_print (_("GDA SQL console version " PACKAGE_VERSION "\n"));
+		return 0;
+	}
+
         gda_init ();
 	sql_gbr_init ();
 



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