libgda r3058 - in branches/V4-branch: . doc/C doc/C/tmpl libgda libgda-report/engine libgda/providers-support libgda/sqlite providers providers/mdb providers/postgres providers/skel-implementation/capi tools



Author: vivien
Date: Wed Feb 20 20:36:04 2008
New Revision: 3058
URL: http://svn.gnome.org/viewvc/libgda?rev=3058&view=rev

Log:
2008-02-20  Vivien Malerba <malerba gnome-db org>

	* tools/gda-sql.c: if the GDA_NO_PAGER environment variable is set, then don't use a pager at all
	* libgda/providers-support/gda-pstmt.[ch]: prepared statement can now hold a (weak)reference to the
	GdaStatement from which it has been prepared
	* libgda/providers-support/gda-pmodel.[ch]: changed the signature of the virtual functions to allow
	implementations to return errors
	* libgda/gda-client.[ch]:
	* libgda/gda-client-private.h:
	* libgda/gda-connection.c: removed some symbols from the API/ABI
	* libgda/gda-client.[ch]: removed gda_client_close_all_connections(), gda_client_begin_transaction(),
	gda_client_commit_transaction(), gda_client_rollback_transaction() and gda_client_find_connection()
	because their implementation was obvious and it could lead to assume some extra services where
	provided which was not true
	* libgda/gda-client.[ch]: use explicit error codes
	* libgda/gda-connection.[ch]: removed gda_connection_new() because creating connection objects
	should only be done using gda_client_open_connection...()
	* doc/C: doc. improvements
	* libgda/gda-config.c:
	* libgda/gda-client.c: provider names are now case insensitive
	* providers/Makefile.am:
	* providers/postgres/: rewrote the PostgreSQL provider
	* providers/skel-implementation/capi/: improved the skeleton example
	* providers/prepare_provider_sources.sh: new script to change all files and objects names
	to reflect the real provider name when starting a provider by making a copy of a
	skeleton implementation
	* other files: compilation warnings removed


Added:
   branches/V4-branch/libgda/gda-client-private.h
   branches/V4-branch/providers/postgres/gda-postgres-meta.c
   branches/V4-branch/providers/postgres/gda-postgres-meta.h
   branches/V4-branch/providers/postgres/gda-postgres-pstmt.c
   branches/V4-branch/providers/postgres/gda-postgres-pstmt.h
   branches/V4-branch/providers/postgres/gda-postgres-util.c
   branches/V4-branch/providers/postgres/gda-postgres-util.h
   branches/V4-branch/providers/prepare_provider_sources.sh   (contents, props changed)
Removed:
   branches/V4-branch/providers/postgres/utils.c
Modified:
   branches/V4-branch/ChangeLog
   branches/V4-branch/doc/C/libgda-4.0-sections.txt
   branches/V4-branch/doc/C/prov-writing.xml
   branches/V4-branch/doc/C/tmpl/gda-client.sgml
   branches/V4-branch/doc/C/tmpl/gda-connection.sgml
   branches/V4-branch/doc/C/tmpl/gda-data-model.sgml
   branches/V4-branch/doc/C/tmpl/gda-pmodel.sgml
   branches/V4-branch/doc/C/tmpl/gda-pstmt.sgml
   branches/V4-branch/doc/C/tmpl/gda-server-provider.sgml
   branches/V4-branch/libgda-report/engine/gda-report-engine.c
   branches/V4-branch/libgda/gda-client.c
   branches/V4-branch/libgda/gda-client.h
   branches/V4-branch/libgda/gda-config.c
   branches/V4-branch/libgda/gda-connection.c
   branches/V4-branch/libgda/gda-connection.h
   branches/V4-branch/libgda/gda-data-proxy.c
   branches/V4-branch/libgda/gda-server-provider.c
   branches/V4-branch/libgda/gda-server-provider.h
   branches/V4-branch/libgda/providers-support/gda-pmodel.c
   branches/V4-branch/libgda/providers-support/gda-pmodel.h
   branches/V4-branch/libgda/providers-support/gda-pstmt.c
   branches/V4-branch/libgda/providers-support/gda-pstmt.h
   branches/V4-branch/libgda/sqlite/gda-sqlite-provider.c
   branches/V4-branch/libgda/sqlite/gda-sqlite-recordset.c
   branches/V4-branch/providers/Makefile.am
   branches/V4-branch/providers/mdb/gda-mdb-provider.c
   branches/V4-branch/providers/postgres/Makefile.am
   branches/V4-branch/providers/postgres/gda-postgres-blob-op.c
   branches/V4-branch/providers/postgres/gda-postgres-ddl.c
   branches/V4-branch/providers/postgres/gda-postgres-ddl.h
   branches/V4-branch/providers/postgres/gda-postgres-handler-bin.c
   branches/V4-branch/providers/postgres/gda-postgres-handler-bin.h
   branches/V4-branch/providers/postgres/gda-postgres-parser.c
   branches/V4-branch/providers/postgres/gda-postgres-parser.h
   branches/V4-branch/providers/postgres/gda-postgres-provider.c
   branches/V4-branch/providers/postgres/gda-postgres-provider.h
   branches/V4-branch/providers/postgres/gda-postgres-recordset.c
   branches/V4-branch/providers/postgres/gda-postgres-recordset.h
   branches/V4-branch/providers/postgres/gda-postgres.h
   branches/V4-branch/providers/postgres/gen_def.c
   branches/V4-branch/providers/postgres/libmain.c
   branches/V4-branch/providers/skel-implementation/capi/gda-capi-ddl.h
   branches/V4-branch/providers/skel-implementation/capi/gda-capi-parser.h
   branches/V4-branch/providers/skel-implementation/capi/gda-capi-provider.c
   branches/V4-branch/providers/skel-implementation/capi/gda-capi-pstmt.h
   branches/V4-branch/providers/skel-implementation/capi/gda-capi-recordset.c
   branches/V4-branch/providers/skel-implementation/capi/gda-capi-recordset.h
   branches/V4-branch/providers/skel-implementation/capi/libgda-capi-4.0.pc.in
   branches/V4-branch/tools/gda-sql.c

Modified: branches/V4-branch/doc/C/libgda-4.0-sections.txt
==============================================================================
--- branches/V4-branch/doc/C/libgda-4.0-sections.txt	(original)
+++ branches/V4-branch/doc/C/libgda-4.0-sections.txt	Wed Feb 20 20:36:04 2008
@@ -2,21 +2,13 @@
 <FILE>gda-client</FILE>
 <TITLE>GdaClient</TITLE>
 GdaClient
+GdaClientError
 GdaClientEvent
-GdaClientSpecsType
 gda_client_new
 gda_client_open_connection
 gda_client_open_connection_from_string
 gda_client_get_connections
-gda_client_find_connection
-gda_client_close_all_connections
-gda_client_notify_event
-gda_client_notify_error_event
-gda_client_notify_connection_opened_event
-gda_client_notify_connection_closed_event
-gda_client_begin_transaction
-gda_client_commit_transaction
-gda_client_rollback_transaction
+<SUBSECTION>
 gda_client_prepare_create_database
 gda_client_perform_create_database
 gda_client_prepare_drop_database
@@ -170,7 +162,6 @@
 <TITLE>GdaConnection</TITLE>
 GdaConnection
 GdaConnectionOptions
-gda_connection_new
 gda_connection_open
 gda_connection_close
 gda_connection_close_no_warning
@@ -1432,6 +1423,8 @@
 GdaPModelClass
 gda_pmodel_take_row
 gda_pmodel_get_stored_row
+gda_pmodel_set_modification_query
+gda_pmodel_compute_modification_queries
 <SUBSECTION Standard>
 GDA_IS_PMODEL
 GDA_PMODEL
@@ -1445,6 +1438,7 @@
 <TITLE>GdaPStmt</TITLE>
 <INCLUDE>providers-support/gda-pstmt.h</INCLUDE>
 GdaPStmt
+gda_pstmt_set_gda_statement
 gda_pstmt_copy_contents
 <SUBSECTION Standard>
 GDA_IS_PSTMT

Modified: branches/V4-branch/doc/C/prov-writing.xml
==============================================================================
--- branches/V4-branch/doc/C/prov-writing.xml	(original)
+++ branches/V4-branch/doc/C/prov-writing.xml	Wed Feb 20 20:36:04 2008
@@ -313,6 +313,33 @@
     This section explains how to write virtual methods for the <link linkend="GdaPModel">GdaPModel</link> subclasses
     implementations, which should be done when implementing a database provider.
   </para>
+  <para>
+    That data model implementation simplifies the implementation of provider's recordsets by having them implement only a
+    few virtual methods, and offering some services.
+  </para>
+  <para>
+    The data model represents each row in a separate <link linkend="GdaPRow">GdaPRow</link> object, and virtual
+    methods to retreive rows have to return new (and correctly initialized) objects of that class. The referencing
+    of these new objects is left up to the implementation which:
+    <itemizedlist>
+      <listitem>
+	<para>can rely on the <link linkend="GdaPRow">GdaPRow</link> implementation to keep them, using
+	  the <link linkend="gda-pmodel-take-row">gda_pmodel_take_row ()</link> method for each row object created which
+	  is the easiest, the fastest as once created, the rows are available for further usage, 
+	  but will consume more memory with each row read from the model.</para>
+      </listitem>
+      <listitem>
+	<para>can keep the references to these objects to the subclass implementation which will consume less memory but
+	  will make it necessary to create a new row object each time a row is read which is slower</para>
+      </listitem>
+      <listitem>
+	<para>can do a mix of the two solutions above: monitor the memory usage for the data model to 
+	  enable to "cache" some rows and discard some when memory is needed</para>
+      </listitem>
+    </itemizedlist>
+    Note that the methods mentionned in the 1st and 3rd items should be reserved for random data access mode, 
+    and that cursor based access mode should implement the method mentionned in th 2nd item.
+  </para>
   <sect2>
     <title>fetch_nb_rows()</title>
     <para>
@@ -328,28 +355,45 @@
   <sect2>
     <title>fetch_random()</title>
     <para>
-      To write.
+      This method is called when the user calls <link linkend="gda-data-model-get-value-at">gda_data_model_get_value_at ()</link>,
+      and in available only when the data access mode for the data model is random (that is not cursor based). When data
+      access is cursor based, this method will not be called.
+    </para>
+  </sect2>
+
+  <sect2>
+    <title>store_all()</title>
+    <para>
+      This method is called when the user sets the "store-all-rows" to TRUE. It has the effect of forcing the creation
+      of a <link linkend="GdaPRow">GdaPRow</link> object for each row of the data model (thus increasing the memory consumption
+      but reducing further access times). It is available only when the data access mode for the data model is random 
+      (that is not cursor based). When data access is cursor based, this method will not be called.
     </para>
   </sect2>
 
   <sect2>
     <title>fetch_next()</title>
     <para>
-      To write.
+      This method is called when data access is cursor based and a data model iterator is moved one position forward. The
+      <parameter>rownum</parameter> is an indication of what the row number will be once the next row has been fetched (it can 
+      safely be discarded if that information is not necessary).
     </para>
   </sect2>
 
   <sect2>
     <title>fetch_prev()</title>
     <para>
-      To write.
+      This method is called when data access is cursor based and a data model iterator is moved one position backward. The
+      <parameter>rownum</parameter> is an indication of what the row number will be once the previous row has been fetched (it can 
+      safely be discarded if that information is not necessary).
     </para>
   </sect2>
 
   <sect2>
     <title>fetch_at()</title>
     <para>
-      To write.
+      This method can be implemented when data access is cursor based and there is a shorter way of getting to a
+      specific row than having to call the fetch_next() or fetch_prev() methods several times.
     </para>
   </sect2>
 </chapter>

Modified: branches/V4-branch/doc/C/tmpl/gda-client.sgml
==============================================================================
--- branches/V4-branch/doc/C/tmpl/gda-client.sgml	(original)
+++ branches/V4-branch/doc/C/tmpl/gda-client.sgml	Wed Feb 20 20:36:04 2008
@@ -9,7 +9,7 @@
   This class is the main entry point for libgda client applications. It provides
   the way by which client applications open connections. Thus, before using any other
   database-oriented function in libgda, applications must create a #GdaClient object
-  (via #gda_client_new), and, once created, open the connections from it.
+  (via gda_client_new()), and, once created, open the connections from it.
 </para>
 <para>
   #GdaClient also provides a way to treat several connections as if they were only
@@ -18,10 +18,11 @@
   obtain the list of all tables in all opened connections.
 </para>
 <para>
-Database creation and destruction is done through a #GdaClient object uding the
-gda_client_create_database() and gda_client_drop_database() methods. Note however that 
-depending on the provider, an opened connection may be required in order to create
-or destroy a database.
+  Database creation and destruction is done through a #GdaClient object uding the
+  gda_client_prepare_create_database(), gda_client_perform_create_database(), 
+  gda_client_prepare_drop_database() and gda_client_perform_drop_database() methods. Note however that 
+  depending on the provider, an opened connection may be required in order to create
+  or destroy a database.
 </para>
 
 <!-- ##### SECTION See_Also ##### -->
@@ -48,6 +49,14 @@
 @arg2: 
 @arg3: 
 
+<!-- ##### ENUM GdaClientError ##### -->
+<para>
+
+</para>
+
+ GDA_CLIENT_DSN_NOT_FOUND_ERROR: 
+ GDA_CLIENT_PROVIDER_NOT_FOUND_ERROR: 
+
 <!-- ##### ENUM GdaClientEvent ##### -->
 <para>
 
@@ -105,98 +114,6 @@
 @Returns: 
 
 
-<!-- ##### FUNCTION gda_client_find_connection ##### -->
-<para>
-
-</para>
-
- client: 
- dsn: 
- auth_string: 
- Returns: 
-
-
-<!-- ##### FUNCTION gda_client_close_all_connections ##### -->
-<para>
-
-</para>
-
- client: 
-
-
-<!-- ##### FUNCTION gda_client_notify_event ##### -->
-<para>
-
-</para>
-
- client: 
- cnc: 
- event: 
- params: 
-
-
-<!-- ##### FUNCTION gda_client_notify_error_event ##### -->
-<para>
-
-</para>
-
- client: 
- cnc: 
- error: 
-
-
-<!-- ##### FUNCTION gda_client_notify_connection_opened_event ##### -->
-<para>
-
-</para>
-
- client: 
- cnc: 
-
-
-<!-- ##### FUNCTION gda_client_notify_connection_closed_event ##### -->
-<para>
-
-</para>
-
- client: 
- cnc: 
-
-
-<!-- ##### FUNCTION gda_client_begin_transaction ##### -->
-<para>
-
-</para>
-
- client: 
- name: 
- level: 
- error: 
- Returns: 
-
-
-<!-- ##### FUNCTION gda_client_commit_transaction ##### -->
-<para>
-
-</para>
-
- client: 
- name: 
- error: 
- Returns: 
-
-
-<!-- ##### FUNCTION gda_client_rollback_transaction ##### -->
-<para>
-
-</para>
-
- client: 
- name: 
- error: 
- Returns: 
-
-
 <!-- ##### FUNCTION gda_client_prepare_create_database ##### -->
 <para>
 

Modified: branches/V4-branch/doc/C/tmpl/gda-connection.sgml
==============================================================================
--- branches/V4-branch/doc/C/tmpl/gda-connection.sgml	(original)
+++ branches/V4-branch/doc/C/tmpl/gda-connection.sgml	Wed Feb 20 20:36:04 2008
@@ -7,11 +7,11 @@
 <!-- ##### SECTION Long_Description ##### -->
 <para>
   The #GdaConnection class offers access to all operations involving an
-  opened connection to a database. #GdaConnection objects are obtained
-  via the #GdaClient class.
+  opened connection to a database. #GdaConnection objects are not instiated directly
+  but by #GdaClient objects using gda_client_open_connection() and gda_client_open_connection_from_string()
 </para>
 <para>
-  Once obtained, applications can use #GdaConnection to execute commands,
+  Applications can then use #GdaConnection objects to execute commands,
   run transactions, and get information about all objects stored in the
   underlying database.
 </para>
@@ -117,19 +117,6 @@
 @GDA_CONNECTION_OPTIONS_READ_ONLY: 
 @GDA_CONNECTION_OPTIONS_DONT_SHARE: 
 
-<!-- ##### FUNCTION gda_connection_new ##### -->
-<para>
-
-</para>
-
- client: 
- provider: 
- dsn: 
- auth_string: 
- options: 
- Returns: 
-
-
 <!-- ##### FUNCTION gda_connection_open ##### -->
 <para>
 

Modified: branches/V4-branch/doc/C/tmpl/gda-data-model.sgml
==============================================================================
--- branches/V4-branch/doc/C/tmpl/gda-data-model.sgml	(original)
+++ branches/V4-branch/doc/C/tmpl/gda-data-model.sgml	Wed Feb 20 20:36:04 2008
@@ -17,10 +17,14 @@
 </para>
 <para>
 Again, depending on the real implementation, data retreiving can be done either accessing direct random
-values located by their row and column, or using a #GdaDataModelIter cursor, or both. Use the 
-gda_data_model_get_access_flags() method to know how the data model can be accessed. Note that a #GdaDatamodel
-which can be accessed in a random way can also be accessed using cursors (and several cusrors may be used at the same
-time), whereas data model which can only be accessed using cursors can only have one cursor for iterating.
+values located by their row and column, or using a cursor, or both. Use the gda_data_model_get_access_flags() 
+method to know how the data model can be accessed. 
+<itemizedlist>
+  <listitem><para>Random access to a data model's contents is done using gda_data_model_get_value_at(), or using
+      one or more #GdaDataModelIter object(s);</para></listitem>
+  <listitem><para>Cursor access to a data model's contents is done using a #GdaDataModelIter object (only one can be created),
+      it is <emphasis>not possible</emphasis> to use gda_data_model_get_value_at() in this mode.</para></listitem>
+</itemizedlist>
 </para>
 <para>
 Random access data models are easier to use since picking a value is very simple using the gda_data_model_get_value_at(),

Modified: branches/V4-branch/doc/C/tmpl/gda-pmodel.sgml
==============================================================================
--- branches/V4-branch/doc/C/tmpl/gda-pmodel.sgml	(original)
+++ branches/V4-branch/doc/C/tmpl/gda-pmodel.sgml	Wed Feb 20 20:36:04 2008
@@ -39,6 +39,7 @@
 @object: base object
 @priv: private data
 @prep_stmt: SELECT prepared statement for which the execution gave this object
+ nb_stored_rows: 
 @advertized_nrows: initially set to -1, set to a value >= 0 when the number of rows in the data model is known
 
 <!-- ##### STRUCT GdaPModelClass ##### -->
@@ -49,6 +50,7 @@
 @parent_class: parent object class
 @fetch_nb_rows: virtual method which must be implemented when access method is GDA_DATA_MODEL_ACCESS_RANDOM
 @fetch_random: virtual method which must be implemented when access method is GDA_DATA_MODEL_ACCESS_RANDOM
+ store_all: 
 @fetch_next: virtual method which must be implemented when access method is GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD
 @fetch_prev: virtual method which must be implemented when access method is GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD
 @fetch_at: virtual method which can be implemented when access method is GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD or GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD
@@ -73,3 +75,26 @@
 @Returns: 
 
 
+<!-- ##### FUNCTION gda_pmodel_set_modification_query ##### -->
+<para>
+
+</para>
+
+ model: 
+ mod_stmt: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION gda_pmodel_compute_modification_queries ##### -->
+<para>
+
+</para>
+
+ model: 
+ target: 
+ use_all_fields_if_no_pk: 
+ error: 
+ Returns: 
+
+

Modified: branches/V4-branch/doc/C/tmpl/gda-pstmt.sgml
==============================================================================
--- branches/V4-branch/doc/C/tmpl/gda-pstmt.sgml	(original)
+++ branches/V4-branch/doc/C/tmpl/gda-pstmt.sgml	Wed Feb 20 20:36:04 2008
@@ -23,12 +23,22 @@
 </para>
 
 @object: base object
+ stmt: 
 @sql: actual SQL code used for this prepared statement, its memory is freed by the object itself
 @param_ids: list of parameters' IDs (as gchar *), the memory is freed by object itself
 @ncols: number of columns in the returned data model (if the prepared statement is a SELECT statement)
 @types: array of ncols types (if the prepared statement is a SELECT statement)
 @tmpl_columns: list of <link linkend="GdaColumn">GdaColumn</link> objects which data models created from this prepared statement can copy
 
+<!-- ##### FUNCTION gda_pstmt_set_gda_statement ##### -->
+<para>
+
+</para>
+
+ pstmt: 
+ stmt: 
+
+
 <!-- ##### FUNCTION gda_pstmt_copy_contents ##### -->
 <para>
 

Modified: branches/V4-branch/doc/C/tmpl/gda-server-provider.sgml
==============================================================================
--- branches/V4-branch/doc/C/tmpl/gda-server-provider.sgml	(original)
+++ branches/V4-branch/doc/C/tmpl/gda-server-provider.sgml	Wed Feb 20 20:36:04 2008
@@ -59,9 +59,16 @@
 @statement_to_sql: 
 @statement_prepare: 
 @statement_execute: 
+ is_busy: 
 @cancel: 
 @create_connection: 
 @meta_funcs: 
+ _gda_reserved1: 
+ _gda_reserved2: 
+ _gda_reserved3: 
+ _gda_reserved4: 
+ _gda_reserved5: 
+ _gda_reserved6: 
 
 <!-- ##### ENUM GdaServerProviderError ##### -->
 <para>
@@ -75,6 +82,7 @@
 @GDA_SERVER_PROVIDER_OPERATION_ERROR: 
 @GDA_SERVER_PROVIDER_INTERNAL_ERROR: 
 @GDA_SERVER_PROVIDER_BUSY_ERROR: 
+ GDA_SERVER_PROVIDER_NON_SUPPORTED_ERROR: 
 
 <!-- ##### STRUCT GdaServerProviderMeta ##### -->
 <para>

Modified: branches/V4-branch/libgda-report/engine/gda-report-engine.c
==============================================================================
--- branches/V4-branch/libgda-report/engine/gda-report-engine.c	(original)
+++ branches/V4-branch/libgda-report/engine/gda-report-engine.c	Wed Feb 20 20:36:04 2008
@@ -597,7 +597,7 @@
 
 				/* find which connection to use */
 				prop = xmlGetProp (child, BAD_CAST "cnc_name");
-				cnc = run_context_find_connection (engine, context, (gchar *) prop);
+				cnc = run_context_find_connection (engine, context, prop);
 				if (!cnc) {
 					if (prop) {
 						g_set_error (error, 0, 0,

Added: branches/V4-branch/libgda/gda-client-private.h
==============================================================================
--- (empty file)
+++ branches/V4-branch/libgda/gda-client-private.h	Wed Feb 20 20:36:04 2008
@@ -0,0 +1,37 @@
+/* GDA library
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GDA_CLIENT_PRIVATE_H__
+#define __GDA_CLIENT_PRIVATE_H__
+
+#include <libgda/gda-client.h>
+
+G_BEGIN_DECLS
+
+void _gda_client_notify_event (GdaClient *client, GdaConnection *cnc, GdaClientEvent event, GdaSet *params);
+void _gda_client_notify_error_event (GdaClient *client, GdaConnection *cnc, GdaConnectionEvent *error);
+void _gda_client_notify_connection_opened_event (GdaClient *client, GdaConnection *cnc);
+void _gda_client_notify_connection_closed_event (GdaClient *client, GdaConnection *cnc);
+
+G_END_DECLS
+
+#endif

Modified: branches/V4-branch/libgda/gda-client.c
==============================================================================
--- branches/V4-branch/libgda/gda-client.c	(original)
+++ branches/V4-branch/libgda/gda-client.c	Wed Feb 20 20:36:04 2008
@@ -24,6 +24,7 @@
 
 #include <gmodule.h>
 #include <libgda/gda-client.h>
+#include <libgda/gda-client-private.h>
 #include <libgda/gda-config.h>
 #include <glib/gi18n-lib.h>
 #include <libgda/gda-log.h>
@@ -44,6 +45,7 @@
 static void gda_client_finalize   (GObject *object);
 
 static void cnc_error_cb (GdaConnection *cnc, GdaConnectionEvent *error, GdaClient *client);
+static GdaConnection *gda_client_find_connection (GdaClient *client, const gchar *dsn, const gchar *auth_string);
 
 enum {
 	EVENT_NOTIFICATION,
@@ -63,7 +65,7 @@
 	g_return_if_fail (GDA_IS_CLIENT (client));
 
 	/* notify error */
-	gda_client_notify_error_event (client, cnc, error);
+	_gda_client_notify_error_event (client, cnc, error);
 }
 
 /*
@@ -186,8 +188,10 @@
  *
  * The @auth_string must contain the authentification information for the server
  * to accept the connection. It is a string containing semi-colon seperated named value, usually 
- * like "USERNAME=...;PASSWORD=..." where the ... are replaced by actual values. However some database
- * providers may require different information.
+ * like "USERNAME=...;PASSWORD=..." where the ... are replaced by actual values. 
+ * The actual named parameters required depend on the provider being used, and that list is available
+ * as the <parameter>auth_params</parameter> member of the #GdaProviderInfo struncture for each installed
+ * provider (use gda_config_get_provider_info() to get it).
  *
  * If a new #GdaConnection is created, then the caller will hold a reference on it, and if a #GdaConnection
  * already existing is used, then the reference count of that object will be increased by one.
@@ -195,11 +199,8 @@
  * Returns: the opened connection if successful, %NULL if there was an error.
  */
 GdaConnection *
-gda_client_open_connection (GdaClient *client,
-			    const gchar *dsn,
-			    const gchar *auth_string,
-			    GdaConnectionOptions options,
-			    GError **error)
+gda_client_open_connection (GdaClient *client, const gchar *dsn, const gchar *auth_string,
+			    GdaConnectionOptions options, GError **error)
 {
 	GdaConnection *cnc = NULL;
 	GdaDataSourceInfo *dsn_info;
@@ -210,7 +211,7 @@
 	dsn_info = gda_config_get_dsn (dsn);
 	if (!dsn_info) {
 		gda_log_error (_("Data source %s not found in configuration"), dsn);
-		g_set_error (error, GDA_CLIENT_ERROR, 0, 
+		g_set_error (error, GDA_CLIENT_ERROR, GDA_CLIENT_DSN_NOT_FOUND_ERROR, 
 			     _("Data source %s not found in configuration"), dsn);
 		return NULL;
 	}
@@ -244,7 +245,7 @@
 	}
 	else {
 		g_warning (_("Datasource configuration error: no provider specified"));
-		g_set_error (error, GDA_CLIENT_ERROR, 0, 
+		g_set_error (error, GDA_CLIENT_ERROR, GDA_CLIENT_PROVIDER_NOT_FOUND_ERROR, 
 			     _("Datasource configuration error: no provider specified"));
 	}
 
@@ -284,8 +285,10 @@
  *
  * The @auth_string must contain the authentification information for the server
  * to accept the connection. It is a string containing semi-colon seperated named value, usually 
- * like "USERNAME=...;PASSWORD=..." where the ... are replaced by actual values. However some database
- * providers may require different information.
+ * like "USERNAME=...;PASSWORD=..." where the ... are replaced by actual values. 
+ * The actual named parameters required depend on the provider being used, and that list is available
+ * as the <parameter>auth_params</parameter> member of the #GdaProviderInfo struncture for each installed
+ * provider (use gda_config_get_provider_info() to get it).
  *
  * Additionnally, it is possible to have the connection string
  * respect the "&lt;provider_name&gt;://&lt;real cnc string&gt;" format, in which case the provider name
@@ -296,11 +299,8 @@
  * an error.
  */
 GdaConnection *
-gda_client_open_connection_from_string (GdaClient *client,
-					const gchar *provider_id,
-					const gchar *cnc_string,
-					const gchar *auth_string,
-					GdaConnectionOptions options,
+gda_client_open_connection_from_string (GdaClient *client, const gchar *provider_id, const gchar *cnc_string,
+					const gchar *auth_string, GdaConnectionOptions options,
 					GError **error)
 {
 	GdaConnection *cnc = NULL;
@@ -322,7 +322,8 @@
 	}
 	
 	if (!provider_id) {
-		g_set_error (error, GDA_CLIENT_ERROR, 0, _("No provider specified"));
+		g_set_error (error, GDA_CLIENT_ERROR, GDA_CLIENT_PROVIDER_NOT_FOUND_ERROR, 
+			     _("No provider specified"));
 		g_free (dup);
 		return NULL;
 	}
@@ -335,7 +336,7 @@
 			tmp_prov = gda_connection_get_provider_name (cnc);
 			tmp_cnc_string = gda_connection_get_cnc_string (cnc);
 	
-			if (strcmp (provider_id, tmp_prov) == 0
+			if (g_ascii_strcasecmp (provider_id, tmp_prov) == 0
 			    && (! strcmp (cnc_string, tmp_cnc_string))) {
 				g_free (dup);
 				return cnc;
@@ -359,7 +360,7 @@
 	}
 	else {
 		g_warning (_("Datasource configuration error: no provider specified"));
-		g_set_error (error, GDA_CLIENT_ERROR, 0, 
+		g_set_error (error, GDA_CLIENT_ERROR, GDA_CLIENT_PROVIDER_NOT_FOUND_ERROR, 
 			     _("Datasource configuration error: no provider specified"));
 	}
 
@@ -385,7 +386,7 @@
 	return (const GList *) client->priv->connections;
 }
 
-/**
+/*
  * gda_client_find_connection
  * @client: a #GdaClient object.
  * @dsn: data source name.
@@ -402,7 +403,7 @@
  * Returns: a pointer to the found connection, or %NULL if it could not
  * be found.
  */
-GdaConnection *
+static GdaConnection *
 gda_client_find_connection (GdaClient *client, const gchar *dsn, const gchar *auth_string)
 {
 	GList *l;
@@ -434,23 +435,7 @@
 }
 
 /**
- * gda_client_close_all_connections
- * @client: a #GdaClient object.
- *
- * Closes all connections opened by the given #GdaClient object.
- */
-void
-gda_client_close_all_connections (GdaClient *client)
-{
-	g_return_if_fail (GDA_IS_CLIENT (client));
-	g_return_if_fail (client->priv);
-
-	if (client->priv->connections) 
-		g_list_foreach (client->priv->connections, (GFunc) gda_connection_close, NULL);
-}
-
-/**
- * gda_client_notify_event
+ * _gda_client_notify_event
  * @client: a #GdaClient object.
  * @cnc: a #GdaConnection object where the event has occurred.
  * @event: event ID.
@@ -461,10 +446,7 @@
  * operation, to changes made to a table in an underlying database.
  */
 void
-gda_client_notify_event (GdaClient *client,
-			 GdaConnection *cnc,
-			 GdaClientEvent event,
-			 GdaSet *params)
+_gda_client_notify_event (GdaClient *client, GdaConnection *cnc, GdaClientEvent event, GdaSet *params)
 {
 	if (!client)
 		return;
@@ -475,7 +457,7 @@
 }
 
 /**
- * gda_client_notify_error_event
+ * _gda_client_notify_error_event
  * @client: a #GdaClient object.
  * @cnc: a #GdaConnection object.
  * @error: the error to be notified.
@@ -483,7 +465,7 @@
  * Notifies the given #GdaClient of the #GDA_CLIENT_EVENT_ERROR event.
  */
 void
-gda_client_notify_error_event (GdaClient *client, GdaConnection *cnc, GdaConnectionEvent *error)
+_gda_client_notify_error_event (GdaClient *client, GdaConnection *cnc, GdaConnectionEvent *error)
 {
 	GdaSet *params;
 	GdaHolder *param;
@@ -504,12 +486,12 @@
 	params = gda_set_new (NULL);
 	gda_set_add_holder (params, param);
 	g_object_unref (param);
-	gda_client_notify_event (client, cnc, GDA_CLIENT_EVENT_ERROR, params);
+	_gda_client_notify_event (client, cnc, GDA_CLIENT_EVENT_ERROR, params);
 	g_object_unref (params);
 }
 
 /**
- * gda_client_notify_connection_opened_event
+ * _gda_client_notify_connection_opened_event
  * @client: a #GdaClient object.
  * @cnc: a #GdaConnection object.
  *
@@ -517,7 +499,7 @@
  * event.
  */
 void
-gda_client_notify_connection_opened_event (GdaClient *client, GdaConnection *cnc)
+_gda_client_notify_connection_opened_event (GdaClient *client, GdaConnection *cnc)
 {
 	if (!client)
 		return;
@@ -525,11 +507,11 @@
 	g_return_if_fail (GDA_IS_CLIENT (client));
 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
 
-	gda_client_notify_event (client, cnc, GDA_CLIENT_EVENT_CONNECTION_OPENED, NULL);
+	_gda_client_notify_event (client, cnc, GDA_CLIENT_EVENT_CONNECTION_OPENED, NULL);
 }
 
 /**
- * gda_client_notify_connection_closed_event
+ * _gda_client_notify_connection_closed_event
  * @client: a #GdaClient object.
  * @cnc: a #GdaConnection object.
  *
@@ -537,7 +519,7 @@
  * event.
  */
 void
-gda_client_notify_connection_closed_event (GdaClient *client, GdaConnection *cnc)
+_gda_client_notify_connection_closed_event (GdaClient *client, GdaConnection *cnc)
 {
 	if (!client)
 		return;
@@ -545,113 +527,7 @@
 	g_return_if_fail (GDA_IS_CLIENT (client));
 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
 
-	gda_client_notify_event (client, cnc, GDA_CLIENT_EVENT_CONNECTION_CLOSED, NULL);
-}
-
-/**
- * gda_client_begin_transaction
- * @client: a #GdaClient object.
- * @name: the name of the transation to start
- * @level:
- * @error: a place to store errors, or %NULL
- *
- * Starts a transaction on all connections being managed by the given
- * #GdaClient. It is important to note that this operates on all
- * connections opened within a #GdaClient, which could not be what
- * you're looking for.
- *
- * To execute a transaction on a unique connection, use
- * #gda_connection_begin_transaction, #gda_connection_commit_transaction
- * and #gda_connection_rollback_transaction.
- *
- * Returns: %TRUE if all transactions could be started successfully,
- * or %FALSE if one of them fails.
- */
-gboolean
-gda_client_begin_transaction (GdaClient *client, const gchar *name, GdaTransactionIsolation level,
-			      GError **error)
-{
-	GList *l;
-
-	g_return_val_if_fail (GDA_IS_CLIENT (client), FALSE);
-
-	for (l = client->priv->connections; l != NULL; l = l->next) {
-		if (!gda_connection_begin_transaction (GDA_CONNECTION (l->data), name, level, error)) {
-			gda_client_rollback_transaction (client, name, NULL);
-			return FALSE;
-		}
-	}
-
-	return TRUE;
-}
-
-/**
- * gda_client_commit_transaction
- * @client: a #GdaClient object.
- * @name: the name of the transation to commit
- * @error: a place to store errors, or %NULL
- *
- * Commits a running transaction on all connections being managed by the given
- * #GdaClient. It is important to note that this operates on all
- * connections opened within a #GdaClient, which could not be what
- * you're looking for.
- *
- * To execute a transaction on a unique connection, use
- * #gda_connection_begin_transaction, #gda_connection_commit_transaction
- * and #gda_connection_rollback_transaction.
- *
- * Returns: %TRUE if all transactions could be committed successfully,
- * or %FALSE if one of them fails.
- */
-gboolean
-gda_client_commit_transaction (GdaClient *client, const gchar *name, GError **error)
-{
-	GList *l;
-
-	g_return_val_if_fail (GDA_IS_CLIENT (client), FALSE);
-
-	for (l = client->priv->connections; l != NULL; l = l->next) {
-		if (!gda_connection_commit_transaction (GDA_CONNECTION (l->data), name, error)) {
-			gda_client_rollback_transaction (client, name, NULL);
-			return FALSE;
-		}
-	}
-
-	return TRUE;
-}
-
-/**
- * gda_client_rollback_transaction
- * @client: a #GdaClient object.
- * @name: the name of the transation to rollback
- * @error: a place to store errors, or %NULL
- *
- * Cancels a running transaction on all connections being managed by the given
- * #GdaClient. It is important to note that this operates on all
- * connections opened within a #GdaClient, which could not be what
- * you're looking for.
- *
- * To execute a transaction on a unique connection, use
- * #gda_connection_begin_transaction, #gda_connection_commit_transaction
- * and #gda_connection_rollback_transaction.
- *
- * Returns: %TRUE if all transactions could be cancelled successfully,
- * or %FALSE if one of them fails.
- */
-gboolean
-gda_client_rollback_transaction (GdaClient *client, const gchar *name, GError **error)
-{
-	GList *l;
-	gint failures = 0;
-
-	g_return_val_if_fail (GDA_IS_CLIENT (client), FALSE);
-
-	for (l = client->priv->connections; l != NULL; l = l->next) {
-		if (!gda_connection_rollback_transaction (GDA_CONNECTION (l->data), name, error))
-			failures++;
-	}
-
-	return failures == 0 ? TRUE : FALSE;
+	_gda_client_notify_event (client, cnc, GDA_CLIENT_EVENT_CONNECTION_CLOSED, NULL);
 }
 
 /**
@@ -765,7 +641,7 @@
 	if (provider) 
 		return gda_server_provider_perform_operation (provider, NULL, op, error);
 	else {
-		g_set_error (error, GDA_CLIENT_ERROR, 0, 
+		g_set_error (error, GDA_CLIENT_ERROR, GDA_CLIENT_PROVIDER_NOT_FOUND_ERROR, 
 			     _("Could not find operation's associated provider, "
 			       "did you use gda_client_prepare_create_database() ?")); 
 		return FALSE;
@@ -795,7 +671,7 @@
 	if (provider) 
 		return gda_server_provider_perform_operation (provider, NULL, op, error);
 	else {
-		g_set_error (error, GDA_CLIENT_ERROR, GDA_CLIENT_GENERAL_ERROR, 
+		g_set_error (error, GDA_CLIENT_ERROR, GDA_CLIENT_PROVIDER_NOT_FOUND_ERROR, 
 			     _("Could not find operation's associated provider, "
 			       "did you use gda_client_prepare_drop_database() ?")); 
 		return FALSE;

Modified: branches/V4-branch/libgda/gda-client.h
==============================================================================
--- branches/V4-branch/libgda/gda-client.h	(original)
+++ branches/V4-branch/libgda/gda-client.h	Wed Feb 20 20:36:04 2008
@@ -60,10 +60,7 @@
 	GObjectClass      parent_class;
 
 	/* signals */
-	void (* event_notification) (GdaClient *client,
-				     GdaConnection *cnc,
-				     GdaClientEvent event,
-				     GdaSet *params);
+	void (* event_notification) (GdaClient *client, GdaConnection *cnc, GdaClientEvent event, GdaSet *params);
 };
 
 /* error reporting */
@@ -72,53 +69,29 @@
 
 typedef enum
 {
-  GDA_CLIENT_GENERAL_ERROR
+	GDA_CLIENT_DSN_NOT_FOUND_ERROR,
+	GDA_CLIENT_PROVIDER_NOT_FOUND_ERROR
 } GdaClientError;
 
-GType          gda_client_get_type                           (void) G_GNUC_CONST;
-GdaClient     *gda_client_new                                (void);
+GType               gda_client_get_type                      (void) G_GNUC_CONST;
+GdaClient          *gda_client_new                           (void);
 
-GdaConnection *gda_client_open_connection                    (GdaClient *client,
-							      const gchar *dsn,
-							      const gchar *auth_string,
-							      GdaConnectionOptions options,
-							      GError **error);
-GdaConnection *gda_client_open_connection_from_string        (GdaClient *client,
-							      const gchar *provider_id,
-							      const gchar *cnc_string,
-							      const gchar *auth_string,
-							      GdaConnectionOptions options,
-							      GError **error);
-const GList   *gda_client_get_connections                    (GdaClient *client);
-GdaConnection *gda_client_find_connection                    (GdaClient *client,
-							      const gchar *dsn,
-							      const gchar *auth_string);
-void           gda_client_close_all_connections              (GdaClient *client);
-
-void           gda_client_notify_event                       (GdaClient *client, GdaConnection *cnc,
-							      GdaClientEvent event, GdaSet *params);
-void           gda_client_notify_error_event                 (GdaClient *client, GdaConnection *cnc, GdaConnectionEvent *error);
-void           gda_client_notify_connection_opened_event     (GdaClient *client, GdaConnection *cnc);
-void           gda_client_notify_connection_closed_event     (GdaClient *client, GdaConnection *cnc);
+GdaConnection      *gda_client_open_connection               (GdaClient *client, const gchar *dsn, const gchar *auth_string,
+							      GdaConnectionOptions options, GError **error);
+GdaConnection      *gda_client_open_connection_from_string   (GdaClient *client, const gchar *provider_id,
+							      const gchar *cnc_string, const gchar *auth_string,
+							      GdaConnectionOptions options, GError **error);
+const GList        *gda_client_get_connections               (GdaClient *client);
 
 /*
  * Database creation and destruction functions
  */
-GdaServerOperation *gda_client_prepare_create_database       (GdaClient *client, const gchar *db_name, 
-							      const gchar *provider);
-gboolean       gda_client_perform_create_database            (GdaClient *client, GdaServerOperation *op, GError **error);
-GdaServerOperation *gda_client_prepare_drop_database         (GdaClient *client, const gchar *db_name, 
-							      const gchar *provider);
-gboolean       gda_client_perform_drop_database              (GdaClient *client, GdaServerOperation *op, GError **error);
+GdaServerOperation *gda_client_prepare_create_database       (GdaClient *client, const gchar *db_name, const gchar *provider);
+gboolean            gda_client_perform_create_database       (GdaClient *client, GdaServerOperation *op, GError **error);
+GdaServerOperation *gda_client_prepare_drop_database         (GdaClient *client, const gchar *db_name, const gchar *provider);
+gboolean            gda_client_perform_drop_database         (GdaClient *client, GdaServerOperation *op, GError **error);
 
-/*
- * Connection stack functions
- */
 
-gboolean       gda_client_begin_transaction                  (GdaClient *client, const gchar *name, GdaTransactionIsolation level,
-							      GError **error);
-gboolean       gda_client_commit_transaction                 (GdaClient *client, const gchar *name, GError **error);
-gboolean       gda_client_rollback_transaction               (GdaClient *client, const gchar *name, GError **error);
 
 
 

Modified: branches/V4-branch/libgda/gda-config.c
==============================================================================
--- branches/V4-branch/libgda/gda-config.c	(original)
+++ branches/V4-branch/libgda/gda-config.c	Wed Feb 20 20:36:04 2008
@@ -916,7 +916,7 @@
 		load_all_providers ();
 
 	for (list = unique_instance->priv->prov_list; list; list = list->next)
-		if (!strcmp (((GdaProviderInfo*) list->data)->id, provider_name)) {
+		if (!g_ascii_strcasecmp (((GdaProviderInfo*) list->data)->id, provider_name)) {
 			GDA_CONFIG_UNLOCK ();
 			return (GdaProviderInfo*) list->data;
 		}

Modified: branches/V4-branch/libgda/gda-connection.c
==============================================================================
--- branches/V4-branch/libgda/gda-connection.c	(original)
+++ branches/V4-branch/libgda/gda-connection.c	Wed Feb 20 20:36:04 2008
@@ -26,6 +26,7 @@
 #undef GDA_DISABLE_DEPRECATED
 #include <stdio.h>
 #include <libgda/gda-client.h>
+#include <libgda/gda-client-private.h>
 #include <libgda/gda-config.h>
 #include <libgda/gda-connection.h>
 #include <libgda/gda-connection-private.h>
@@ -408,40 +409,6 @@
         }	
 }
 
-
-/**
- * gda_connection_new
- * @client: a #GdaClient object, or %NULL
- * @provider: a #GdaServerProvider object.
- * @dsn: GDA data source to connect to.
- * @auth_string: authentification string.
- * @options: options for the connection.
- *
- * This function creates a new #GdaConnection object. It is not
- * intended to be used directly by applications (use
- * #gda_client_open_connection instead).
- *
- * The connection is not opened at this stage; use 
- * gda_connection_open() to open the connection.
- *
- * Returns: a newly allocated #GdaConnection object.
- */
-GdaConnection *
-gda_connection_new (GdaClient *client, GdaServerProvider *provider,
-		    const gchar *dsn, const gchar *auth_string,
-		    GdaConnectionOptions options)
-{
-	GdaConnection *cnc;
-
-	g_return_val_if_fail (!client || GDA_IS_CLIENT (client), NULL);
-	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
-
-	cnc = g_object_new (GDA_TYPE_CONNECTION, "client", client, "provider_obj", provider, 
-			    "dsn", dsn, "auth_string", auth_string, 
-			    "options", options, NULL);
-	return cnc;
-}
-
 /**
  * gda_connection_open
  * @cnc: a #GdaConnection object
@@ -505,24 +472,16 @@
 	else {
 		if (dsn_info && dsn_info->auth_string)
 			real_auth_string = g_strdup (dsn_info->auth_string);
-		else {
-			TO_IMPLEMENT; /* look into @params */
-			/*
-			const gchar *s;
-			s = gda_quark_list_find (params, "USER");
-			if (s) {
-				real_username = g_strdup (s);
-				gda_quark_list_remove (params, "USER");
-			}
-			*/
-		}
+		else 
+			/* look for authentification parameters in cnc string */
+			real_auth_string = g_strdup (cnc->priv->cnc_string);
 	}
 
 	/* try to open the connection */
-	auth = gda_quark_list_new_from_string (cnc->priv->cnc_string);
+	auth = gda_quark_list_new_from_string (real_auth_string);
 	if (gda_server_provider_open_connection (cnc->priv->provider_obj, cnc, params, auth)) {
 		cnc->priv->is_open = TRUE;
-		gda_client_notify_connection_opened_event (cnc->priv->client, cnc);
+		_gda_client_notify_connection_opened_event (cnc->priv->client, cnc);
 	}
 	else {
 		const GList *events;
@@ -539,8 +498,8 @@
 					if (error && !(*error))
 						g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_OPEN_ERROR,
 							     gda_connection_event_get_description (event));
-					gda_client_notify_error_event (cnc->priv->client, cnc, 
-								       GDA_CONNECTION_EVENT (l->data));
+					_gda_client_notify_error_event (cnc->priv->client, cnc, 
+									GDA_CONNECTION_EVENT (l->data));
 				}
 			}
 		}
@@ -610,7 +569,7 @@
 		return;
 
 	gda_server_provider_close_connection (cnc->priv->provider_obj, cnc);
-	gda_client_notify_connection_closed_event (cnc->priv->client, cnc);
+	_gda_client_notify_connection_closed_event (cnc->priv->client, cnc);
 	cnc->priv->is_open = FALSE;
 
 	if (cnc->priv->provider_data) {
@@ -1135,7 +1094,9 @@
  * return object will either be:
  * <itemizedlist>
  *   <listitem><para>a #GdaDataModel if @stmt is a SELECT statement (a GDA_SQL_STATEMENT_SELECT, see #GdaSqlStatementType)
- *             containing the results of the SELECT</para></listitem>
+ *             containing the results of the SELECT. The resulting data model is by default read only, but
+ *             modifications can be made possible using gda_pmodel_set_modification_query() and/or
+ *             gda_pmodel_compute_modification_queries().</para></listitem>
  *   <listitem><para>a #GdaSet for any other SQL statement which correctly executed. In this case
  *        (if the provider supports it), then the #GdaSet may contain value holders named:
  *        <itemizedlist>
@@ -1180,9 +1141,9 @@
  * This function returns the number of rows affected by the execution of @stmt, or -1
  * if an error occurred, or -2 if the connection's provider does not return the number of rows affected.
  *
- * This function is just a convenience function around the gda_connection_execute_statement()
+ * This function is just a convenience function around the gda_connection_statement_execute()
  * function. 
- * See the documentation of the gda_connection_execute_statement() for information
+ * See the documentation of the gda_connection_statement_execute() for information
  * about the @params list of parameters.
  *
  * If @last_insert_row is not %NULL and @stmt is an INSERT statement, then it will contain (if the
@@ -1252,10 +1213,10 @@
  * This function returns a #GdaDataModel resulting from the SELECT statement, or %NULL
  * if an error occurred.
  *
- * This function is just a convenience function around the gda_connection_execute_command()
+ * This function is just a convenience function around the gda_connection_statement_execute()
  * function.
  *
- * See the documentation of the gda_connection_execute_statement() for information
+ * See the documentation of the gda_connection_statement_execute() for information
  * about the @params list of parameters.
  *
  * Returns: a #GdaDataModel containing the data returned by the
@@ -1300,10 +1261,10 @@
  * This function returns a #GdaDataModel resulting from the SELECT statement, or %NULL
  * if an error occurred.
  *
- * This function is just a convenience function around the gda_connection_execute_command()
+ * This function is just a convenience function around the gda_connection_statement_execute()
  * function.
  *
- * See the documentation of the gda_connection_execute_statement() for information
+ * See the documentation of the gda_connection_statement_execute() for information
  * about the @params list of parameters.
  *
  * Returns: a #GdaDataModel containing the data returned by the
@@ -1357,10 +1318,10 @@
  * This function returns a #GdaDataModel resulting from the SELECT statement, or %NULL
  * if an error occurred.
  *
- * This function is just a convenience function around the gda_connection_execute_command()
+ * This function is just a convenience function around the gda_connection_statement_execute()
  * function.
  *
- * See the documentation of the gda_connection_execute_statement() for information
+ * See the documentation of the gda_connection_statement_execute() for information
  * about the @params list of parameters.
  *
  * Returns: a #GdaDataModel containing the data returned by the
@@ -1421,7 +1382,7 @@
 
 	retval = gda_server_provider_begin_transaction (cnc->priv->provider_obj, cnc, name, level, error);
 	if (retval)
-		gda_client_notify_event (cnc->priv->client, cnc, GDA_CLIENT_EVENT_TRANSACTION_STARTED, NULL);
+		_gda_client_notify_event (cnc->priv->client, cnc, GDA_CLIENT_EVENT_TRANSACTION_STARTED, NULL);
 
 	return retval;
 }
@@ -1449,7 +1410,7 @@
 
 	retval = gda_server_provider_commit_transaction (cnc->priv->provider_obj, cnc, name, error);
 	if (retval)
-		gda_client_notify_event (cnc->priv->client, cnc, GDA_CLIENT_EVENT_TRANSACTION_COMMITTED, NULL);
+		_gda_client_notify_event (cnc->priv->client, cnc, GDA_CLIENT_EVENT_TRANSACTION_COMMITTED, NULL);
 
 	return retval;
 }
@@ -1478,7 +1439,7 @@
 
 	retval = gda_server_provider_rollback_transaction (cnc->priv->provider_obj, cnc, name, error);
 	if (retval)
-		gda_client_notify_event (cnc->priv->client, cnc, GDA_CLIENT_EVENT_TRANSACTION_CANCELLED, NULL);
+		_gda_client_notify_event (cnc->priv->client, cnc, GDA_CLIENT_EVENT_TRANSACTION_CANCELLED, NULL);
 
 	return retval;
 }

Modified: branches/V4-branch/libgda/gda-connection.h
==============================================================================
--- branches/V4-branch/libgda/gda-connection.h	(original)
+++ branches/V4-branch/libgda/gda-connection.h	Wed Feb 20 20:36:04 2008
@@ -128,9 +128,6 @@
 
 
 GType                gda_connection_get_type             (void) G_GNUC_CONST;
-GdaConnection       *gda_connection_new                  (GdaClient *client, GdaServerProvider *provider,
-							  const gchar *dsn, const gchar *auth_string,
-							  GdaConnectionOptions options);
 gboolean             gda_connection_open                 (GdaConnection *cnc, GError **error);
 void                 gda_connection_close                (GdaConnection *cnc);
 void                 gda_connection_close_no_warning     (GdaConnection *cnc);

Modified: branches/V4-branch/libgda/gda-data-proxy.c
==============================================================================
--- branches/V4-branch/libgda/gda-data-proxy.c	(original)
+++ branches/V4-branch/libgda/gda-data-proxy.c	Wed Feb 20 20:36:04 2008
@@ -3178,7 +3178,6 @@
 			     GError **error)
 {
 	GdaDataProxy *proxy;
-	GdaValueAttribute att = 0;
 
 	g_return_val_if_fail (GDA_IS_DATA_PROXY (model), FALSE);
 	proxy = GDA_DATA_PROXY (model);
@@ -3188,13 +3187,6 @@
 	/* ensure that there is no sync to be done */
 	ensure_chunk_sync (proxy);
 
-	att = gda_data_proxy_get_value_attributes (proxy, proxy_row, col);
-	if (att & GDA_VALUE_ATTR_NO_MODIF) {
-		g_set_error (error, GDA_DATA_PROXY_ERROR, GDA_DATA_PROXY_READ_ONLY_VALUE,
-			     _("Value is read-only"));
-		return FALSE;
-	}
-
 	if ((proxy_row == 0) && proxy->priv->add_null_entry) {
 		g_set_error (error, GDA_DATA_PROXY_ERROR, GDA_DATA_PROXY_READ_ONLY_ROW,
 			     _("The first row is an empty row artificially prepended and cannot be altered"));

Modified: branches/V4-branch/libgda/gda-server-provider.c
==============================================================================
--- branches/V4-branch/libgda/gda-server-provider.c	(original)
+++ branches/V4-branch/libgda/gda-server-provider.c	Wed Feb 20 20:36:04 2008
@@ -306,8 +306,10 @@
 			g_object_set (G_OBJECT (cnc), "auth_string", auth_string, "options", options, NULL);
 		}
 	}
-	else 
-		cnc = gda_connection_new (client, provider, dsn, auth_string, options);
+	else
+		cnc = g_object_new (GDA_TYPE_CONNECTION, "client", client, "provider_obj", provider, 
+				    "dsn", dsn, "auth_string", auth_string, 
+				    "options", options, NULL);
 
 	return cnc;
 }

Modified: branches/V4-branch/libgda/gda-server-provider.h
==============================================================================
--- branches/V4-branch/libgda/gda-server-provider.h	(original)
+++ branches/V4-branch/libgda/gda-server-provider.h	Wed Feb 20 20:36:04 2008
@@ -54,7 +54,8 @@
 	GDA_SERVER_PROVIDER_STATEMENT_EXEC_ERROR,
 	GDA_SERVER_PROVIDER_OPERATION_ERROR,
 	GDA_SERVER_PROVIDER_INTERNAL_ERROR,
-	GDA_SERVER_PROVIDER_BUSY_ERROR
+	GDA_SERVER_PROVIDER_BUSY_ERROR,
+	GDA_SERVER_PROVIDER_NON_SUPPORTED_ERROR
 } GdaServerProviderError;
 
 struct _GdaServerProvider {
@@ -150,6 +151,14 @@
 	gboolean                (* cancel)               (GdaServerProvider *provider, GdaConnection *cnc, guint task_id);
 	GdaConnection          *(* create_connection)    (GdaServerProvider *provider);
 	GdaServerProviderMeta      meta_funcs;
+
+	/* Padding for future expansion */
+	void                    (*_gda_reserved1)        (void);
+	void                    (*_gda_reserved2)        (void);
+	void                    (*_gda_reserved3)        (void);
+	void                    (*_gda_reserved4)        (void);
+	void                    (*_gda_reserved5)        (void);
+	void                    (*_gda_reserved6)        (void);
 };
 
 GType                  gda_server_provider_get_type (void) G_GNUC_CONST;

Modified: branches/V4-branch/libgda/providers-support/gda-pmodel.c
==============================================================================
--- branches/V4-branch/libgda/providers-support/gda-pmodel.c	(original)
+++ branches/V4-branch/libgda/providers-support/gda-pmodel.c	Wed Feb 20 20:36:04 2008
@@ -55,7 +55,11 @@
         PROP_0,
 	PROP_PREP_STMT,
 	PROP_MOD_STMT,
-	PROP_FLAGS
+	PROP_FLAGS,
+	PROP_ALL_STORED,
+	PROP_INS_QUERY,
+	PROP_UPD_QUERY,
+	PROP_DEL_QUERY
 };
 
 static void gda_pmodel_class_init (GdaPModelClass *klass);
@@ -144,6 +148,27 @@
 							    GDA_DATA_MODEL_ACCESS_RANDOM, G_MAXUINT,
 							    GDA_DATA_MODEL_ACCESS_RANDOM,
 							    G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+	g_object_class_install_property (object_class, PROP_ALL_STORED,
+					 g_param_spec_boolean ("store-all-rows", "Store all the rows",
+							       "Tells if model has analysed all the rows", FALSE,
+							       G_PARAM_READABLE | G_PARAM_WRITABLE));
+	g_object_class_install_property (object_class, PROP_INS_QUERY,
+                                         g_param_spec_object ("insert_query", "INSERT query", 
+							      "INSERT Query to be executed to add data",
+							      GDA_TYPE_STATEMENT,
+							      G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+	g_object_class_install_property (object_class, PROP_UPD_QUERY,
+                                         g_param_spec_object ("update_query", "UPDATE query", 
+							      "UPDATE Query to be executed to update data",
+							      GDA_TYPE_STATEMENT,
+							      G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+	g_object_class_install_property (object_class, PROP_DEL_QUERY,
+                                         g_param_spec_object ("delete_query", "DELETE query", 
+							      "DELETE Query to be executed to remove data",
+							      GDA_TYPE_STATEMENT,
+							      G_PARAM_READABLE | G_PARAM_WRITABLE));
 
 	/* virtual functions */
 	object_class->dispose = gda_pmodel_dispose;
@@ -308,6 +333,19 @@
 			model->priv->usage_flags = flags;
 			break;
 		}
+		case PROP_ALL_STORED:
+			if ((model->advertized_nrows < 0) && CLASS (model)->fetch_nb_rows)
+				CLASS (model)->fetch_nb_rows (model);
+				
+			if (model->nb_stored_rows != model->advertized_nrows) {
+				if (CLASS (model)->store_all)
+					CLASS (model)->store_all (model, NULL);
+			}
+			break;
+		case PROP_INS_QUERY:
+		case PROP_DEL_QUERY:
+		case PROP_UPD_QUERY:
+			TO_IMPLEMENT;
 		default:
 			break;
 		}
@@ -332,6 +370,20 @@
 		case PROP_FLAGS:
 			g_value_set_uint (value, model->priv->usage_flags);
 			break;
+		case PROP_ALL_STORED:
+			if (!model->priv->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM)
+				g_warning ("Cannot set the 'store-all-rows' property when acces mode is cursor based");
+			else {
+				if ((model->advertized_nrows < 0) && CLASS (model)->fetch_nb_rows)
+					CLASS (model)->fetch_nb_rows (model);
+				g_value_set_boolean (value, model->nb_stored_rows == model->advertized_nrows);
+			}
+			break;
+		case PROP_INS_QUERY:
+		case PROP_DEL_QUERY:
+		case PROP_UPD_QUERY:
+			TO_IMPLEMENT;
+
 		default:
 			break;
 		}
@@ -344,7 +396,8 @@
  * @row: a #GdaPRow row
  * @rownum: "external" advertized row number
  *
- * Stores @row into @model, externally advertized at row number @rownum
+ * Stores @row into @model, externally advertized at row number @rownum. The reference to
+ * @row is stolen.
  */
 void
 gda_pmodel_take_row (GdaPModel *model, GdaPRow *row, gint rownum)
@@ -357,7 +410,7 @@
 
 	g_hash_table_insert (model->priv->index, GINT_TO_POINTER (rownum + 1), GINT_TO_POINTER (model->priv->rows->len + 1));
 	g_array_append_val (model->priv->rows, row);
-	g_object_ref (row);
+	model->nb_stored_rows = model->priv->rows->len;
 }
 
 /**
@@ -383,6 +436,51 @@
 		return g_array_index (model->priv->rows, GdaPRow *, irow - 1);
 }
 
+/**
+ * gda_pmodel_set_modification_query
+ * @model: a #GdaPModel data model
+ * @mod_stmt: a #GdaStatement (INSERT, UPDATE or DELETE)
+ * @error: a place to store errors, or %NULL
+ *
+ * Forces @model to allow data modification using @mod_stmt as the statement executed when the corresponding
+ * modification is requested
+ *
+ * Returns: TRUE if no error occurred.
+ */
+gboolean
+gda_pmodel_set_modification_query (GdaPModel *model, GdaStatement *mod_stmt, GError **error)
+{
+	g_return_val_if_fail (GDA_IS_PMODEL (model), FALSE);
+	g_return_val_if_fail (model->priv, FALSE);
+	g_return_val_if_fail (GDA_IS_STATEMENT (mod_stmt), FALSE);
+
+	TO_IMPLEMENT;
+
+	return FALSE;
+}
+
+/**
+ * gda_pmodel_compute_modification_queries
+ * @model: a #GdaPModel data model
+ * @target: the name of the target to modify (a table name or alias)
+ * @use_all_fields_if_no_pk: set to TRUE if all fields must be used in the WHERE condition when no primary key exists
+ * @error: a place to store errors, or %NULL
+ *
+ * Makes @model try to compute INSERT, UPDATE and DELETE statements to be used when modifying @model's contents
+ *
+ * Returns: TRUE if no error occurred.
+ */
+gboolean
+gda_pmodel_compute_modification_queries (GdaPModel *model, const gchar *target, gboolean use_all_fields_if_no_pk, GError **error)
+{
+	g_return_val_if_fail (GDA_IS_PMODEL (model), FALSE);
+	g_return_val_if_fail (model->priv, FALSE);
+
+	TO_IMPLEMENT;
+
+	return FALSE;
+}
+
 /*
  * GdaDataModel interface implementation
  */
@@ -449,27 +547,34 @@
 gda_pmodel_get_value_at (GdaDataModel *model, gint col, gint row)
 {
 	GdaPRow *prow;
-	gint irow;
+	gint irow, nrows;
 	GdaPModel *imodel;
 
 	g_return_val_if_fail (GDA_IS_PMODEL (model), NULL);
 	imodel = (GdaPModel *) model;
-	g_return_val_if_fail (imodel->priv, 0);
+	g_return_val_if_fail (imodel->priv, NULL);
 
 	/* available only if GDA_DATA_MODEL_ACCESS_RANDOM */
 	if (! (imodel->priv->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM))
 		return NULL;
 
+	/* check row number validity */
+	nrows = imodel->advertized_nrows < 0 ? gda_pmodel_get_n_rows (model) : imodel->advertized_nrows;
+	if ((row < 0) || ((nrows >= 0) && (row >= nrows)))
+		return NULL;
+
 	irow = GPOINTER_TO_INT (g_hash_table_lookup (imodel->priv->index, GINT_TO_POINTER (row + 1)));
 	if (irow <= 0) {
-		if (CLASS (model)->fetch_random)
-			prow = CLASS (model)->fetch_random (imodel, row, NULL);
+		prow = NULL;
+		if (CLASS (model)->fetch_random) 
+			CLASS (model)->fetch_random (imodel, &prow, row, NULL);
 	}
 	else 
 		prow = g_array_index (imodel->priv->rows, GdaPRow *, irow - 1);
 	
 	if (prow) 
 		return gda_prow_get_value (prow, col);
+
 	return NULL;
 }
 
@@ -520,10 +625,12 @@
 	GdaPModel *imodel;
 	GdaPRow *prow = NULL;
 	gint target_iter_row;
+	gint irow;
 
-	g_return_val_if_fail (GDA_IS_PMODEL (model), 0);
+	g_return_val_if_fail (GDA_IS_PMODEL (model), FALSE);
 	imodel = (GdaPModel *) model;
-	g_return_val_if_fail (imodel->priv, 0);
+	g_return_val_if_fail (imodel->priv, FALSE);
+	g_return_val_if_fail (CLASS (model)->fetch_next, FALSE);
 
 	if (imodel->priv->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM) 
 		return gda_data_model_move_iter_next_default (model, iter);
@@ -538,10 +645,11 @@
 	else
 		target_iter_row = imodel->priv->iter_row + 1;
 
-	if (CLASS (model)->fetch_next)
-		prow = CLASS (model)->fetch_next (imodel, target_iter_row, NULL);
-	else
-		g_error ("INTERNAL error: fetch_next() virtual method not implemented, aborting");
+	irow = GPOINTER_TO_INT (g_hash_table_lookup (imodel->priv->index, GINT_TO_POINTER (target_iter_row + 1)));
+	if (irow > 0)
+		prow = g_array_index (imodel->priv->rows, GdaPRow *, irow - 1);
+	if (!CLASS (model)->fetch_next (imodel, &prow, target_iter_row, NULL))
+		TO_IMPLEMENT;
 	
 	if (prow) {
 		imodel->priv->iter_row = target_iter_row;
@@ -562,10 +670,12 @@
 	GdaPModel *imodel;
 	GdaPRow *prow = NULL;
 	gint target_iter_row;
+	gint irow;
 
-	g_return_val_if_fail (GDA_IS_PMODEL (model), 0);
+	g_return_val_if_fail (GDA_IS_PMODEL (model), FALSE);
 	imodel = (GdaPModel *) model;
-	g_return_val_if_fail (imodel->priv, 0);
+	g_return_val_if_fail (imodel->priv, FALSE);
+	g_return_val_if_fail (CLASS (model)->fetch_prev, FALSE);
 
 	if (imodel->priv->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM) 
 		return gda_data_model_move_iter_prev_default (model, iter);
@@ -583,18 +693,17 @@
         else
                 target_iter_row = imodel->priv->iter_row - 1;
 
-	if (CLASS (model)->fetch_prev)
-		prow = CLASS (model)->fetch_prev (imodel, target_iter_row, NULL);
-	else
-		g_error ("INTERNAL error: fetch_prev() virtual method not implemented, aborting");
+	irow = GPOINTER_TO_INT (g_hash_table_lookup (imodel->priv->index, GINT_TO_POINTER (target_iter_row + 1)));
+	if (irow > 0)
+		prow = g_array_index (imodel->priv->rows, GdaPRow *, irow - 1);
+	if (!CLASS (model)->fetch_prev (imodel, &prow, target_iter_row, NULL))
+		TO_IMPLEMENT;
 
 	if (prow) {
 		imodel->priv->iter_row = target_iter_row;
                 update_iter (imodel, prow);
                 return TRUE;
 	}
-	else 
-		goto prev_error;
 
  prev_error:
         g_object_set (G_OBJECT (iter), "current-row", -1, NULL);
@@ -607,10 +716,11 @@
 {
 	GdaPModel *imodel;
 	GdaPRow *prow = NULL;
+	gint irow;
 
-	g_return_val_if_fail (GDA_IS_PMODEL (model), 0);
+	g_return_val_if_fail (GDA_IS_PMODEL (model), FALSE);
 	imodel = (GdaPModel *) model;
-	g_return_val_if_fail (imodel->priv, 0);
+	g_return_val_if_fail (imodel->priv, FALSE);
 
 	if (imodel->priv->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM) 
 		return gda_data_model_move_iter_at_row_default (model, iter, row);
@@ -618,8 +728,13 @@
         g_return_val_if_fail (iter, FALSE);
         g_return_val_if_fail (imodel->priv->iter == iter, FALSE);
 
+	irow = GPOINTER_TO_INT (g_hash_table_lookup (imodel->priv->index, GINT_TO_POINTER (row + 1)));
+	if (irow > 0)
+		prow = g_array_index (imodel->priv->rows, GdaPRow *, irow - 1);
+
 	if (CLASS (model)->fetch_at) {
-		prow = CLASS (model)->fetch_at (imodel, row, NULL);
+		if (!CLASS (model)->fetch_at (imodel, &prow, row, NULL))
+			TO_IMPLEMENT;
 		if (prow) {
 			imodel->priv->iter_row = row;
 			update_iter (imodel, prow);
@@ -632,9 +747,16 @@
 		}
 	}
 	else {
-		/* implementation of fetch_at() is optional */
-		TO_IMPLEMENT; /* iter back or forward the right number of times */
-		return FALSE;
+		if (prow) {
+			imodel->priv->iter_row = row;
+			update_iter (imodel, prow);
+			return TRUE;
+		}
+		else {
+			/* implementation of fetch_at() is optional */
+			TO_IMPLEMENT; /* iter back or forward the right number of times */
+			return FALSE;
+		}
 	}
 }
 

Modified: branches/V4-branch/libgda/providers-support/gda-pmodel.h
==============================================================================
--- branches/V4-branch/libgda/providers-support/gda-pmodel.h	(original)
+++ branches/V4-branch/libgda/providers-support/gda-pmodel.h	Wed Feb 20 20:36:04 2008
@@ -42,7 +42,9 @@
 struct _GdaPModel {
 	GObject           object;
 	GdaPModelPrivate *priv;
+	/* read only information */
 	GdaPStmt         *prep_stmt; /* use the "prepared-stmt" property to set this */
+	gint              nb_stored_rows; /* number of GdaPRow objects currently stored */
 	gint              advertized_nrows; /* set when the number of rows becomes known */
 };
 
@@ -63,17 +65,22 @@
 
 	/* GDA_DATA_MODEL_ACCESS_RANDOM */
 	gint             (*fetch_nb_rows) (GdaPModel *model);
-	GdaPRow         *(*fetch_random)  (GdaPModel *model, gint rownum, GError **error);
+	gboolean         (*fetch_random)  (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error);
+	gboolean         (*store_all)     (GdaPModel *model, GError **error);
 
 	/* GDA_STATEMENT_MODEL_CURSOR_* */
-	GdaPRow         *(*fetch_next)    (GdaPModel *model, gint rownum, GError **error);
-	GdaPRow         *(*fetch_prev)    (GdaPModel *model, gint rownum, GError **error);
-	GdaPRow         *(*fetch_at)      (GdaPModel *model, gint rownum, GError **error);
+	gboolean         (*fetch_next)    (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error);
+	gboolean         (*fetch_prev)    (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error);
+	gboolean         (*fetch_at)      (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error);
 };
 
-GType    gda_pmodel_get_type       (void) G_GNUC_CONST;
-void     gda_pmodel_take_row       (GdaPModel *model, GdaPRow *row, gint rownum);
-GdaPRow *gda_pmodel_get_stored_row (GdaPModel *model, gint rownum);
+GType    gda_pmodel_get_type                     (void) G_GNUC_CONST;
+void     gda_pmodel_take_row                     (GdaPModel *model, GdaPRow *row, gint rownum);
+GdaPRow *gda_pmodel_get_stored_row               (GdaPModel *model, gint rownum);
+
+gboolean gda_pmodel_set_modification_query       (GdaPModel *model, GdaStatement *mod_stmt, GError **error);
+gboolean gda_pmodel_compute_modification_queries (GdaPModel *model, const gchar *target, 
+						  gboolean use_all_fields_if_no_pk, GError **error);
 
 G_END_DECLS
 

Modified: branches/V4-branch/libgda/providers-support/gda-pstmt.c
==============================================================================
--- branches/V4-branch/libgda/providers-support/gda-pstmt.c	(original)
+++ branches/V4-branch/libgda/providers-support/gda-pstmt.c	Wed Feb 20 20:36:04 2008
@@ -27,7 +27,8 @@
 
 static void gda_pstmt_class_init (GdaPStmtClass *klass);
 static void gda_pstmt_init       (GdaPStmt *pstmt, GdaPStmtClass *klass);
-static void gda_pstmt_finalize    (GObject *object);
+static void gda_pstmt_dispose    (GObject *object);
+static void gda_pstmt_finalize   (GObject *object);
 
 static GObjectClass *parent_class = NULL;
 
@@ -66,6 +67,7 @@
 	parent_class = g_type_class_peek_parent (klass);
 
 	/* virtual functions */
+	object_class->dispose = gda_pstmt_dispose;
 	object_class->finalize = gda_pstmt_finalize;
 }
 
@@ -81,11 +83,23 @@
 }
 
 static void
-gda_pstmt_finalize (GObject *object)
+gda_pstmt_dispose (GObject *object)
 {
 	GdaPStmt *pstmt = (GdaPStmt *) object;
 
-	g_return_if_fail (GDA_IS_PSTMT (pstmt));
+	if (pstmt->stmt) {
+		g_object_remove_weak_pointer ((GObject*) pstmt->stmt, (gpointer*) &(pstmt->stmt));
+		pstmt->stmt = NULL;
+	}
+
+	/* chain to parent class */
+	parent_class->dispose (object);
+}
+
+static void
+gda_pstmt_finalize (GObject *object)
+{
+	GdaPStmt *pstmt = (GdaPStmt *) object;
 
 	/* free memory */
 	if (pstmt->sql) {
@@ -110,7 +124,33 @@
 	parent_class->finalize (object);
 }
 
-/*
+/**
+ * gda_pstmt_set_gda_statement
+ * @pstmt: a #GdaPStmt object
+ * @stmt: a #GdaStatement object
+ *
+ * Informs @pstmt that it corresponds to the preparation of the @stmt statement
+ */
+void
+gda_pstmt_set_gda_statement (GdaPStmt *pstmt, GdaStatement *stmt)
+{
+	g_return_if_fail (GDA_IS_PSTMT (pstmt));
+	g_return_if_fail (!stmt || GDA_IS_STATEMENT (stmt));
+
+	if (pstmt->stmt == stmt)
+		return;
+	if (pstmt->stmt)
+		g_object_unref (pstmt->stmt);
+	pstmt->stmt = stmt;
+	if (stmt)
+		g_object_add_weak_pointer ((GObject*) stmt, (gpointer*) &(pstmt->stmt));
+}
+
+/**
+ * gda_pstmt_copy_contents
+ * @src: a #GdaPStmt object
+ * @dest: a #GdaPStmt object
+ *
  * Copies @src's data to @dest 
  */
 void

Modified: branches/V4-branch/libgda/providers-support/gda-pstmt.h
==============================================================================
--- branches/V4-branch/libgda/providers-support/gda-pstmt.h	(original)
+++ branches/V4-branch/libgda/providers-support/gda-pstmt.h	Wed Feb 20 20:36:04 2008
@@ -24,6 +24,7 @@
 #define __GDA_PSTMT_H__
 
 #include <glib-object.h>
+#include <libgda/gda-statement.h>
 
 G_BEGIN_DECLS
 
@@ -39,6 +40,7 @@
 struct _GdaPStmt {
 	GObject       object;
 
+	GdaStatement *stmt; /* GdaPStmt object holds a reference on this stmt object, may be NULL */
 	gchar        *sql; /* actual SQL code used for this prepared statement, mem freed by GdaPStmt */
         GSList       *param_ids; /* list of parameters' IDs (as gchar *), mem freed by GdaPStmt */
 
@@ -53,8 +55,9 @@
 	GObjectClass  parent_class;
 };
 
-GType gda_pstmt_get_type      (void) G_GNUC_CONST;
-void  gda_pstmt_copy_contents (GdaPStmt *src, GdaPStmt *dest);
+GType gda_pstmt_get_type          (void) G_GNUC_CONST;
+void  gda_pstmt_set_gda_statement (GdaPStmt *pstmt, GdaStatement *stmt);
+void  gda_pstmt_copy_contents     (GdaPStmt *src, GdaPStmt *dest);
 
 G_END_DECLS
 

Modified: branches/V4-branch/libgda/sqlite/gda-sqlite-provider.c
==============================================================================
--- branches/V4-branch/libgda/sqlite/gda-sqlite-provider.c	(original)
+++ branches/V4-branch/libgda/sqlite/gda-sqlite-provider.c	Wed Feb 20 20:36:04 2008
@@ -1481,6 +1481,7 @@
 
 	/* create a prepared statement */
 	ps = gda_sqlite_pstmt_new (sqlite_stmt);
+	gda_pstmt_set_gda_statement (_GDA_PSTMT (ps), stmt);
 	_GDA_PSTMT (ps)->param_ids = param_ids;
 	_GDA_PSTMT (ps)->sql = sql;
 	return ps;

Modified: branches/V4-branch/libgda/sqlite/gda-sqlite-recordset.c
==============================================================================
--- branches/V4-branch/libgda/sqlite/gda-sqlite-recordset.c	(original)
+++ branches/V4-branch/libgda/sqlite/gda-sqlite-recordset.c	Wed Feb 20 20:36:04 2008
@@ -40,9 +40,9 @@
 
 /* virtual methods */
 static gint    gda_sqlite_recordset_fetch_nb_rows (GdaPModel *model);
-static GdaPRow *gda_sqlite_recordset_fetch_random (GdaPModel *model, gint rownum, GError **error);
+static gboolean gda_sqlite_recordset_fetch_random (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error);
 
-static GdaPRow *gda_sqlite_recordset_fetch_next (GdaPModel *model, gint rownum, GError **error);
+static gboolean gda_sqlite_recordset_fetch_next (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error);
 
 
 static GdaPRow *fetch_next_sqlite_row (GdaSqliteRecordset *model, gboolean do_store, GError **error);
@@ -457,16 +457,23 @@
 	return model->advertized_nrows;
 }
 
-static GdaPRow *
-gda_sqlite_recordset_fetch_random (GdaPModel *model, gint rownum, GError **error)
+/*
+ * Create a new filled #GdaPRow object for the row at position @rownum.
+ *
+ * Each new #GdaPRow created is "given" to the #GdaPModel implementation using gda_pmodel_take_row ().
+ */
+static gboolean
+gda_sqlite_recordset_fetch_random (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error)
 {
 	GdaSqliteRecordset *imodel;
-	GdaPRow *prow = NULL;
+
+	if (*prow)
+		return TRUE;
 
 	imodel = GDA_SQLITE_RECORDSET (model);
 	for (; imodel->priv->next_row_num <= rownum; ) {
-		prow = fetch_next_sqlite_row (imodel, TRUE, error);
-		if (!prow) {
+		*prow = fetch_next_sqlite_row (imodel, TRUE, error);
+		if (!*prow) {
 			/*if (GDA_PMODEL (model)->advertized_nrows >= 0), it's not an error */
 			if ((GDA_PMODEL (model)->advertized_nrows >= 0) && 
 			    (imodel->priv->next_row_num < rownum)) {
@@ -474,27 +481,29 @@
 					     GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR,
 					     _("Row %d not found"), rownum);
 			}
-			break;
+			return FALSE;
 		}
 	}
 
-	return prow;
+	return TRUE;
 }
 
-static GdaPRow *
-gda_sqlite_recordset_fetch_next (GdaPModel *model, gint rownum, GError **error)
+/*
+ * Create a new filled #GdaPRow object for the next cursor row
+ *
+ * Each new #GdaPRow created is referenced only by imodel->priv->tmp_row (the #GdaPModel implementation
+ * never keeps a reference to it). Before a new #GdaPRow gets created, the previous one, if set, is discarded.
+ */
+static gboolean
+gda_sqlite_recordset_fetch_next (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error)
 {
-	GdaPRow *prow;
 	GdaSqliteRecordset *imodel = (GdaSqliteRecordset*) model;
 
-	prow = gda_pmodel_get_stored_row (model, rownum);
-	if (prow)
-		return prow;
 	if (imodel->priv->tmp_row) 
 		g_object_unref (imodel->priv->tmp_row);
 
-	prow = fetch_next_sqlite_row (imodel, FALSE, error);
-	imodel->priv->tmp_row = prow;
+	*prow = fetch_next_sqlite_row (imodel, FALSE, error);
+	imodel->priv->tmp_row = *prow;
 
-	return prow;
+	return TRUE;
 }

Modified: branches/V4-branch/providers/Makefile.am
==============================================================================
--- branches/V4-branch/providers/Makefile.am	(original)
+++ branches/V4-branch/providers/Makefile.am	Wed Feb 20 20:36:04 2008
@@ -53,7 +53,8 @@
 SUBDIRS = \
 	sqlite \
 	$(GDA_BDB_SERVER) \
-	$(GDA_MDB_SERVER)
+	$(GDA_MDB_SERVER) \
+	$(GDA_POSTGRES_SERVER)
 #	$(GDA_FREETDS_SERVER) \
 #	$(GDA_IBMDB2_SERVER) \
 #	$(GDA_FIREBIRD_SERVER) \
@@ -61,7 +62,6 @@
 #       $(GDA_MSQL_SERVER) \
 #	$(GDA_ODBC_SERVER) \
 #	$(GDA_ORACLE_SERVER) \
-#	$(GDA_POSTGRES_SERVER) \
 #	$(GDA_SYBASE_SERVER) \
 #	$(GDA_XBASE_SERVER) \
 #	$(GDA_LDAP_SERVER) 

Modified: branches/V4-branch/providers/mdb/gda-mdb-provider.c
==============================================================================
--- branches/V4-branch/providers/mdb/gda-mdb-provider.c	(original)
+++ branches/V4-branch/providers/mdb/gda-mdb-provider.c	Wed Feb 20 20:36:04 2008
@@ -473,7 +473,7 @@
 				GdaBinary bin;
 				
 				bin.binary_length = mdb_ole_read (spec->cdata->mdb, mdb_col, bound_values[c], MDB_BIND_SIZE);
-				bin.data = bound_values[c];
+				bin.data = (guchar*) bound_values[c];
 				gda_value_set_binary ((tmpval = gda_value_new (coltypes [c])), &bin);
 				
 #ifdef DUMP_BINARY

Modified: branches/V4-branch/providers/postgres/Makefile.am
==============================================================================
--- branches/V4-branch/providers/postgres/Makefile.am	(original)
+++ branches/V4-branch/providers/postgres/Makefile.am	Wed Feb 20 20:36:04 2008
@@ -5,9 +5,9 @@
 	-I$(top_srcdir) \
 	-I$(top_srcdir)/libgda \
 	-I$(top_builddir) \
-	$(LIBGDA_CFLAGS) \
-	$(POSTGRES_CFLAGS) 
+	$(LIBGDA_CFLAGS) $(POSTGRES_CFLAGS) 
 
+# parser generation
 parser.c parser.h: parser.y $(top_builddir)/libgda/sql-parser/lemon$(EXEEXT_FOR_BUILD)
 	- $(top_builddir)/libgda/sql-parser/lemon$(EXEEXT_FOR_BUILD) parser.y
 
@@ -22,8 +22,6 @@
 libgda_postgres_la_SOURCES = \
 	gda-postgres-blob-op.c \
 	gda-postgres-blob-op.h \
-	gda-postgres-cursor-recordset.c \
-	gda-postgres-cursor-recordset.h \
 	gda-postgres-ddl.c \
 	gda-postgres-ddl.h \
 	gda-postgres-handler-bin.c \
@@ -32,34 +30,39 @@
 	gda-postgres-parser.h \
 	gda-postgres-provider.c \
 	gda-postgres-provider.h \
+	gda-postgres-pstmt.c \
+	gda-postgres-pstmt.h \
+	gda-postgres-meta.c \
+	gda-postgres-meta.h \
 	gda-postgres-recordset.c \
 	gda-postgres-recordset.h \
+	gda-postgres-util.c \
+	gda-postgres-util.h \
 	gda-postgres.h \
 	libmain.c \
 	parser.h \
-	parser.c \
-	postgres_token_types.h \
-	utils.c
+        parser.c \
+        postgres_token_types.h
+
 libgda_postgres_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED)
 libgda_postgres_la_LIBADD = \
 	$(top_builddir)/libgda/libgda-4.0.la \
-	$(LIBGDA_LIBS) \
-	$(POSTGRES_LIBS)
+	$(LIBGDA_LIBS) $(POSTGRES_LIBS)
 
 xmldir   = $(datadir)/libgda-4.0
 xml_in_files = \
 	postgres_specs_create_db.xml.in \
-	postgres_specs_drop_db.xml.in \
-	postgres_specs_dsn.xml.in \
-	postgres_specs_create_table.xml.in \
-	postgres_specs_drop_table.xml.in \
-	postgres_specs_create_index.xml.in \
-	postgres_specs_drop_index.xml.in \
-	postgres_specs_rename_table.xml.in \
-	postgres_specs_add_column.xml.in \
-	postgres_specs_drop_column.xml.in \
-	postgres_specs_create_view.xml.in \
-	postgres_specs_drop_view.xml.in
+        postgres_specs_drop_db.xml.in \
+        postgres_specs_dsn.xml.in \
+        postgres_specs_create_table.xml.in \
+        postgres_specs_drop_table.xml.in \
+        postgres_specs_create_index.xml.in \
+        postgres_specs_drop_index.xml.in \
+        postgres_specs_rename_table.xml.in \
+        postgres_specs_add_column.xml.in \
+        postgres_specs_drop_column.xml.in \
+        postgres_specs_create_view.xml.in \
+        postgres_specs_drop_view.xml.in
 
 @INTLTOOL_XML_RULE@
 
@@ -71,5 +74,4 @@
 EXTRA_DIST = $(xml_in_files) libgda-postgres-4.0.pc.in parser.y
 DISTCLEANFILES = $(xml_DATA)
 
-
 CLEANFILES = parser.h parser.c parser.out postgres_token_types.h gen_def$(EXEEXT_FOR_BUILD)

Modified: branches/V4-branch/providers/postgres/gda-postgres-blob-op.c
==============================================================================
--- branches/V4-branch/providers/postgres/gda-postgres-blob-op.c	(original)
+++ branches/V4-branch/providers/postgres/gda-postgres-blob-op.c	Wed Feb 20 20:36:04 2008
@@ -1,5 +1,5 @@
 /* GDA Postgres blob
- * Copyright (C) 2005 - 2007 The GNOME Foundation
+ * Copyright (C) 2005 - 2008 The GNOME Foundation
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -24,13 +24,7 @@
 #include <string.h>
 #include "gda-postgres.h"
 #include "gda-postgres-blob-op.h"
-#include <libpq/libpq-fs.h>
-
-#ifdef PARENT_TYPE
-#undef PARENT_TYPE
-#endif
-
-#define PARENT_TYPE GDA_TYPE_BLOB_OP
+#include "gda-postgres-util.h"
 
 struct _GdaPostgresBlobOpPrivate {
 	GdaConnection *cnc;
@@ -69,7 +63,7 @@
 			0,
 			(GInstanceInitFunc) gda_postgres_blob_op_init
 		};
-		type = g_type_register_static (PARENT_TYPE, "GdaPostgresBlobOp", &info, 0);
+		type = g_type_register_static (GDA_TYPE_BLOB_OP, "GdaPostgresBlobOp", &info, 0);
 	}
 	return type;
 }
@@ -102,33 +96,40 @@
 static PGconn *
 get_pconn (GdaConnection *cnc)
 {
-	GdaPostgresConnectionData *priv_data;
+	PostgresConnectionData *cdata;
 
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-	if (!priv_data) {
-		gda_connection_add_event_string (cnc, _("Invalid PostgreSQL handle"));
+	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
 		return NULL;
-	}
 
-	return priv_data->pconn;
+	return cdata->pconn;
 }
 
 static gboolean
 blob_op_open (GdaPostgresBlobOp *pgop)
 {
+	gboolean use_svp = FALSE;
+
 	if (pgop->priv->blobid == InvalidOid)
 		return FALSE;
 	if (pgop->priv->fd >= 0)
 		return TRUE;
 
-	/* add a savepoint to prevent a blob open failure from rendering the transaction unuseable */
-	gda_connection_add_savepoint (pgop->priv->cnc, "__gda_blob_read_svp", NULL);
+	if (gda_connection_get_transaction_status (pgop->priv->cnc)) 
+		/* add a savepoint to prevent a blob open failure from rendering the transaction unuseable */
+		use_svp = TRUE;
+
+	if (use_svp)
+		gda_connection_add_savepoint (pgop->priv->cnc, "__gda_blob_read_svp", NULL);
+	
 	pgop->priv->fd = lo_open (get_pconn (pgop->priv->cnc), pgop->priv->blobid, INV_READ | INV_WRITE);
 	if (pgop->priv->fd < 0) {
-		gda_connection_rollback_savepoint (pgop->priv->cnc, "__gda_blob_read_svp", NULL);
+		if (use_svp)
+			gda_connection_rollback_savepoint (pgop->priv->cnc, "__gda_blob_read_svp", NULL);
 		return FALSE;
 	}
-	gda_connection_delete_savepoint (pgop->priv->cnc, "__gda_blob_read_svp", NULL);
+	if (use_svp)
+		gda_connection_delete_savepoint (pgop->priv->cnc, "__gda_blob_read_svp", NULL);
 	return TRUE;
 }
 
@@ -193,7 +194,7 @@
 		PGconn *pconn = get_pconn (pgop->priv->cnc);
 		pgop->priv->blobid = lo_creat (pconn, INV_READ | INV_WRITE);
 		if (pgop->priv->blobid == InvalidOid) {
-			gda_postgres_make_error (pgop->priv->cnc, pconn, NULL);
+			_gda_postgres_make_error (pgop->priv->cnc, pconn, NULL, NULL);
 			return FALSE;
 		}
 	}
@@ -283,14 +284,14 @@
 
 	pconn = get_pconn (pgop->priv->cnc);
 	if (lo_lseek (pconn, pgop->priv->fd, offset, SEEK_SET) < 0) {
-		gda_postgres_make_error (pgop->priv->cnc, pconn, NULL);
+		_gda_postgres_make_error (pgop->priv->cnc, pconn, NULL, NULL);
 		return -1;
 	}
 
 	bin = (GdaBinary *) blob;
 	if (bin->data) 
 		g_free (bin->data);
-	bin->data = g_new0 (gchar, size);
+	bin->data = g_new0 (guchar, size);
 	bin->binary_length = lo_read (pconn, pgop->priv->fd, (char *) (bin->data), size);
 	return bin->binary_length;
 }
@@ -314,14 +315,14 @@
 
 	pconn = get_pconn (pgop->priv->cnc);
 	if (lo_lseek (pconn, pgop->priv->fd, offset, SEEK_SET) < 0) {
-		gda_postgres_make_error (pgop->priv->cnc, pconn, NULL);
+		_gda_postgres_make_error (pgop->priv->cnc, pconn, NULL, NULL);
 		return -1;
 	}
 
 	bin = (GdaBinary *) blob;
 	nbwritten = lo_write (pconn, pgop->priv->fd, (char*) bin->data, bin->binary_length);
 	if (nbwritten == -1) {
-		gda_postgres_make_error (pgop->priv->cnc, pconn, NULL);
+		_gda_postgres_make_error (pgop->priv->cnc, pconn, NULL, NULL);
 		return -1;
 	}
 

Modified: branches/V4-branch/providers/postgres/gda-postgres-ddl.c
==============================================================================
--- branches/V4-branch/providers/postgres/gda-postgres-ddl.c	(original)
+++ branches/V4-branch/providers/postgres/gda-postgres-ddl.c	Wed Feb 20 20:36:04 2008
@@ -1,9 +1,8 @@
-/* GNOME DB Postgres Provider
- * Copyright (C) 2006 - 2008 The GNOME Foundation
+/* GDA Postgres Provider
+ * Copyright (C) 2008 The GNOME Foundation
  *
  * AUTHORS:
- *         Vivien Malerba <malerba gnome-db org>
- *         Bas Driessen <bas driessen xobas com>
+ *      TO_ADD: your name and email
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -21,85 +20,13 @@
  * Boston, MA 02111-1307, USA.
  */
 
-#include "gda-postgres-ddl.h"
 #include <glib/gi18n-lib.h>
-#include <libgda/gda-data-handler.h>
-
-gchar *
-gda_postgres_render_CREATE_DB (GdaServerProvider *provider, GdaConnection *cnc, 
-			       GdaServerOperation *op, GError **error)
-{
-	GString *string;
-	const GValue *value;
-	gchar *sql = NULL;
-
-	string = g_string_new ("CREATE DATABASE ");
-
-	value = gda_server_operation_get_value_at (op, "/DB_DEF_P/DB_NAME");
-	g_assert (value && G_VALUE_HOLDS (value, G_TYPE_STRING));
-	g_string_append_printf (string, "\"%s\"", g_value_get_string (value));
-
-	value = gda_server_operation_get_value_at (op, "/DB_DEF_P/OWNER");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value)) {
-		g_string_append (string, " OWNER ");
-		g_string_append (string, g_value_get_string (value));
-	}
-
-	value = gda_server_operation_get_value_at (op, "/DB_DEF_P/TEMPLATE");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value)) {
-		g_string_append (string, " TEMPLATE ");
-		g_string_append (string, g_value_get_string (value));
-	}
-
-	value = gda_server_operation_get_value_at (op, "/DB_DEF_P/DB_CSET");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value)) {
-		GdaDataHandler *dh;
-		gchar *str;
-		
-		dh = gda_server_provider_get_data_handler_gtype (provider, cnc, G_TYPE_STRING);
-		str = gda_data_handler_get_sql_from_value (dh, value);
-
-		g_string_append (string, " ENCODING ");
-		g_string_append (string, str);
-		g_free (str);
-	}
-
-	value = gda_server_operation_get_value_at (op, "/DB_DEF_P/TABLESPACE");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value)) {
-		g_string_append (string, " TABLESPACE ");
-		g_string_append (string, g_value_get_string (value));
-	}
-
-	sql = string->str;
-	g_string_free (string, FALSE);
-
-	return sql;	
-}
-
-gchar *
-gda_postgres_render_DROP_DB (GdaServerProvider *provider, GdaConnection *cnc, 
-			     GdaServerOperation *op, GError **error)
-{
-	GString *string;
-	const GValue *value;
-	gchar *sql = NULL;
-
-	string = g_string_new ("DROP DATABASE ");
-
-	value = gda_server_operation_get_value_at (op, "/DB_DESC_P/DB_NAME");
-	g_assert (value && G_VALUE_HOLDS (value, G_TYPE_STRING));
-	g_string_append_printf (string, "\"%s\"", g_value_get_string (value));
-
-	sql = string->str;
-	g_string_free (string, FALSE);
-
-	return sql;	
-}
-
+#include <libgda/libgda.h>
+#include "gda-postgres-ddl.h"
 
 gchar *
 gda_postgres_render_CREATE_TABLE (GdaServerProvider *provider, GdaConnection *cnc, 
-				  GdaServerOperation *op, GError **error)
+			      GdaServerOperation *op, GError **error)
 {
 	GString *string;
 	const GValue *value;
@@ -112,11 +39,8 @@
 	gint nbpkfields = 0;
 	gchar *sql = NULL;
 
-	string = g_string_new ("CREATE ");
-	value = gda_server_operation_get_value_at (op, "/TABLE_DEF_P/TABLE_TEMP");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
-		g_string_append (string, "TEMP ");
-	g_string_append (string, "TABLE ");
+	/* CREATE TABLE */
+	string = g_string_new ("CREATE TABLE ");
 
 	value = gda_server_operation_get_value_at (op, "/TABLE_DEF_P/TABLE_NAME");
 	g_assert (value && G_VALUE_HOLDS (value, G_TYPE_STRING));
@@ -150,25 +74,12 @@
 				g_string_append (string, ", ");
 				
 			value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_NAME/%d", i);
-			g_string_append_c (string, '\"');
 			g_string_append (string, g_value_get_string (value));
-			g_string_append_c (string, '\"');
 			g_string_append_c (string, ' ');
 				
 			value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_TYPE/%d", i);
 			g_string_append (string, g_value_get_string (value));
 				
-			value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_SIZE/%d", i);
-			if (value && G_VALUE_HOLDS (value, G_TYPE_UINT)) {
-				g_string_append_printf (string, "(%d", g_value_get_uint (value));
-
-				value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_SCALE/%d", i);
-				if (value && G_VALUE_HOLDS (value, G_TYPE_UINT))
-					g_string_append_printf (string, ",%d)", g_value_get_uint (value));
-				else
-					g_string_append (string, ")");
-			}
-				
 			value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_DEFAULT/%d", i);
 			if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) {
 				const gchar *str = g_value_get_string (value);
@@ -181,7 +92,7 @@
 			value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_NNUL/%d", i);
 			if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
 				g_string_append (string, " NOT NULL");
-				
+
 			value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_UNIQUE/%d", i);
 			if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
 				g_string_append (string, " UNIQUE");
@@ -202,33 +113,6 @@
 				}
 			}
 		}
-
-		/* LIKE inheritance */
-		nrows = gda_server_operation_get_sequence_size (op, "/TABLE_PARENTS_S");
-		for (i = 0; i < nrows; i++) {
-			value = gda_server_operation_get_value_at (op, "/TABLE_PARENTS_S/%d/TABLE_PARENT_COPY", i);
-			if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && !g_value_get_boolean (value)) {
-				value = gda_server_operation_get_value_at (op, "/TABLE_PARENTS_S/%d/TABLE_PARENT_TABLE", i);
-				if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) {
-					const gchar *str = g_value_get_string (value);
-					if (str && *str) {
-						hasfields = TRUE;
-						if (first) 
-							first = FALSE;
-						else
-							g_string_append (string, ", ");
-
-						g_string_append (string, "LIKE ");
-						g_string_append (string, str);
-						value = gda_server_operation_get_value_at (op, 
-											   "/TABLE_PARENTS_S/%d/TABLE_PARENT_COPY_DEFAULTS", i);
-						if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && 
-						    g_value_get_boolean (value))
-							g_string_append (string, " INCLUDING DEFAULTS");
-					}
-				}
-			}
-		}
 	}
 
 	/* composed primary key */
@@ -239,501 +123,20 @@
 		while (list) {
 			if (list != pkfields)
 				g_string_append (string, ", ");
-			g_string_append_c (string, '\"');
 			g_string_append (string, g_value_get_string ((GValue*) list->data));
-			g_string_append_c (string, '\"');
 			list = list->next;
 		}
 		g_string_append_c (string, ')');
 	}
 
-	/* foreign keys */
-	if (allok) {
-		GdaServerOperationNode *node;
-
-		first = TRUE;
-		node = gda_server_operation_get_node_info (op, "/FKEY_S");
-		if (node) {
-			nrows = gda_server_operation_get_sequence_size (op, "/FKEY_S");
-			for (i = 0; i < nrows; i++) {
-				gint nbfields, j;
-
-				g_string_append (string, ", FOREIGN KEY (");
-				node = gda_server_operation_get_node_info (op, "/FKEY_S/%d/FKEY_FIELDS_A", i);
-				if (!node || ((nbfields = gda_data_model_get_n_rows (node->model)) == 0)) {
-					allok = FALSE;
-					g_set_error (error, 0, 0, _("No field specified in foreign key constraint"));
-				}
-				else {
-					for (j = 0; j < nbfields; j++) {
-						if (j != 0)
-							g_string_append (string, ", ");
-						value = gda_server_operation_get_value_at (op, 
-											   "/FKEY_S/%d/FKEY_FIELDS_A/@FK_FIELD/%d", i, j);
-						if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value))
-						{
-							g_string_append_c (string, '\"');
-							g_string_append (string, g_value_get_string (value));
-							g_string_append_c (string, '\"');
-						}
-						else {
-							allok = FALSE;
-							g_set_error (error, 0, 0, 
-								     _("Empty field specified in foreign key constraint"));
-						}
-					}
-				}
-				g_string_append (string, ") REFERENCES ");
-				value = gda_server_operation_get_value_at (op, "/FKEY_S/%d/FKEY_REF_TABLE", i);
-				if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value))
-					g_string_append (string, g_value_get_string (value));
-				else {
-					allok = FALSE;
-					g_set_error (error, 0, 0, _("No referenced table specified in foreign key constraint"));
-				}
-
-				g_string_append (string, " (");
-				for (j = 0; j < nbfields; j++) {
-					if (j != 0)
-						g_string_append (string, ", ");
-					value = gda_server_operation_get_value_at (op, 
-										   "/FKEY_S/%d/FKEY_FIELDS_A/@FK_REF_PK_FIELD/%d", i, j);
-					if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value))
-					{
-						g_string_append_c (string, '\"');
-						g_string_append (string, g_value_get_string (value));
-						g_string_append_c (string, '\"');
-					}
-					else {
-						allok = FALSE;
-						g_set_error (error, 0, 0, 
-							     _("Empty referenced field specified in foreign key constraint"));
-					}
-				}
-				g_string_append_c (string, ')');
-				value = gda_server_operation_get_value_at (op, "/FKEY_S/%d/FKEY_MATCH_TYPE", i);
-				if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value))
-					g_string_append_printf (string, " %s", g_value_get_string (value));
-				value = gda_server_operation_get_value_at (op, "/FKEY_S/%d/FKEY_ONUPDATE", i);
-				if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value))
-					g_string_append_printf (string, " ON UPDATE %s", g_value_get_string (value));
-				value = gda_server_operation_get_value_at (op, "/FKEY_S/%d/FKEY_ONDELETE", i);
-				if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value))
-					g_string_append_printf (string, " ON DELETE %s", g_value_get_string (value));
-				value = gda_server_operation_get_value_at (op, "/FKEY_S/%d/FKEY_DEFERRABLE", i);
-				if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value))
-					g_string_append_printf (string, " %s", g_value_get_string (value));
-			}
-		}
-	}
-
 	g_string_append (string, ")");
 
-	/* INHERITS */
-	first = TRUE;
-	nrows = gda_server_operation_get_sequence_size (op, "/TABLE_PARENTS_S");
-	for (i = 0; i < nrows; i++) {
-		value = gda_server_operation_get_value_at (op, "/TABLE_PARENTS_S/%d/TABLE_PARENT_COPY", i);
-		if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value)) {
-			value = gda_server_operation_get_value_at (op, "/TABLE_PARENTS_S/%d/TABLE_PARENT_TABLE", i);
-			if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) {
-				const gchar *str = g_value_get_string (value);
-				if (str && *str) {
-					hasfields = TRUE;
-					if (first) {
-						g_string_append (string, " INHERITS ");
-						first = FALSE;
-					}
-					else
-						g_string_append (string, ", ");
-					g_string_append (string, str);
-				}
-			}
-		}
-	}
-
 	if (!hasfields) {
 		allok = FALSE;
 		g_set_error (error, 0, 0, _("Table to create must have at least one row"));
 	}
-
-	if (allok) {
-		value = gda_server_operation_get_value_at (op, "/TABLE_DEF_P/TABLE_WITH_OIDS");
-		if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
-			g_string_append (string, " WITH OIDS");
-	}
-
 	g_slist_free (pkfields);
 
-
-	sql = string->str;
-	g_string_free (string, FALSE);
-
-	return sql;
-}
-
-gchar *
-gda_postgres_render_DROP_TABLE   (GdaServerProvider *provider, GdaConnection *cnc, 
-				  GdaServerOperation *op, GError **error)
-{
-	GString *string;
-	const GValue *value;
-	gchar *sql = NULL;
-
-	string = g_string_new ("DROP TABLE ");
-
-	value = gda_server_operation_get_value_at (op, "/TABLE_DESC_P/TABLE_NAME");
-	g_assert (value && G_VALUE_HOLDS (value, G_TYPE_STRING));
-	g_string_append (string, g_value_get_string (value));
-
-	value = gda_server_operation_get_value_at (op, "/TABLE_DESC_P/REFERENCED_ACTION");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) {
-		g_string_append_c (string, ' ');
-		g_string_append (string, g_value_get_string (value));
-	}
-
-	sql = string->str;
-	g_string_free (string, FALSE);
-
-	return sql;
-}
-
-gchar *
-gda_postgres_render_RENAME_TABLE (GdaServerProvider *provider, GdaConnection *cnc, 
-				  GdaServerOperation *op, GError **error)
-{
-	GString *string;
-	const GValue *value;
-	gchar *sql = NULL;
-
-	string = g_string_new ("ALTER TABLE ");
-
-	value = gda_server_operation_get_value_at (op, "/TABLE_DESC_P/TABLE_NAME");
-	g_assert (value && G_VALUE_HOLDS (value, G_TYPE_STRING));
-	g_string_append (string, g_value_get_string (value));
-
-	value = gda_server_operation_get_value_at (op, "/TABLE_DESC_P/TABLE_NEW_NAME");
-	g_assert (value && G_VALUE_HOLDS (value, G_TYPE_STRING));
-	g_string_append (string, " RENAME TO ");
-	g_string_append (string, g_value_get_string (value));
-
-	sql = string->str;
-	g_string_free (string, FALSE);
-
-	return sql;
-}
-
-
-gchar *
-gda_postgres_render_ADD_COLUMN (GdaServerProvider *provider, GdaConnection *cnc, 
-				GdaServerOperation *op, GError **error)
-{
-	GString *string;
-	const GValue *value;
-	gchar *sql = NULL;
-
-	string = g_string_new ("ALTER TABLE ");
-
-	value = gda_server_operation_get_value_at (op, "/COLUMN_DEF_P/TABLE_ONLY");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
-		g_string_append (string, "ONLY ");
-
-	value = gda_server_operation_get_value_at (op, "/COLUMN_DEF_P/TABLE_NAME");
-	g_assert (value && G_VALUE_HOLDS (value, G_TYPE_STRING));
-	g_string_append (string, g_value_get_string (value));
-
-	g_string_append (string, " ADD COLUMN ");
-
-	value = gda_server_operation_get_value_at (op, "/COLUMN_DEF_P/COLUMN_NAME");
-	g_assert (value && G_VALUE_HOLDS (value, G_TYPE_STRING));
-	g_string_append (string, g_value_get_string (value));
-
-	value = gda_server_operation_get_value_at (op, "/COLUMN_DEF_P/COLUMN_TYPE");
-	g_assert (value && G_VALUE_HOLDS (value, G_TYPE_STRING));
-	g_string_append_c (string, ' ');
-	g_string_append (string, g_value_get_string (value));
-
-	value = gda_server_operation_get_value_at (op, "/COLUMN_DEF_P/COLUMN_SIZE");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_UINT)) {
-		g_string_append_printf (string, "(%d", g_value_get_uint (value));
-
-		value = gda_server_operation_get_value_at (op, "/COLUMN_DEF_P/COLUMN_SCALE");
-		if (value && G_VALUE_HOLDS (value, G_TYPE_UINT))
-			g_string_append_printf (string, ",%d)", g_value_get_uint (value));
-		else
-			g_string_append (string, ")");
-	}
-
-	value = gda_server_operation_get_value_at (op, "/COLUMN_DEF_P/COLUMN_DEFAULT");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) {
-		const gchar *str = g_value_get_string (value);
-		if (str && *str) {
-			g_string_append (string, " DEFAULT ");
-			g_string_append (string, str);
-		}
-	}
-				
-	value = gda_server_operation_get_value_at (op, "/COLUMN_DEF_P/COLUMN_NNUL");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
-		g_string_append (string, " NOT NULL");
-				
-	value = gda_server_operation_get_value_at (op, "/COLUMN_DEF_P/COLUMN_UNIQUE");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
-		g_string_append (string, " UNIQUE");
-	
-	value = gda_server_operation_get_value_at (op, "/COLUMN_DEF_P/COLUMN_PKEY");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
-		g_string_append (string, " PRIMARY KEY");
-				
-	value = gda_server_operation_get_value_at (op, "/COLUMN_DEF_P/COLUMN_CHECK");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) {
-		const gchar *str = g_value_get_string (value);
-		if (str && *str) {
-			g_string_append (string, " CHECK (");
-			g_string_append (string, str);
-			g_string_append_c (string, ')');
-		}
-	}
-
-	sql = string->str;
-	g_string_free (string, FALSE);
-
-	return sql;
-}
-
-gchar *
-gda_postgres_render_DROP_COLUMN  (GdaServerProvider *provider, GdaConnection *cnc, 
-				  GdaServerOperation *op, GError **error)
-{
-	GString *string;
-	const GValue *value;
-	gchar *sql = NULL;
-
-	string = g_string_new ("ALTER TABLE ");
-
-	value = gda_server_operation_get_value_at (op, "/COLUMN_DESC_P/TABLE_NAME");
-	g_assert (value && G_VALUE_HOLDS (value, G_TYPE_STRING));
-	g_string_append (string, g_value_get_string (value));
-
-	value = gda_server_operation_get_value_at (op, "/COLUMN_DESC_P/COLUMN_NAME");
-	g_assert (value && G_VALUE_HOLDS (value, G_TYPE_STRING));
-	g_string_append (string, " DROP COLUMN ");
-	g_string_append (string, g_value_get_string (value));
-
-	value = gda_server_operation_get_value_at (op, "/COLUMN_DESC_P/REFERENCED_ACTION");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) {
-		const gchar *str = g_value_get_string (value);
-		if (str && *str) {
-			g_string_append_c (string, ' ');
-			g_string_append (string, str);
-		}
-	}
-
-	sql = string->str;
-	g_string_free (string, FALSE);
-
-	return sql;
-}
-
-
-gchar *
-gda_postgres_render_CREATE_INDEX (GdaServerProvider *provider, GdaConnection *cnc, 
-				  GdaServerOperation *op, GError **error)
-{
-	GString *string;
-	const GValue *value;
-	gchar *sql = NULL;
-	GdaServerOperationNode *node;
-	gint nrows, i;
-
-	string = g_string_new ("CREATE ");
-
-	value = gda_server_operation_get_value_at (op, "/INDEX_DEF_P/INDEX_TYPE");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && 
-	    g_value_get_string (value) && *g_value_get_string (value)) {
-		g_string_append (string, g_value_get_string (value));
-		g_string_append_c (string, ' ');
-	}
-
-	g_string_append (string, "INDEX ");
-
-	value = gda_server_operation_get_value_at (op, "/INDEX_DEF_P/INDEX_NAME");
-	g_assert (value && G_VALUE_HOLDS (value, G_TYPE_STRING));
-	g_string_append (string, g_value_get_string (value));
-
-	g_string_append (string, " ON ");
-	
-	value = gda_server_operation_get_value_at (op, "/INDEX_DEF_P/INDEX_ON_TABLE");
-	g_assert (value && G_VALUE_HOLDS (value, G_TYPE_STRING));
-	g_string_append (string, g_value_get_string (value));
-
-	value = gda_server_operation_get_value_at (op, "/INDEX_DEF_P/INDEX_METHOD");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value)) {
-		g_string_append (string, " USING ");
-		g_string_append (string, g_value_get_string (value));
-	}
-
-	/* fields or expressions the index is on */
-	g_string_append (string, " (");
-	node = gda_server_operation_get_node_info (op, "/INDEX_FIELDS_S");
-	g_assert (node);
-	nrows = gda_server_operation_get_sequence_size (op, "/INDEX_FIELDS_S");
-	for (i = 0; i < nrows; i++) {
-		value = gda_server_operation_get_value_at (op, "/INDEX_FIELDS_S/%d/INDEX_FIELD", i);
-		if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value)) {
-			if (i != 0)
-				g_string_append (string, ", ");
-			g_string_append_c (string, '\"');
-			g_string_append (string, g_value_get_string (value));
-			g_string_append_c (string, '\"');
-		}
-	}
-
-	g_string_append (string, ")");
-
-	/* options */
-	value = gda_server_operation_get_value_at (op, "/INDEX_DEF_P/INDEX_TABLESPACE");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value)) {
-		g_string_append (string, " TABLESPACE ");
-		g_string_append (string, g_value_get_string (value));
-	}
-
-	value = gda_server_operation_get_value_at (op, "/INDEX_DEF_P/INDEX_PREDICATE");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value)) {
-		g_string_append (string, " WHERE ");
-		g_string_append (string, g_value_get_string (value));
-	}
-
-	sql = string->str;
-	g_string_free (string, FALSE);
-
-	return sql;
-}
-
-gchar *
-gda_postgres_render_DROP_INDEX   (GdaServerProvider *provider, GdaConnection *cnc, 
-				  GdaServerOperation *op, GError **error)
-{
-	GString *string;
-	const GValue *value;
-	gchar *sql = NULL;
-
-	string = g_string_new ("DROP INDEX ");
-
-	value = gda_server_operation_get_value_at (op, "/INDEX_DESC_P/INDEX_NAME");
-	g_assert (value && G_VALUE_HOLDS (value, G_TYPE_STRING));
-	g_string_append (string, g_value_get_string (value));
-
-	value = gda_server_operation_get_value_at (op, "/INDEX_DESC_P/REFERENCED_ACTION");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) {
-		g_string_append_c (string, ' ');
-		g_string_append (string, g_value_get_string (value));
-	}
-
-	sql = string->str;
-	g_string_free (string, FALSE);
-
-	return sql;
-}
-
-gchar *
-gda_postgres_render_CREATE_VIEW (GdaServerProvider *provider, GdaConnection *cnc, 
-				 GdaServerOperation *op, GError **error)
-{
-	GString *string;
-	const GValue *value;
-	gboolean allok = TRUE;
-	gchar *sql = NULL;
-	GdaServerOperationNode *node;
-
-	string = g_string_new ("CREATE ");
-
-	value = gda_server_operation_get_value_at (op, "/VIEW_DEF_P/VIEW_OR_REPLACE");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
-		g_string_append (string, "OR REPLACE ");
-
-	value = gda_server_operation_get_value_at (op, "/VIEW_DEF_P/VIEW_TEMP");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
-		g_string_append (string, "TEMP ");
-
-	g_string_append (string, "VIEW ");
-		
-	value = gda_server_operation_get_value_at (op, "/VIEW_DEF_P/VIEW_NAME");
-	g_assert (value && G_VALUE_HOLDS (value, G_TYPE_STRING));
-	g_string_append (string, g_value_get_string (value));
-
-	node = gda_server_operation_get_node_info (op, "/FIELDS_A");
-	if (node) {
-		gint nrows;
-		gint i;
-		/* finding if there is a composed primary key */
-		nrows = gda_data_model_get_n_rows (node->model);
-		for (i = 0; (i < nrows) && allok; i++) {
-			if (i == 0)
-				g_string_append (string, " (");
-			value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_NAME/%d", i);
-			if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value)) {
-				if (i != 0) 
-					g_string_append (string, ", ");
-				
-				g_string_append_c (string, '`');
-				g_string_append (string, g_value_get_string (value));
-				g_string_append_c (string, '`');
-				g_string_append_c (string, ' ');
-			}
-			else {
-				g_set_error (error, 0, 0, _("Incorrect specified column name"));
-				allok = FALSE;
-			}
-		}
-		if (i > 0)
-			g_string_append (string, ")");
-	}
-	
-	if (allok) {
-		value = gda_server_operation_get_value_at (op, "/VIEW_DEF_P/VIEW_DEF");
-		g_assert (value && G_VALUE_HOLDS (value, G_TYPE_STRING));
-		g_string_append (string, " AS ");
-		g_string_append (string, g_value_get_string (value));
-	}
-
-	if (allok) {
-		sql = string->str;
-		g_string_free (string, FALSE);
-	}
-	else {
-		sql = NULL;
-		g_string_free (string, TRUE);
-	}
-
-	return sql;
-}
-	
-gchar *
-gda_postgres_render_DROP_VIEW (GdaServerProvider *provider, GdaConnection *cnc, 
-			       GdaServerOperation *op, GError **error)
-{
-	GString *string;
-	const GValue *value;
-	gchar *sql = NULL;
-
-	string = g_string_new ("DROP VIEW");
-
-	value = gda_server_operation_get_value_at (op, "/VIEW_DESC_P/VIEW_IFEXISTS");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
-		g_string_append (string, " IF EXISTS");
-
-	value = gda_server_operation_get_value_at (op, "/VIEW_DESC_P/VIEW_NAME");
-	g_assert (value && G_VALUE_HOLDS (value, G_TYPE_STRING));
-	g_string_append_c (string, ' ');
-	g_string_append (string, g_value_get_string (value));
-
-	value = gda_server_operation_get_value_at (op, "/TABLE_DESC_P/REFERENCED_ACTION");
-	if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) {
-		g_string_append_c (string, ' ');
-		g_string_append (string, g_value_get_string (value));
-	}
-
 	sql = string->str;
 	g_string_free (string, FALSE);
 

Modified: branches/V4-branch/providers/postgres/gda-postgres-ddl.h
==============================================================================
--- branches/V4-branch/providers/postgres/gda-postgres-ddl.h	(original)
+++ branches/V4-branch/providers/postgres/gda-postgres-ddl.h	Wed Feb 20 20:36:04 2008
@@ -1,8 +1,10 @@
-/* GDA Postgres Provider
- * Copyright (C) 2006 - 2008 The GNOME Foundation
+/* GDA postgres provider
+ * Copyright (C) 1998 - 2008 The GNOME Foundation.
  *
  * AUTHORS:
  *         Vivien Malerba <malerba gnome-db org>
+ *         Rodrigo Moya <rodrigo gnome-db org>
+ *         Gonzalo Paniagua Javier <gonzalo 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
@@ -26,29 +28,28 @@
 
 G_BEGIN_DECLS
 
-gchar *gda_postgres_render_CREATE_DB    (GdaServerProvider *provider, GdaConnection *cnc, 
-					 GdaServerOperation *op, GError **error);
-gchar *gda_postgres_render_DROP_DB      (GdaServerProvider *provider, GdaConnection *cnc, 
-					 GdaServerOperation *op, GError **error);
-gchar *gda_postgres_render_CREATE_TABLE (GdaServerProvider *provider, GdaConnection *cnc, 
-					 GdaServerOperation *op, GError **error);
-gchar *gda_postgres_render_RENAME_TABLE (GdaServerProvider *provider, GdaConnection *cnc, 
-					 GdaServerOperation *op, GError **error);
-gchar *gda_postgres_render_DROP_TABLE   (GdaServerProvider *provider, GdaConnection *cnc, 
-					 GdaServerOperation *op, GError **error);
-gchar *gda_postgres_render_ADD_COLUMN   (GdaServerProvider *provider, GdaConnection *cnc, 
-					 GdaServerOperation *op, GError **error);
-gchar *gda_postgres_render_DROP_COLUMN  (GdaServerProvider *provider, GdaConnection *cnc, 
-					 GdaServerOperation *op, GError **error);
-gchar *gda_postgres_render_CREATE_INDEX (GdaServerProvider *provider, GdaConnection *cnc, 
-					 GdaServerOperation *op, GError **error);
-gchar *gda_postgres_render_DROP_INDEX   (GdaServerProvider *provider, GdaConnection *cnc, 
-					 GdaServerOperation *op, GError **error);
-gchar *gda_postgres_render_CREATE_VIEW  (GdaServerProvider *provider, GdaConnection *cnc, 
-					 GdaServerOperation *op, GError **error);
-gchar *gda_postgres_render_DROP_VIEW    (GdaServerProvider *provider, GdaConnection *cnc, 
-					 GdaServerOperation *op, GError **error);
-
+gchar *gda_postgres_render_CREATE_DB    (GdaServerProvider *provider, GdaConnection *cnc,
+                                         GdaServerOperation *op, GError **error);
+gchar *gda_postgres_render_DROP_DB      (GdaServerProvider *provider, GdaConnection *cnc,
+                                         GdaServerOperation *op, GError **error);
+gchar *gda_postgres_render_CREATE_TABLE (GdaServerProvider *provider, GdaConnection *cnc,
+                                         GdaServerOperation *op, GError **error);
+gchar *gda_postgres_render_RENAME_TABLE (GdaServerProvider *provider, GdaConnection *cnc,
+                                         GdaServerOperation *op, GError **error);
+gchar *gda_postgres_render_DROP_TABLE   (GdaServerProvider *provider, GdaConnection *cnc,
+                                         GdaServerOperation *op, GError **error);
+gchar *gda_postgres_render_ADD_COLUMN   (GdaServerProvider *provider, GdaConnection *cnc,
+                                         GdaServerOperation *op, GError **error);
+gchar *gda_postgres_render_DROP_COLUMN  (GdaServerProvider *provider, GdaConnection *cnc,
+                                         GdaServerOperation *op, GError **error);
+gchar *gda_postgres_render_CREATE_INDEX (GdaServerProvider *provider, GdaConnection *cnc,
+                                         GdaServerOperation *op, GError **error);
+gchar *gda_postgres_render_DROP_INDEX   (GdaServerProvider *provider, GdaConnection *cnc,
+                                         GdaServerOperation *op, GError **error);
+gchar *gda_postgres_render_CREATE_VIEW  (GdaServerProvider *provider, GdaConnection *cnc,
+                                         GdaServerOperation *op, GError **error);
+gchar *gda_postgres_render_DROP_VIEW    (GdaServerProvider *provider, GdaConnection *cnc,
+                                         GdaServerOperation *op, GError **error);
 G_END_DECLS
 
 #endif

Modified: branches/V4-branch/providers/postgres/gda-postgres-handler-bin.c
==============================================================================
--- branches/V4-branch/providers/postgres/gda-postgres-handler-bin.c	(original)
+++ branches/V4-branch/providers/postgres/gda-postgres-handler-bin.c	Wed Feb 20 20:36:04 2008
@@ -1,6 +1,8 @@
-/* gda-postgres-handler-bin.c
+/* GDA postgres provider
+ * Copyright (C) 2007 - 2008 The GNOME Foundation.
  *
- * Copyright (C) 2007 Vivien Malerba
+ * 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
@@ -18,7 +20,7 @@
  */
 
 #include "gda-postgres-handler-bin.h"
-#include "gda-postgres-provider.h"
+#include "gda-postgres.h"
 #include <string.h>
 #include <glib/gi18n-lib.h>
 #include <libgda/gda-server-provider.h>
@@ -77,7 +79,7 @@
 			NULL
 		};
 
-		type = g_type_register_static (GDA_TYPE_OBJECT, "GdaPostgresHandlerBin", &info, 0);
+		type = g_type_register_static (G_TYPE_OBJECT, "GdaPostgresHandlerBin", &info, 0);
 		g_type_add_interface_static (type, GDA_TYPE_DATA_HANDLER, &data_entry_info);
 	}
 	return type;
@@ -119,8 +121,8 @@
 	hdl->priv->valid_g_types[0] = GDA_TYPE_BINARY;
 	hdl->priv->valid_g_types[1] = GDA_TYPE_BLOB;
 
-	gda_object_set_name (GDA_OBJECT (hdl), _("PostgresqlBin"));
-	gda_object_set_description (GDA_OBJECT (hdl), _("PostgreSQL binary representation"));
+	g_object_set_data (G_OBJECT (hdl), "name", _("PostgresqlBin"));
+	g_object_set_data (G_OBJECT (hdl), "descr", _("PostgreSQL binary representation"));
 }
 
 static void
@@ -134,8 +136,6 @@
 	hdl = GDA_POSTGRES_HANDLER_BIN (object);
 
 	if (hdl->priv) {
-		gda_object_destroy_check (GDA_OBJECT (object));
-
 		g_free (hdl->priv->valid_g_types);
 		hdl->priv->valid_g_types = NULL;
 
@@ -180,7 +180,7 @@
 {
 	gchar *retval;
 	GdaPostgresHandlerBin *hdl;
-	GdaPostgresConnectionData *priv_data = NULL;
+	PostgresConnectionData *cdata = NULL;
 
 	g_return_val_if_fail (iface && GDA_IS_POSTGRES_HANDLER_BIN (iface), NULL);
 	
@@ -190,11 +190,9 @@
 	if (hdl->priv->cnc) {
 		g_return_val_if_fail (GDA_IS_CONNECTION (hdl->priv->cnc), NULL);
 		
-		priv_data = g_object_get_data (G_OBJECT (hdl->priv->cnc), OBJECT_DATA_POSTGRES_HANDLE);
-		if (!priv_data) {
-			gda_connection_add_event_string (hdl->priv->cnc, _("Invalid PostgreSQL handle"));
-			return NULL;
-		}
+		cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (hdl->priv->cnc);
+		if (!cdata) 
+			return FALSE;
 	}
 
 	if (value) {
@@ -203,12 +201,13 @@
 			if (data) {
 				gchar *tmp;
 				size_t retlength;
-				if (0 && priv_data) {
+				if (0 && cdata) {
 					/* FIXME: use this call but it's only defined for Postgres >= 8.1 */
-					/*tmp = PQescapeByteaConn (priv_data->pconn, data, length, &retlength);*/
+					/*tmp = PQescapeByteaConn (cdata->pconn, data, length, &retlength);*/
 				}
 				else
-					tmp = PQescapeBytea (data->data, data->binary_length, &retlength);
+					tmp = (gchar *)PQescapeBytea (data->data, 
+								      data->binary_length, &retlength);
 			
 				if (tmp) {
 					retval = g_strdup_printf ("'%s'", tmp);
@@ -272,7 +271,7 @@
 				size_t retlength;
 				
 				str[i-1] = 0;
-				unstr = PQunescapeBytea (str+1, &retlength);
+				unstr = PQunescapeBytea ((guchar*) (str+1), &retlength);
 				if (unstr) {
 					value = gda_value_new_binary (unstr, retlength);
 					PQfreemem (unstr);
@@ -365,5 +364,5 @@
 	hdl = GDA_POSTGRES_HANDLER_BIN (iface);
 	g_return_val_if_fail (hdl->priv, NULL);
 
-	return gda_object_get_description (GDA_OBJECT (hdl));
+	return g_object_get_data (G_OBJECT (hdl), "descr");
 }

Modified: branches/V4-branch/providers/postgres/gda-postgres-handler-bin.h
==============================================================================
--- branches/V4-branch/providers/postgres/gda-postgres-handler-bin.h	(original)
+++ branches/V4-branch/providers/postgres/gda-postgres-handler-bin.h	Wed Feb 20 20:36:04 2008
@@ -1,6 +1,8 @@
-/* gda-postgres-handler-bin.h
+/* GDA postgres provider
+ * Copyright (C) 2007 - 2008 The GNOME Foundation.
  *
- * Copyright (C) 2007 Vivien Malerba
+ * 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
@@ -20,15 +22,14 @@
 #ifndef __GDA_POSTGRES_HANDLER_BIN__
 #define __GDA_POSTGRES_HANDLER_BIN__
 
-#include <libgda/gda-object.h>
 #include <libgda/gda-data-handler.h>
 
 G_BEGIN_DECLS
 
 #define GDA_TYPE_POSTGRES_HANDLER_BIN          (gda_postgres_handler_bin_get_type())
-#define GDA_POSTGRES_HANDLER_BIN(obj)          G_TYPE_CHECK_INSTANCE_CAST (obj, gda_postgres_handler_bin_get_type(), GdaPostgresHandlerBin)
-#define GDA_POSTGRES_HANDLER_BIN_CLASS(klass)  G_TYPE_CHECK_CLASS_CAST (klass, gda_postgres_handler_bin_get_type (), GdaPostgresHandlerBinClass)
-#define GDA_IS_POSTGRES_HANDLER_BIN(obj)       G_TYPE_CHECK_INSTANCE_TYPE (obj, gda_postgres_handler_bin_get_type ())
+#define GDA_POSTGRES_HANDLER_BIN(obj)          G_TYPE_CHECK_INSTANCE_CAST (obj, GDA_TYPE_POSTGRES_HANDLER_BIN, GdaPostgresHandlerBin)
+#define GDA_POSTGRES_HANDLER_BIN_CLASS(klass)  G_TYPE_CHECK_CLASS_CAST (klass, GDA_TYPE_POSTGRES_HANDLER_BIN, GdaPostgresHandlerBinClass)
+#define GDA_IS_POSTGRES_HANDLER_BIN(obj)       G_TYPE_CHECK_INSTANCE_TYPE (obj, GDA_TYPE_POSTGRES_HANDLER_BIN)
 
 
 typedef struct _GdaPostgresHandlerBin      GdaPostgresHandlerBin;
@@ -39,7 +40,7 @@
 /* struct for the object's data */
 struct _GdaPostgresHandlerBin
 {
-	GdaObject           object;
+	GObject                     object;
 
 	GdaPostgresHandlerBinPriv  *priv;
 };
@@ -47,7 +48,7 @@
 /* struct for the object's class */
 struct _GdaPostgresHandlerBinClass
 {
-	GdaObjectClass      parent_class;
+	GObjectClass                parent_class;
 };
 
 

Added: branches/V4-branch/providers/postgres/gda-postgres-meta.c
==============================================================================
--- (empty file)
+++ branches/V4-branch/providers/postgres/gda-postgres-meta.c	Wed Feb 20 20:36:04 2008
@@ -0,0 +1,267 @@
+/* GDA postgres provider
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *         Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include "gda-postgres.h"
+#include "gda-postgres-meta.h"
+#include "gda-postgres-provider.h"
+#include "gda-postgres-util.h"
+#include <libgda/gda-meta-store.h>
+#include <libgda/sql-parser/gda-sql-parser.h>
+#include <glib/gi18n-lib.h>
+#include <libgda/gda-server-provider-extra.h>
+#include <libgda/gda-connection-private.h>
+#include <libgda/gda-data-model-array.h>
+#include <libgda/gda-set.h>
+
+static gboolean append_a_row (GdaDataModel *to_model, GError **error, gint nb, ...);
+
+/*
+ * predefined statements' IDs
+ */
+typedef enum {
+        I_STMT_CATALOG,
+	I_STMT_BTYPES,
+	I_STMT_SCHEMATA
+} InternalStatementItem;
+
+
+/*
+ * predefined statements' SQL
+ */
+static gchar *internal_sql[] = {
+	"SELECT pg_catalog.current_database()",
+	"SELECT t.typname, 'pg_catalog.' || t.typname, 'gchararray', pg_catalog.obj_description(t.oid), NULL, CASE WHEN t.typname ~ '^_' THEN TRUE WHEN typtype = 'p' THEN TRUE WHEN t.typname in ('any', 'anyarray', 'anyelement', 'cid', 'cstring', 'int2vector', 'internal', 'language_handler', 'oidvector', 'opaque', 'record', 'refcursor', 'regclass', 'regoper', 'regoperator', 'regproc', 'regprocedure', 'regtype', 'SET', 'smgr', 'tid', 'trigger', 'unknown', 'void', 'xid', 'oid', 'aclitem') THEN TRUE ELSE FALSE END, CAST (t.oid AS int8) FROM pg_catalog.pg_type t, pg_catalog.pg_user u, pg_catalog.pg_namespace n WHERE t.typowner=u.usesysid AND n.oid = t.typnamespace AND pg_catalog.pg_type_is_visible(t.oid) AND (typtype='b' OR typtype='p')",
+	"SELECT catalog_name, schema_name, schema_owner, CASE WHEN schema_name ~'^pg_' THEN TRUE WHEN schema_name ='information_schema' THEN TRUE ELSE FALSE END FROM information_schema.schemata"
+};
+
+/*
+ * predefined statements' GdaStatement
+ */
+static GdaStatement **internal_stmt;
+static GdaSet        *internal_params;
+
+/* 
+ * global static values
+ */
+static GdaSqlParser *internal_parser = NULL;
+/* TO_ADD: other static values */
+
+
+/*
+ * Meta initialization
+ */
+void
+_gda_postgres_provider_meta_init (GdaServerProvider *provider)
+{
+	InternalStatementItem i;
+
+        internal_parser = gda_server_provider_internal_get_parser (provider);
+	internal_params = gda_set_new (NULL);
+
+        internal_stmt = g_new0 (GdaStatement *, sizeof (internal_sql) / sizeof (gchar*));
+        for (i = I_STMT_CATALOG; i < sizeof (internal_sql) / sizeof (gchar*); i++) {
+		GdaSet *set;
+                internal_stmt[i] = gda_sql_parser_parse_string (internal_parser, internal_sql[i], NULL, NULL);
+                if (!internal_stmt[i])
+                        g_error ("Could not parse internal statement: %s\n", internal_sql[i]);
+		g_assert (gda_statement_get_parameters (internal_stmt[i], &set, NULL));
+		if (set) {
+			gda_set_merge_with_set (internal_params, set);
+			g_object_unref (set);
+		}
+        }
+
+	/* initialize static values here */
+}
+
+gboolean
+_gda_postgres_meta_info (GdaServerProvider *prov, GdaConnection *cnc, 
+			 GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	GdaDataModel *model;
+	gboolean retval;
+
+	model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_CATALOG], NULL, error);
+	if (!model)
+		return FALSE;
+
+	retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
+	g_object_unref (model);
+
+	return retval;
+}
+
+gboolean
+_gda_postgres_meta_btypes (GdaServerProvider *prov, GdaConnection *cnc, 
+			   GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	GdaDataModel *model, *proxy;
+	gboolean retval = TRUE;
+	gint i, nrows;
+	PostgresConnectionData *cdata;
+
+	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata)
+		return FALSE;
+
+	/* use a prepared statement for the "base" model */
+	model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_BTYPES], NULL, error);
+	if (!model)
+		return FALSE;
+
+	/* use a proxy to customize @model */
+	proxy = (GdaDataModel*) gda_data_proxy_new (model);
+	gda_data_proxy_set_sample_size ((GdaDataProxy*) proxy, 0);
+	nrows = gda_data_model_get_n_rows (model);
+	for (i = 0; i < nrows; i++) {
+		const GValue *value;
+		GType type;
+		value = gda_data_model_get_value_at (model, 6, i);
+		
+		type = _gda_postgres_type_oid_to_gda (cdata, g_value_get_int64 (value));
+		if (type != G_TYPE_STRING) {
+			GValue *v;
+			g_value_set_string (v = gda_value_new (G_TYPE_STRING), g_type_name (type));
+			retval = gda_data_model_set_value_at (proxy, 2, i, v, error);
+			gda_value_free (v);
+			if (!retval)
+				break;
+		}
+	}
+
+	/* modify meta store with @proxy */
+	if (retval)
+		retval = gda_meta_store_modify (store, context->table_name, proxy, NULL, error, NULL);
+	g_object_unref (proxy);
+	g_object_unref (model);
+
+	return retval;
+}
+
+gboolean 
+_gda_postgres_meta_schemata (GdaServerProvider *prov, GdaConnection *cnc, 
+			     GdaMetaStore *store, GdaMetaContext *context, GError **error, 
+			     const GValue *schema_name)
+{
+	GdaDataModel *model;
+	gboolean retval;
+
+	model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_SCHEMATA], NULL, error);
+	if (!model)
+		return FALSE;
+
+	retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
+	g_object_unref (model);
+
+	return retval;
+}
+
+
+
+gboolean
+_gda_postgres_meta_tables_views (GdaServerProvider *prov, GdaConnection *cnc, 
+				 GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	GdaDataModel *model;
+	gboolean retval = TRUE;
+
+	model = gda_meta_store_create_modify_data_model (store, context->table_name);
+	g_assert (model);
+
+	/* fill in @model */
+	TO_IMPLEMENT;
+	if (retval)
+		retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
+	g_object_unref (model);
+
+	return retval;
+}
+
+
+
+gboolean 
+_gda_postgres_meta_tables_views_s (GdaServerProvider *prov, GdaConnection *cnc, 
+				   GdaMetaStore *store, GdaMetaContext *context, GError **error, 
+				   const GValue *table_schema, const GValue *table_name)
+{
+	GdaDataModel *model;
+	gboolean retval = TRUE;
+
+	model = gda_meta_store_create_modify_data_model (store, context->table_name);
+	g_assert (model);
+
+	/* fill in @model */
+	TO_IMPLEMENT;
+	if (retval)
+		retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
+	g_object_unref (model);
+
+	return retval;
+}
+
+gboolean
+_gda_postgres_meta_columns (GdaServerProvider *prov, GdaConnection *cnc, 
+			    GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	GdaDataModel *model;
+	gboolean retval = TRUE;
+
+	model = gda_meta_store_create_modify_data_model (store, context->table_name);
+	g_assert (model);
+
+	/* fill in @model */
+	TO_IMPLEMENT;
+	if (retval)
+		retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
+	g_object_unref (model);
+
+	return retval;
+}
+
+gboolean
+_gda_postgres_meta_columns_t (GdaServerProvider *prov, GdaConnection *cnc, 
+			      GdaMetaStore *store, GdaMetaContext *context, GError **error, 
+			      const GValue *table_schema, const GValue *table_name)
+{
+	return _gda_postgres_meta_columns_c (prov, cnc, store, context, error, table_schema, table_name, NULL);
+}
+
+gboolean
+_gda_postgres_meta_columns_c (GdaServerProvider *prov, GdaConnection *cnc, 
+			      GdaMetaStore *store, GdaMetaContext *context, GError **error, 
+			      const GValue *table_schema, const GValue *table_name, const GValue *column_name)
+{
+	GdaDataModel *model;
+	gboolean retval = TRUE;
+
+	model = gda_meta_store_create_modify_data_model (store, context->table_name);
+	g_assert (model);
+
+	/* fill in @model */
+	TO_IMPLEMENT;
+	if (retval)
+		retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
+	g_object_unref (model);
+
+	return retval;
+}

Added: branches/V4-branch/providers/postgres/gda-postgres-meta.h
==============================================================================
--- (empty file)
+++ branches/V4-branch/providers/postgres/gda-postgres-meta.h	Wed Feb 20 20:36:04 2008
@@ -0,0 +1,56 @@
+/* GDA postgres provider
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *         Vivien Malerba <malerba gnome-db org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __GDA_POSTGRES_META_H__
+#define __GDA_POSTGRES_META_H__
+
+#include <libgda/gda-server-provider.h>
+
+G_BEGIN_DECLS
+
+void     _gda_postgres_provider_meta_init (GdaServerProvider *provider);
+gboolean _gda_postgres_meta_info          (GdaServerProvider *prov, GdaConnection *cnc, 
+				       GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_postgres_meta_btypes        (GdaServerProvider *prov, GdaConnection *cnc, 
+				       GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_postgres_meta_schemata      (GdaServerProvider *prov, GdaConnection *cnc, 
+				       GdaMetaStore *store, GdaMetaContext *context, GError **error, 
+				       const GValue *schema_name);
+gboolean _gda_postgres_meta_tables_views  (GdaServerProvider *prov, GdaConnection *cnc, 
+				       GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_postgres_meta_tables_views_s(GdaServerProvider *prov, GdaConnection *cnc, 
+				       GdaMetaStore *store, GdaMetaContext *context, GError **error, 
+				       const GValue *table_schema, const GValue *table_name);
+gboolean _gda_postgres_meta_columns        (GdaServerProvider *prov, GdaConnection *cnc, 
+					GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_postgres_meta_columns_t      (GdaServerProvider *prov, GdaConnection *cnc, 
+					GdaMetaStore *store, GdaMetaContext *context, GError **error, 
+					const GValue *table_schema, const GValue *table_name);
+gboolean _gda_postgres_meta_columns_c      (GdaServerProvider *prov, GdaConnection *cnc, 
+					GdaMetaStore *store, GdaMetaContext *context, GError **error, 
+					const GValue *table_schema, const GValue *table_name, const GValue *column_name);
+
+/* TO_ADD: more functions as defined in GdaServerProviderMeta */
+
+G_END_DECLS
+
+#endif
+

Modified: branches/V4-branch/providers/postgres/gda-postgres-parser.c
==============================================================================
--- branches/V4-branch/providers/postgres/gda-postgres-parser.c	(original)
+++ branches/V4-branch/providers/postgres/gda-postgres-parser.c	Wed Feb 20 20:36:04 2008
@@ -1,6 +1,9 @@
-/* gda-postgres-parser.c
+/* GDA Postgres provider
  *
- * Copyright (C) 2007 Vivien Malerba
+ * Copyright (C) 2008 The GNOME Foundation
+ *
+ * AUTHORS:
+ *      TO_ADD: your name and email
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as

Modified: branches/V4-branch/providers/postgres/gda-postgres-parser.h
==============================================================================
--- branches/V4-branch/providers/postgres/gda-postgres-parser.h	(original)
+++ branches/V4-branch/providers/postgres/gda-postgres-parser.h	Wed Feb 20 20:36:04 2008
@@ -1,6 +1,9 @@
-/* gda-postgres-parser.h
+/* GDA Postgres provider
  *
- * Copyright (C) 2007 Vivien Malerba
+ * Copyright (C) 2008 The GNOME Foundation
+ *
+ * AUTHORS:
+ *      TO_ADD: your name and email
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -26,10 +29,11 @@
 
 G_BEGIN_DECLS
 
-#define GDA_TYPE_POSTGRES_PARSER          (gda_postgres_parser_get_type())
-#define GDA_POSTGRES_PARSER(obj)          G_TYPE_CHECK_INSTANCE_CAST (obj, gda_postgres_parser_get_type(), GdaPostgresParser)
-#define GDA_POSTGRES_PARSER_CLASS(klass)  G_TYPE_CHECK_CLASS_CAST (klass, gda_postgres_parser_get_type (), GdaPostgresParserClass)
-#define GDA_IS_POSTGRES_PARSER(obj)       G_TYPE_CHECK_INSTANCE_TYPE (obj, gda_postgres_parser_get_type ())
+#define GDA_TYPE_POSTGRES_PARSER            (gda_postgres_parser_get_type())
+#define GDA_POSTGRES_PARSER(obj)            (G_TYPE_CHECK_INSTANCE_CAST (obj, GDA_TYPE_POSTGRES_PARSER, GdaPostgresParser))
+#define GDA_POSTGRES_PARSER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST (klass, GDA_TYPE_POSTGRES_PARSER, GdaPostgresParserClass))
+#define GDA_IS_POSTGRES_PARSER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE (obj, GDA_TYPE_POSTGRES_PARSER))
+#define GDA_IS_POSTGRES_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDA_TYPE_POSTGRES_PARSER))
 
 typedef struct _GdaPostgresParser GdaPostgresParser;
 typedef struct _GdaPostgresParserClass GdaPostgresParserClass;
@@ -38,17 +42,17 @@
 /* struct for the object's data */
 struct _GdaPostgresParser
 {
-	GdaSqlParser              object;
+	GdaSqlParser          object;
 	GdaPostgresParserPrivate *priv;
 };
 
 /* struct for the object's class */
 struct _GdaPostgresParserClass
 {
-	GdaSqlParserClass         parent_class;
+	GdaSqlParserClass      parent_class;
 };
 
-GType               gda_postgres_parser_get_type               (void) G_GNUC_CONST;
+GType gda_postgres_parser_get_type (void) G_GNUC_CONST;
 
 G_END_DECLS
 

Modified: branches/V4-branch/providers/postgres/gda-postgres-provider.c
==============================================================================
--- branches/V4-branch/providers/postgres/gda-postgres-provider.c	(original)
+++ branches/V4-branch/providers/postgres/gda-postgres-provider.c	Wed Feb 20 20:36:04 2008
@@ -1,179 +1,148 @@
-/* GNOME DB Postgres Provider
- * Copyright (C) 1998 - 2008 The GNOME Foundation
+/* GDA postgres provider
+ * Copyright (C) 1998 - 2008 The GNOME Foundation.
  *
  * AUTHORS:
  *         Vivien Malerba <malerba gnome-db org>
  *         Rodrigo Moya <rodrigo gnome-db org>
  *         Gonzalo Paniagua Javier <gonzalo gnome-db org>
- *         Bas Driessen <bas driessen xobas com>
  *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * 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,
+ * 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; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 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 <stdio.h>
 #include <stdlib.h>
+#include <errno.h>
 #include <string.h>
-#include <sys/time.h>
-#include <libgda/gda-parameter-list.h>
-#include <libgda/gda-data-model-array.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <libgda/libgda.h>
 #include <libgda/gda-data-model-private.h>
 #include <libgda/gda-server-provider-extra.h>
-#include <libgda/gda-column-index.h>
-#include <libgda/gda-server-operation.h>
-#include <libgda/gda-query.h>
-#include <libgda/gda-util.h>
-#include <libgda/gda-renderer.h>
+#include <libgda/binreloc/gda-binreloc.h>
+#include <libgda/gda-statement-extra.h>
+#include <sql-parser/gda-sql-parser.h>
 #include "gda-postgres.h"
-#include "gda-postgres-parser.h"
 #include "gda-postgres-provider.h"
+#include "gda-postgres-handler-bin.h"
+#include "gda-postgres-recordset.h"
 #include "gda-postgres-ddl.h"
+#include "gda-postgres-meta.h"
+#include "gda-postgres-util.h"
 #include "gda-postgres-blob-op.h"
-#include "gda-postgres-handler-bin.h"
-#include <libpq/libpq-fs.h>
-
-#include <libgda/handlers/gda-handler-numerical.h>
-#include <libgda/handlers/gda-handler-boolean.h>
-#include <libgda/handlers/gda-handler-time.h>
-#include <libgda/handlers/gda-handler-string.h>
-#include <libgda/handlers/gda-handler-type.h>
-#include <libgda/handlers/gda-handler-bin.h>
+#include "gda-postgres-parser.h"
 
-#include <libgda/sql-delimiter/gda-sql-delimiter.h>
-#include <libgda/gda-connection-private.h>
-#include <libgda/binreloc/gda-binreloc.h>
+#define _GDA_PSTMT(x) ((GdaPStmt*)(x))
 
+/*
+ * GObject methods
+ */
 static void gda_postgres_provider_class_init (GdaPostgresProviderClass *klass);
 static void gda_postgres_provider_init       (GdaPostgresProvider *provider,
 					      GdaPostgresProviderClass *klass);
-static void gda_postgres_provider_finalize   (GObject *object);
+static GObjectClass *parent_class = NULL;
+
+/*
+ * GdaServerProvider's virtual methods
+ */
+/* connection management */
+static gboolean            gda_postgres_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
+								  GdaQuarkList *params, GdaQuarkList *auth,
+								  guint *task_id, GdaServerProviderAsyncCallback async_cb, gpointer cb_data);
+static gboolean            gda_postgres_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc);
+static const gchar        *gda_postgres_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc);
+static const gchar        *gda_postgres_provider_get_database (GdaServerProvider *provider, GdaConnection *cnc);
+
+/* DDL operations */
+static gboolean            gda_postgres_provider_supports_operation (GdaServerProvider *provider, GdaConnection *cnc,
+								     GdaServerOperationType type, GdaSet *options);
+static GdaServerOperation *gda_postgres_provider_create_operation (GdaServerProvider *provider, GdaConnection *cnc,
+								   GdaServerOperationType type,
+								   GdaSet *options, GError **error);
+static gchar              *gda_postgres_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc,
+								   GdaServerOperation *op, GError **error);
+
+static gboolean            gda_postgres_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
+								    GdaServerOperation *op, guint *task_id, 
+								    GdaServerProviderAsyncCallback async_cb, gpointer cb_data,
+								    GError **error);
+/* transactions */
+static gboolean            gda_postgres_provider_begin_transaction (GdaServerProvider *provider, GdaConnection *cnc,
+								    const gchar *name, GdaTransactionIsolation level, GError **error);
+static gboolean            gda_postgres_provider_commit_transaction (GdaServerProvider *provider, GdaConnection *cnc,
+								     const gchar *name, GError **error);
+static gboolean            gda_postgres_provider_rollback_transaction (GdaServerProvider *provider, GdaConnection * cnc,
+								       const gchar *name, GError **error);
+static gboolean            gda_postgres_provider_add_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
+								const gchar *name, GError **error);
+static gboolean            gda_postgres_provider_rollback_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
+								     const gchar *name, GError **error);
+static gboolean            gda_postgres_provider_delete_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
+								   const gchar *name, GError **error);
+
+/* information retreival */
+static const gchar        *gda_postgres_provider_get_version (GdaServerProvider *provider);
+static gboolean            gda_postgres_provider_supports_feature (GdaServerProvider *provider, GdaConnection *cnc,
+								   GdaConnectionFeature feature);
+
+static const gchar        *gda_postgres_provider_get_name (GdaServerProvider *provider);
+
+static GdaDataHandler     *gda_postgres_provider_get_data_handler (GdaServerProvider *provider, GdaConnection *cnc,
+								   GType g_type, const gchar *dbms_type);
+
+static const gchar*        gda_postgres_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConnection *cnc,
+									GType type);
+/* statements */
+static GdaSqlParser        *gda_postgres_provider_create_parser (GdaServerProvider *provider, GdaConnection *cnc);
+static gchar               *gda_postgres_provider_statement_to_sql  (GdaServerProvider *provider, GdaConnection *cnc,
+								     GdaStatement *stmt, GdaSet *params, 
+								     GdaStatementSqlFlag flags,
+								     GSList **params_used, GError **error);
+static gboolean             gda_postgres_provider_statement_prepare (GdaServerProvider *provider, GdaConnection *cnc,
+								     GdaStatement *stmt, GError **error);
+static GObject             *gda_postgres_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
+								     GdaStatement *stmt, GdaSet *params,
+								     GdaStatementModelUsage model_usage, 
+								     GType *col_types, GdaSet **last_inserted_row, 
+								     guint *task_id, GdaServerProviderAsyncCallback async_cb, 
+								     gpointer cb_data, GError **error);
 
-static const gchar *gda_postgres_provider_get_version (GdaServerProvider *provider);
-static gboolean gda_postgres_provider_open_connection (GdaServerProvider *provider,
-						       GdaConnection *cnc,
-						       GdaQuarkList *params,
-						       const gchar *username,
-						       const gchar *password);
-
-static gboolean gda_postgres_provider_close_connection (GdaServerProvider *provider,
-							GdaConnection *cnc);
-
-static const gchar *gda_postgres_provider_get_server_version (GdaServerProvider *provider,
-							      GdaConnection *cnc);
-
-static const gchar *gda_postgres_provider_get_database (GdaServerProvider *provider,
-							GdaConnection *cnc);
-
-static gboolean gda_postgres_provider_supports_operation (GdaServerProvider *provider, GdaConnection *cnc, 
-							  GdaServerOperationType type, GdaParameterList *options);
-static GdaServerOperation *gda_postgres_provider_create_operation (GdaServerProvider *provider, GdaConnection *cnc, 
-								   GdaServerOperationType type, 
-								   GdaParameterList *options, GError **error);
-static gchar *gda_postgres_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc, 
-						      GdaServerOperation *op, GError **error);
-static gboolean gda_postgres_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc, 
-							 GdaServerOperation *op, GError **error);
-
-static GList *gda_postgres_provider_execute_command (GdaServerProvider *provider,
-						     GdaConnection *cnc,
-						     GdaCommand *cmd,
-						     GdaParameterList *params);
-static GdaObject *gda_postgres_provider_execute_query (GdaServerProvider *provider,
-						       GdaConnection *cnc,
-						       GdaQuery *query,
-						       GdaParameterList *params);
-
-static gchar *gda_postgres_provider_get_last_insert_id (GdaServerProvider *provider,
-							GdaConnection *cnc,
-							GdaDataModel *recset);
-
-static gboolean gda_postgres_provider_begin_transaction (GdaServerProvider *provider,
-							 GdaConnection *cnc,
-							 const gchar *name, GdaTransactionIsolation level,
-							 GError **error);
-
-static gboolean gda_postgres_provider_commit_transaction (GdaServerProvider *provider,
-							  GdaConnection *cnc,
-							  const gchar *name, GError **error);
-
-static gboolean gda_postgres_provider_rollback_transaction (GdaServerProvider *provider,
-							    GdaConnection *cnc,
-							    const gchar *name, GError **error);
-
-static gboolean gda_postgres_provider_add_savepoint (GdaServerProvider *provider,
-						     GdaConnection *cnc,
-						     const gchar *name,
-						     GError **error);
-
-static gboolean gda_postgres_provider_rollback_savepoint (GdaServerProvider *provider,
-							  GdaConnection *cnc,
-							  const gchar *name,
-							  GError **error);
-
-static gboolean gda_postgres_provider_delete_savepoint (GdaServerProvider *provider,
-							GdaConnection *cnc,
-							const gchar *name,
-							GError **error);
-
-static gboolean gda_postgres_provider_single_command (const GdaPostgresProvider *provider,
-						      GdaConnection *cnc,
-						      const gchar *command);
-
-static gboolean gda_postgres_provider_supports (GdaServerProvider *provider,
-						GdaConnection *cnc,
-						GdaConnectionFeature feature);
-
-static GdaServerProviderInfo *gda_postgres_provider_get_info (GdaServerProvider *provider,
-							      GdaConnection *cnc);
-
-static GdaDataModel *gda_postgres_provider_get_schema (GdaServerProvider *provider,
-						       GdaConnection *cnc,
-						       GdaConnectionSchema schema,
-						       GdaParameterList *params);
-
-static GdaDataHandler *gda_postgres_provider_get_data_handler (GdaServerProvider *provider,
-							       GdaConnection *cnc,
-							       GType g_type,
-							       const gchar *dbms_type);
-static const gchar* gda_postgres_provider_get_default_dbms_type (GdaServerProvider *provider,
-								 GdaConnection *cnc,
-								 GType type);
-static gchar *gda_postgres_provider_escape_string (GdaServerProvider *provider, 
-						   GdaConnection *cnc, const gchar *str);
-static gchar *gda_postgres_provider_unescape_string (GdaServerProvider *provider, 
-						   GdaConnection *cnc, const gchar *str);
-
-static GdaSqlParser *gda_postgres_provider_create_parser (GdaServerProvider *provider, GdaConnection *cnc);
-				 		 
-typedef struct {
-	gint ncolumns;
-	gint *columns;
-	gboolean primary;
-	gboolean unique;
-} GdaPostgresIdxData;
+/* 
+ * private connection data destroy 
+ */
+static void gda_postgres_free_cnc_data (PostgresConnectionData *cdata);
 
-typedef enum {
-	IDX_PRIMARY,
-	IDX_UNIQUE
-} IdxType;
-
-typedef struct {
-	gchar *colname;  /* used for PG < 7.3 */
-	guint  colnum;   /* used for PG >= 7.3 */
-	gchar *reference;
-} GdaPostgresRefData;
 
-static GObjectClass *parent_class = NULL;
+/*
+ * Prepared internal statements
+ * TO_ADD: any prepared statement to be used internally by the provider should be
+ *         declared here, as constants and as SQL statements
+ */
+GdaStatement **internal_stmt;
+
+typedef enum {
+	I_STMT_BEGIN,
+	I_STMT_COMMIT,
+	I_STMT_ROLLBACK,
+} InternalStatementItem;
+
+gchar *internal_sql[] = {
+	"BEGIN",
+	"COMMIT",
+	"ROLLBACK"
+};
 
 /*
  * GdaPostgresProvider class implementation
@@ -181,67 +150,67 @@
 static void
 gda_postgres_provider_class_init (GdaPostgresProviderClass *klass)
 {
-	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 	GdaServerProviderClass *provider_class = GDA_SERVER_PROVIDER_CLASS (klass);
 
 	parent_class = g_type_class_peek_parent (klass);
 
-	object_class->finalize = gda_postgres_provider_finalize;
-
 	provider_class->get_version = gda_postgres_provider_get_version;
 	provider_class->get_server_version = gda_postgres_provider_get_server_version;
-	provider_class->get_info = gda_postgres_provider_get_info;
-	provider_class->supports_feature = gda_postgres_provider_supports;
-	provider_class->get_schema = gda_postgres_provider_get_schema;
+	provider_class->get_name = gda_postgres_provider_get_name;
+	provider_class->supports_feature = gda_postgres_provider_supports_feature;
 
 	provider_class->get_data_handler = gda_postgres_provider_get_data_handler;
-	provider_class->string_to_value = NULL;
 	provider_class->get_def_dbms_type = gda_postgres_provider_get_default_dbms_type;
-	provider_class->escape_string = gda_postgres_provider_escape_string;
-	provider_class->unescape_string = gda_postgres_provider_unescape_string;
 
 	provider_class->create_connection = NULL;
 	provider_class->open_connection = gda_postgres_provider_open_connection;
 	provider_class->close_connection = gda_postgres_provider_close_connection;
 	provider_class->get_database = gda_postgres_provider_get_database;
-	provider_class->change_database = NULL;
 
 	provider_class->supports_operation = gda_postgres_provider_supports_operation;
-	provider_class->create_operation = gda_postgres_provider_create_operation;
-	provider_class->render_operation = gda_postgres_provider_render_operation;
-	provider_class->perform_operation = gda_postgres_provider_perform_operation;
-
-	provider_class->execute_command = gda_postgres_provider_execute_command;
-	provider_class->execute_query = gda_postgres_provider_execute_query;
-	provider_class->get_last_insert_id = gda_postgres_provider_get_last_insert_id;
+        provider_class->create_operation = gda_postgres_provider_create_operation;
+        provider_class->render_operation = gda_postgres_provider_render_operation;
+        provider_class->perform_operation = gda_postgres_provider_perform_operation;
 
 	provider_class->begin_transaction = gda_postgres_provider_begin_transaction;
 	provider_class->commit_transaction = gda_postgres_provider_commit_transaction;
 	provider_class->rollback_transaction = gda_postgres_provider_rollback_transaction;
 	provider_class->add_savepoint = gda_postgres_provider_add_savepoint;
-	provider_class->rollback_savepoint = gda_postgres_provider_rollback_savepoint;
-	provider_class->delete_savepoint = gda_postgres_provider_delete_savepoint;
+        provider_class->rollback_savepoint = gda_postgres_provider_rollback_savepoint;
+        provider_class->delete_savepoint = gda_postgres_provider_delete_savepoint;
 
 	provider_class->create_parser = gda_postgres_provider_create_parser;
-        provider_class->statement_to_sql = NULL;
-        provider_class->statement_prepare = NULL;
-        provider_class->statement_execute = NULL;
+	provider_class->statement_to_sql = gda_postgres_provider_statement_to_sql;
+	provider_class->statement_prepare = gda_postgres_provider_statement_prepare;
+	provider_class->statement_execute = gda_postgres_provider_statement_execute;
+
+	memset (&(provider_class->meta_funcs), 0, sizeof (GdaServerProviderMeta));
+	provider_class->meta_funcs.info = _gda_postgres_meta_info;
+	provider_class->meta_funcs.btypes = _gda_postgres_meta_btypes;
+	provider_class->meta_funcs.schemata = _gda_postgres_meta_schemata;
+	provider_class->meta_funcs.tables_views = _gda_postgres_meta_tables_views;
+	provider_class->meta_funcs.tables_views_s = _gda_postgres_meta_tables_views_s;
+	provider_class->meta_funcs.columns = _gda_postgres_meta_columns;
+	provider_class->meta_funcs.columns_t = _gda_postgres_meta_columns_t;
+	provider_class->meta_funcs.columns_c = _gda_postgres_meta_columns_c;
 }
 
 static void
-gda_postgres_provider_init (GdaPostgresProvider *pg_prv, GdaPostgresProviderClass *klass)
+gda_postgres_provider_init (GdaPostgresProvider *postgres_prv, GdaPostgresProviderClass *klass)
 {
-}
+	InternalStatementItem i;
+	GdaSqlParser *parser;
 
-static void
-gda_postgres_provider_finalize (GObject *object)
-{
-	GdaPostgresProvider *pg_prv = (GdaPostgresProvider *) object;
+	parser = gda_server_provider_internal_get_parser ((GdaServerProvider*) postgres_prv);
+	internal_stmt = g_new0 (GdaStatement *, sizeof (internal_sql) / sizeof (gchar*));
+	for (i = I_STMT_BEGIN; i < sizeof (internal_sql) / sizeof (gchar*); i++) {
+		internal_stmt[i] = gda_sql_parser_parse_string (parser, internal_sql[i], NULL, NULL);
+		if (!internal_stmt[i]) 
+			g_error ("Could not parse internal statement: %s\n", internal_sql[i]);
+	}
 
-	g_return_if_fail (GDA_IS_POSTGRES_PROVIDER (pg_prv));
-	
-	/* chain to parent class */
-	parent_class->finalize(object);
+	/* meta data init */
+	_gda_postgres_provider_meta_init ((GdaServerProvider*) postgres_prv);
 }
 
 GType
@@ -260,21 +229,80 @@
 			0,
 			(GInstanceInitFunc) gda_postgres_provider_init
 		};
-		type = g_type_register_static (PARENT_TYPE,
-					       "GdaPostgresProvider",
+		type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, "GdaPostgresProvider",
 					       &info, 0);
 	}
 
 	return type;
 }
 
-GdaServerProvider *
-gda_postgres_provider_new (void)
+
+/*
+ * Get provider name request
+ */
+static const gchar *
+gda_postgres_provider_get_name (GdaServerProvider *provider)
+{
+	return POSTGRES_PROVIDER_NAME;
+}
+
+/* 
+ * Get provider's version, no need to change this
+ */
+static const gchar *
+gda_postgres_provider_get_version (GdaServerProvider *provider)
+{
+	return PACKAGE_VERSION;
+}
+
+/* get the float version of a Postgres version which looks like:
+ * PostgreSQL 7.2.2 on i686-pc-linux-gnu, compiled by GCC 2.96 => returns 7.22
+ * PostgreSQL 7.3 on i686-pc-linux-gnu, compiled by GCC 2.95.3 => returns 7.3
+ * WARNING: no serious test is made on the validity of the string
+ */
+static gfloat
+get_pg_version_float (const gchar *str)
+{
+        gfloat retval = 0.;
+        const gchar *ptr;
+        gfloat div = 1;
+
+        if (!str)
+                return retval;
+
+        /* go on  the first digit of version number */
+        ptr = str;
+        while (*ptr != ' ')
+                ptr++;
+        ptr++;
+
+        /* elaborate the real version number */
+        while (*ptr != ' ') {
+                if (*ptr != '.') {
+                        retval += (*ptr - '0')/div;
+                        div *= 10;
+                }
+                ptr++;
+        }
+
+        return retval;
+}
+
+static void
+pq_notice_processor (PostgresConnectionData *cdata, const char *message)
 {
-	GdaPostgresProvider *provider;
+        GdaConnectionEvent *error;
+
+        if (!message)
+                return;
+
+        error = gda_connection_event_new (GDA_CONNECTION_EVENT_NOTICE);
+        gda_connection_event_set_description (error, message);
+        gda_connection_event_set_code (error, -1);
+        gda_connection_event_set_source (error, gda_connection_get_provider_name (cdata->cnc));
+        gda_connection_event_set_sqlstate (error, "-1"); 
 
-	provider = g_object_new (gda_postgres_provider_get_type (), NULL);
-	return GDA_SERVER_PROVIDER (provider);
+        gda_connection_add_event (cdata->cnc, error);
 }
 
 static GType
@@ -338,7 +366,7 @@
 }
 
 static int
-get_connection_type_list (GdaPostgresConnectionData *priv_td)
+get_connection_type_list (PostgresConnectionData *cdata)
 {
 	GHashTable *h_table;
 	GdaPostgresTypeOid *td;
@@ -347,7 +375,7 @@
 	gchar *avoid_types = NULL;
 	GString *string;
 
-	if (priv_td->version_float < 7.3) {
+	if (cdata->version_float < 7.3) {
 		gchar *query;
 		avoid_types = "'SET', 'cid', 'oid', 'int2vector', 'oidvector', 'regproc', 'smgr', 'tid', 'unknown', 'xid'";
 		/* main query to fetch infos about the data types */
@@ -356,12 +384,12 @@
 					 "WHERE typowner=usesysid AND typrelid = 0 AND typname !~ '^_' "
 					 "AND  typname not in (%s) "
 					 "ORDER BY typname", avoid_types);
-		pg_res = gda_postgres_PQexec_wrap (priv_td->cnc, priv_td->pconn, query);
+		pg_res = _gda_postgres_PQexec_wrap (cdata->cnc, cdata->pconn, query);
 		g_free (query);
 
 		/* query to fetch non returned data types */
 		query = g_strdup_printf ("SELECT pg_type.oid FROM pg_type WHERE typname in (%s)", avoid_types);
-		pg_res_avoid = gda_postgres_PQexec_wrap (priv_td->cnc, priv_td->pconn, query);
+		pg_res_avoid = _gda_postgres_PQexec_wrap (cdata->cnc, cdata->pconn, query);
 		g_free (query);
 	}
 	else {
@@ -381,23 +409,23 @@
 			  "(SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "
 			  "AND t.typname not in (%s) "
 			  "ORDER BY typname", avoid_types);
-		pg_res = gda_postgres_PQexec_wrap (priv_td->cnc, priv_td->pconn, query);
+		pg_res = _gda_postgres_PQexec_wrap (cdata->cnc, cdata->pconn, query);
 		g_free (query);
 
 		/* query to fetch non returned data types */
 		query = g_strdup_printf ("SELECT t.oid FROM pg_catalog.pg_type t WHERE t.typname in (%s)",
 					 avoid_types);
-		pg_res_avoid = gda_postgres_PQexec_wrap (priv_td->cnc, priv_td->pconn, query);
+		pg_res_avoid = _gda_postgres_PQexec_wrap (cdata->cnc, cdata->pconn, query);
 		g_free (query);
 
 		/* query to fetch the oid of the 'any' data type */
-		pg_res_anyoid = gda_postgres_PQexec_wrap (priv_td->cnc, priv_td->pconn, 
-					"SELECT t.oid FROM pg_catalog.pg_type t WHERE t.typname = 'any'");
+		pg_res_anyoid = _gda_postgres_PQexec_wrap (cdata->cnc, cdata->pconn, 
+							   "SELECT t.oid FROM pg_catalog.pg_type t WHERE t.typname = 'any'");
 	}
 
 	if (!pg_res || (PQresultStatus (pg_res) != PGRES_TUPLES_OK) ||
 	    !pg_res_avoid || (PQresultStatus (pg_res_avoid) != PGRES_TUPLES_OK) ||
-	    ((priv_td->version_float >= 7.3) && 
+	    ((cdata->version_float >= 7.3) && 
 	     (!pg_res_anyoid || (PQresultStatus (pg_res_anyoid) != PGRES_TUPLES_OK)))) {
 		if (pg_res)
 			PQclear (pg_res);
@@ -425,9 +453,9 @@
 	}
 
 	PQclear (pg_res);
-	priv_td->ntypes = nrows;
-	priv_td->type_data = td;
-	priv_td->h_table = h_table;
+	cdata->ntypes = nrows;
+	cdata->type_data = td;
+	cdata->h_table = h_table;
 
 	/* Make a string of data types internal to postgres and not returned, for future queries */
 	string = NULL;
@@ -439,600 +467,478 @@
 			g_string_append_printf (string, ", %s", PQgetvalue (pg_res_avoid, i, 0));
 	}
 	PQclear (pg_res_avoid);
-	priv_td->avoid_types = avoid_types;
-	priv_td->avoid_types_oids = string->str;
+	cdata->avoid_types = avoid_types;
+	cdata->avoid_types_oids = string->str;
 	g_string_free (string, FALSE);
 
 	/* make a string of the oid of type 'any' */
-	priv_td->any_type_oid = "";
+	cdata->any_type_oid = "";
 	if (pg_res_anyoid) {
 		if (PQntuples (pg_res_anyoid) == 1) 
-			priv_td->any_type_oid = g_strdup (PQgetvalue (pg_res_anyoid, 0, 0));
+			cdata->any_type_oid = g_strdup (PQgetvalue (pg_res_anyoid, 0, 0));
 		PQclear (pg_res_anyoid);
 	}
 	return 0;
 }
 
-/* get_version handler for the GdaPostgresProvider class */
-static const gchar *
-gda_postgres_provider_get_version (GdaServerProvider *provider)
-{
-	GdaPostgresProvider *pg_prv = (GdaPostgresProvider *) provider;
-
-	g_return_val_if_fail (GDA_IS_POSTGRES_PROVIDER (pg_prv), NULL);
-	return PACKAGE_VERSION;
-}
-
-/* get the float version of a Postgres version which looks like:
- * PostgreSQL 7.2.2 on i686-pc-linux-gnu, compiled by GCC 2.96 => returns 7.22
- * PostgreSQL 7.3 on i686-pc-linux-gnu, compiled by GCC 2.95.3 => returns 7.3
- * WARNING: no serious test is made on the validity of the string
+/* 
+ * Open connection request
+ *
+ * In this function, the following _must_ be done:
+ *   - check for the presence and validify of the parameters required to actually open a connection,
+ *     using @params
+ *   - open the real connection to the database using the parameters previously checked
+ *   - create a PostgresConnectionData structure and associate it to @cnc
+ *
+ * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR gonnection event must be added to @cnc)
  */
-static gfloat 
-get_pg_version_float (const gchar *str)
-{
-	gfloat retval = 0.;
-	const gchar *ptr;
-	gfloat div = 1;
-
-	if (!str)
-		return retval;
-
-	/* go on  the first digit of version number */
-	ptr = str;
-	while (*ptr != ' ')
-		ptr++;
-	ptr++;
-	
-	/* elaborate the real version number */
-	while (*ptr != ' ') {
-		if (*ptr != '.') {
-			retval += (*ptr - '0')/div;
-			div *= 10;
-		}
-		ptr++;
-	}
-
-	return retval;
-}
-
-static void
-pq_notice_processor (GdaPostgresConnectionData *data, const char *message)
+static gboolean
+gda_postgres_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
+				       GdaQuarkList *params, GdaQuarkList *auth,
+				       guint *task_id, GdaServerProviderAsyncCallback async_cb, gpointer cb_data)
 {
-	GdaConnectionEvent *error;
-
-	if (!message)
-		return;
-
-        error = gda_connection_event_new (GDA_CONNECTION_EVENT_NOTICE);
-        gda_connection_event_set_description (error, message);
-        gda_connection_event_set_code (error, -1);
-        gda_connection_event_set_source (error, gda_connection_get_provider (data->cnc));
-        gda_connection_event_set_sqlstate (error, "-1");
+	g_return_val_if_fail (GDA_IS_POSTGRES_PROVIDER (provider), FALSE);
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
 
-        gda_connection_add_event (data->cnc, error);
-}
+	/* If asynchronous connection opening is not supported, then exit now */
+	if (async_cb) {
+		gda_connection_add_event_string (cnc, _("Provider does not support asynchronous connection open"));
+                return FALSE;
+	}
 
-/* open_connection handler for the GdaPostgresProvider class */
-static gboolean
-gda_postgres_provider_open_connection (GdaServerProvider *provider,
-				       GdaConnection *cnc,
-				       GdaQuarkList *params,
-				       const gchar *username,
-				       const gchar *password)
-{
+	/* Check for connection parameters */
+	/* TO_ADD: your own connection parameters */
 	const gchar *pq_host;
 	const gchar *pq_db;
-	const gchar *pg_searchpath;
-	const gchar *pq_port;
-	const gchar *pq_options;
-	const gchar *pq_tty;
-	const gchar *pq_user;
-	const gchar *pq_pwd;
-	const gchar *pq_hostaddr;
-	const gchar *pq_requiressl;
-	gchar *conn_string;
-	GdaPostgresConnectionData *priv_data;
-	PGconn *pconn;
-	PGresult *pg_res;
-	gchar *version;
-	gfloat version_float;
-
-	GdaPostgresProvider *pg_prv = (GdaPostgresProvider *) provider;
-
-	g_return_val_if_fail (GDA_IS_POSTGRES_PROVIDER (pg_prv), FALSE);
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
-
-	/* parse connection string */
+        const gchar *pg_searchpath;
+        const gchar *pq_port;
+        const gchar *pq_options;
+        const gchar *pq_tty;
+        const gchar *pq_user = NULL;
+        const gchar *pq_pwd = NULL;
+        const gchar *pq_hostaddr;
+        const gchar *pq_requiressl;
+        gchar *conn_string;
 	pq_host = gda_quark_list_find (params, "HOST");
-	pq_hostaddr = gda_quark_list_find (params, "HOSTADDR");
-	pq_db = gda_quark_list_find (params, "DB_NAME");
-	if (!pq_db) {
-		const gchar *str;
-
-		str = gda_quark_list_find (params, "DATABASE");
-		if (!str) {
-			gda_connection_add_event_string (cnc,
-							 _("The connection string must contain a DB_NAME value"));
-			return FALSE;
-		}
-		else {
-			g_warning (_("The connection string format has changed: replace DATABASE with "
-				     "DB_NAME and the same contents"));
-			pq_db = str;
-		}
-	}
-	pg_searchpath = gda_quark_list_find (params, "SEARCHPATH");
-	pq_port = gda_quark_list_find (params, "PORT");
-	pq_options = gda_quark_list_find (params, "OPTIONS");
-	pq_tty = gda_quark_list_find (params, "TTY");
-	if (!username || *username == '\0')
-		pq_user = gda_quark_list_find (params, "USER");
-	else
-		pq_user = username;
+        pq_hostaddr = gda_quark_list_find (params, "HOSTADDR");
+        pq_db = gda_quark_list_find (params, "DB_NAME");
+        if (!pq_db) {
+                const gchar *str;
+
+                str = gda_quark_list_find (params, "DATABASE");
+                if (!str) {
+                        gda_connection_add_event_string (cnc,
+                                                         _("The connection string must contain a DB_NAME value"));
+                        return FALSE;
+                }
+                else {
+                        g_warning (_("The connection string format has changed: replace DATABASE with "
+                                     "DB_NAME and the same contents"));
+                        pq_db = str;
+                }
+        }
+        pg_searchpath = gda_quark_list_find (params, "SEARCHPATH");
+        pq_port = gda_quark_list_find (params, "PORT");
+        pq_options = gda_quark_list_find (params, "OPTIONS");
+        pq_tty = gda_quark_list_find (params, "TTY");
+	pq_user = gda_quark_list_find (auth, "USERNAME");
+	if (!pq_user)
+		pq_user = gda_quark_list_find (params, "USERNAME");
 
-	if (!password || *password == '\0')
+	pq_pwd = gda_quark_list_find (auth, "PASSWORD");
+	if (!pq_pwd)
 		pq_pwd = gda_quark_list_find (params, "PASSWORD");
-	else
-		pq_pwd = password;
 
-	pq_requiressl = gda_quark_list_find (params, "USE_SSL");
+        pq_requiressl = gda_quark_list_find (params, "USE_SSL");
 
 	/* TODO: Escape single quotes and backslashes in the user name and password: */
-	conn_string = g_strconcat ("",
-				   /* host: */
-				   pq_host ? "host='" : "",
-				   pq_host ? pq_host : "",
-				   pq_host ? "'" : "",
-				   /* hostaddr: */
-				   pq_hostaddr ? " hostaddr=" : "",
-				   pq_hostaddr ? pq_hostaddr : "",
-				   /* db: */
-				   pq_db ? " dbname='" : "",
-				   pq_db ? pq_db : "",
-				   pq_db ? "'" : "",
-				   /* port: */
-				   pq_port ? " port=" : "",
-				   pq_port ? pq_port : "",
-				   /* options: */
-				   pq_options ? " options='" : "",
-				   pq_options ? pq_options : "",
-				   pq_options ? "'" : "",
-				   /* tty: */
-				   pq_tty ? " tty=" : "",
-				   pq_tty ? pq_tty : "",
-				   /* user: */
-				   (pq_user && *pq_user) ? " user='" : "",
-				   (pq_user && *pq_user)? pq_user : "",
-				   (pq_user && *pq_user)? "'" : "",
-				   /* password: */
-				   (pq_pwd && *pq_pwd) ? " password='" : "",
-				   (pq_pwd && *pq_pwd) ? pq_pwd : "",
-				   (pq_pwd && *pq_pwd) ? "'" : "",
-				   pq_requiressl ? " requiressl=" : "",
-				   pq_requiressl ? pq_requiressl : "",
-				   NULL);
-
-	/* actually establish the connection */
+        conn_string = g_strconcat ("",
+                                   /* host: */
+                                   pq_host ? "host='" : "",
+                                   pq_host ? pq_host : "",
+                                   pq_host ? "'" : "",
+                                   /* hostaddr: */
+                                   pq_hostaddr ? " hostaddr=" : "",
+                                   pq_hostaddr ? pq_hostaddr : "",
+                                   /* db: */
+                                   pq_db ? " dbname='" : "",
+                                   pq_db ? pq_db : "",
+                                   pq_db ? "'" : "",
+                                   /* port: */
+                                   pq_port ? " port=" : "",
+                                   pq_port ? pq_port : "",
+                                   /* options: */
+                                   pq_options ? " options='" : "",
+                                   pq_options ? pq_options : "",
+                                   pq_options ? "'" : "",
+                                   /* tty: */
+                                   pq_tty ? " tty=" : "",
+                                   pq_tty ? pq_tty : "",
+                                   /* user: */
+                                   (pq_user && *pq_user) ? " user='" : "",
+                                   (pq_user && *pq_user)? pq_user : "",
+                                   (pq_user && *pq_user)? "'" : "",
+                                   /* password: */
+                                   (pq_pwd && *pq_pwd) ? " password='" : "",
+                                   (pq_pwd && *pq_pwd) ? pq_pwd : "",
+                                   (pq_pwd && *pq_pwd) ? "'" : "",
+                                   pq_requiressl ? " requiressl=" : "",
+                                   pq_requiressl ? pq_requiressl : "",
+                                   NULL);
+	
+	/* open the real connection to the database */
+	PGconn *pconn;
 	pconn = PQconnectdb (conn_string);
-	g_free(conn_string);
+        g_free(conn_string);
+
+        if (PQstatus (pconn) != CONNECTION_OK) {
+                _gda_postgres_make_error (cnc, pconn, NULL, NULL);
+                PQfinish (pconn);
+                return FALSE;
+        }
+	
+	/* Create a new instance of the provider specific data associated to a connection (PostgresConnectionData),
+	 * and set its contents */
+	PostgresConnectionData *cdata;
+	cdata = g_new0 (PostgresConnectionData, 1);
+	cdata->cnc = cnc;
+        cdata->pconn = pconn;
 
-	if (PQstatus (pconn) != CONNECTION_OK) {
-		gda_postgres_make_error (cnc, pconn, NULL);
-		PQfinish (pconn);
+	/*
+         * Get the version as a float
+         */
+	PGresult *pg_res;
+        pg_res = _gda_postgres_PQexec_wrap (cnc, pconn, "SELECT version ()");
+	if (!pg_res) {
+		gda_postgres_free_cnc_data (cdata);
 		return FALSE;
 	}
+        cdata->version = g_strdup (PQgetvalue(pg_res, 0, 0));
+        cdata->version_float = get_pg_version_float (cdata->version);
+        PQclear (pg_res);
 
 	/*
-	 * Sets the DATE format for all the current session to YYYY-MM-DD
-	 */
-	pg_res = gda_postgres_PQexec_wrap (cnc, pconn, "SET DATESTYLE TO 'ISO'");
-	PQclear (pg_res);
+         * Sets the DATE format for all the current session to YYYY-MM-DD
+         */
+        pg_res = _gda_postgres_PQexec_wrap (cnc, pconn, "SET DATESTYLE TO 'ISO'");
+	if (!pg_res) {
+		gda_postgres_free_cnc_data (cdata);
+		return FALSE;
+	}
+        PQclear (pg_res);
 
-	/*
-	 * Unicode is the default character set now
-	 */
-	pg_res = gda_postgres_PQexec_wrap (cnc, pconn, "SET CLIENT_ENCODING TO 'UNICODE'");
-	PQclear (pg_res);
+        /*
+         * Unicode is the default character set now
+         */
+        pg_res = _gda_postgres_PQexec_wrap (cnc, pconn, "SET CLIENT_ENCODING TO 'UNICODE'");
+	if (!pg_res) {
+		gda_postgres_free_cnc_data (cdata);
+		return FALSE;
+	}
+        PQclear (pg_res);
 
 	/*
-	 * Get the version as a float
-	 */
-	pg_res = gda_postgres_PQexec_wrap (cnc, pconn, "SELECT version ()");
-	version = g_strdup (PQgetvalue(pg_res, 0, 0));
-	version_float = get_pg_version_float (PQgetvalue(pg_res, 0, 0));
-	PQclear (pg_res);
+         * Set the search_path
+         */
+        if ((cdata->version_float >= 7.3) && pg_searchpath) {
+                const gchar *ptr;
+                gboolean path_valid = TRUE;
+
+                ptr = pg_searchpath;
+                while (*ptr) {
+                        if (*ptr == ';')
+                                path_valid = FALSE;
+                        ptr++;
+                }
 
-	/*
-	 * Set the search_path
-	 */
-	if ((version_float >= 7.3) && pg_searchpath) {
-		const gchar *ptr;
-		gboolean path_valid = TRUE;
-
-		ptr = pg_searchpath;
-		while (*ptr) {
-			if (*ptr == ';')
-				path_valid = FALSE;
-			ptr++;
-		}
-		
-		if (path_valid) {
-			gchar *query = g_strdup_printf ("SET search_path TO %s", pg_searchpath);
-			pg_res = gda_postgres_PQexec_wrap (cnc, pconn, query);
-			g_free (query);
+                if (path_valid) {
+                        gchar *query = g_strdup_printf ("SET search_path TO %s", pg_searchpath);
+                        pg_res = _gda_postgres_PQexec_wrap (cnc, pconn, query);
+                        g_free (query);
+
+                        if (!pg_res || (PQresultStatus (pg_res) != PGRES_COMMAND_OK)) {
+                                gda_connection_add_event_string (cnc, _("Could not set search_path to %s"), pg_searchpath);
+                                PQclear (pg_res);
+				gda_postgres_free_cnc_data (cdata);
+                                return FALSE;
+                        }
+                        PQclear (pg_res);
+                }
+                else {
+			gda_connection_add_event_string (cnc, _("Search path %s is invalid)"), pg_searchpath);
+			gda_postgres_free_cnc_data (cdata);
+                        return FALSE;
+                }
+        }
+	
+	/* attach connection data */
+	gda_connection_internal_set_provider_data (cnc, cdata, (GDestroyNotify) gda_postgres_free_cnc_data);
 
-			if (!pg_res || (PQresultStatus (pg_res) != PGRES_COMMAND_OK)) {
-				g_warning ("Could not set search_path to %s\n", pg_searchpath);
-				PQclear (pg_res);
-				return FALSE;
-			}
-			PQclear (pg_res);
-		}
-		else {
-			g_warning ("Search path %s is invalid\n", pg_searchpath);
-			return FALSE;
-		}
-	}
 
-	/*
-	 * Associated data
-	 */
-	priv_data = g_new0 (GdaPostgresConnectionData, 1);
-	priv_data->cnc = cnc;
-	priv_data->pconn = pconn;
-	priv_data->version = version;
-	priv_data->version_float = version_float;
-	if (get_connection_type_list (priv_data) != 0) {
-		gda_postgres_make_error (cnc, pconn, NULL);
-		PQfinish (pconn);
-		g_free (priv_data);
-		return FALSE;
-	}
+	/* handle LibPQ's notices */
+        PQsetNoticeProcessor (pconn, (PQnoticeProcessor) pq_notice_processor, cdata);
 
-	g_object_set_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE, priv_data);
+        if (get_connection_type_list (cdata) != 0) {
+                _gda_postgres_make_error (cnc, pconn, NULL, NULL);
+		gda_postgres_free_cnc_data (cdata);
+                return FALSE;
+        }
 
-	/* handle LibPQ's notices */
-	PQsetNoticeProcessor (pconn, (PQnoticeProcessor) pq_notice_processor, priv_data);
-	
 	return TRUE;
 }
 
-/* close_connection handler for the GdaPostgresProvider class */
+/* 
+ * Close connection request
+ *
+ * In this function, the following _must_ be done:
+ *   - Actually close the connection to the database using @cnc's associated PostgresConnectionData structure
+ *   - Free the PostgresConnectionData structure and its contents
+ *
+ * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR gonnection event must be added to @cnc)
+ */
 static gboolean
 gda_postgres_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc)
 {
-	GdaPostgresConnectionData *priv_data;
-	gint i;
-
-	GdaPostgresProvider *pg_prv = (GdaPostgresProvider *) provider;
+	PostgresConnectionData *cdata;
 
-	g_return_val_if_fail (GDA_IS_POSTGRES_PROVIDER (pg_prv), FALSE);
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
 
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-	if (!priv_data)
+	/* Close the connection using the C API */
+	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
 		return FALSE;
 
-	PQfinish (priv_data->pconn);
-
-	for (i = 0; i < priv_data->ntypes; i++) {
-		g_free (priv_data->type_data[i].name);
-		g_free (priv_data->type_data[i].comments);
-		g_free (priv_data->type_data[i].owner);
-	}
-	
-	g_hash_table_destroy (priv_data->h_table);
-	g_free (priv_data->type_data);
-	g_free (priv_data->version);
-	g_free (priv_data->avoid_types_oids);
-	g_free (priv_data);
+	/* Free the PostgresConnectionData structure and its contents 
+	 * (will also actually close the connection to the server )*/
+	gda_postgres_free_cnc_data (cdata);
+	gda_connection_internal_set_provider_data (cnc, NULL, NULL);
 
-	g_object_set_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE, NULL);
 	return TRUE;
 }
 
-/* get_server_version handler for the GdaPostgresProvider class */
+/*
+ * Server version request
+ *
+ * Returns the server version as a string, which should be stored in @cnc's associated PostgresConnectionData structure
+ */
 static const gchar *
 gda_postgres_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc)
 {
-	GdaPostgresProvider *pg_prv = (GdaPostgresProvider *) provider;
-	GdaPostgresConnectionData *priv_data;
-
-	g_return_val_if_fail (GDA_IS_POSTGRES_PROVIDER (pg_prv), NULL);
-	if (cnc)
-		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-	else
-		return NULL;
-
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-	if (!priv_data) {
-		gda_connection_add_event_string (cnc, _("Invalid PostgreSQL handle"));
-		return NULL;
-	}
-
-	return priv_data->version;
-}
-
-static GdaObject *
-compute_retval_from_pg_res (GdaConnection *cnc, PGconn *pconn, const gchar *sql, PGresult *pg_res, const gchar *cursor_name)
-{
-	GdaConnectionEvent *error = NULL;
-	GdaObject *retval = NULL;
-
-	if (pg_res == NULL) 
-		error = gda_postgres_make_error (cnc, pconn, NULL);
-	else {
-		GdaPostgresConnectionData *priv_data;
-		gint status;
-
-		priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);		
-		status = PQresultStatus (pg_res);
-		
-		if (status == PGRES_EMPTY_QUERY ||
-		    status == PGRES_TUPLES_OK ||
-		    status == PGRES_COMMAND_OK) {
-			if ((status == PGRES_COMMAND_OK) && !cursor_name) {
-				gchar *str;
-				GdaConnectionEvent *event;
-				
-				event = gda_connection_event_new (GDA_CONNECTION_EVENT_NOTICE);
-				str = g_strdup (PQcmdStatus (pg_res));
-				gda_connection_event_set_description (event, str);
-				g_free (str);
-				gda_connection_add_event (cnc, event);
-				retval = (GdaObject *) gda_parameter_list_new_inline (NULL, 
-										      "IMPACTED_ROWS", G_TYPE_INT, 
-										      atoi (PQcmdTuples (pg_res)),
-										      NULL);
-				
-				if ((PQoidValue (pg_res) != InvalidOid))
-					priv_data->last_insert_id = PQoidValue (pg_res);
-				else
-					priv_data->last_insert_id = 0;
-
-				PQclear (pg_res);
-			}
-			else if ((status == PGRES_TUPLES_OK)  ||
-				 ((status == PGRES_COMMAND_OK) && cursor_name)) {
-				GdaDataModel *recset;
-
-				if (cursor_name) {
-					recset = gda_postgres_cursor_recordset_new (cnc, cursor_name, 
-										    priv_data->chunk_size);
-					PQclear (pg_res);
-				}
-				else
-					recset = gda_postgres_recordset_new (cnc, pg_res);
-
-				if (GDA_IS_DATA_MODEL (recset)) {
-					g_object_set (G_OBJECT (recset), 
-						      "command_text", sql,
-						      "command_type", GDA_COMMAND_TYPE_SQL, NULL);
-					
-					retval = (GdaObject *) recset;
-				}
-			}
-			else {
-				PQclear (pg_res);
-				retval = (GdaObject *) gda_data_model_array_new (0);	
-			}
-		}
-		else {
-			error = gda_postgres_make_error (cnc, pconn, pg_res);
-			PQclear (pg_res);
-		}
-	}
-	
-	gda_connection_internal_treat_sql (cnc, sql, error);
-	return retval;
-}
-
-static GList *
-process_sql_commands (GList *reclist, GdaConnection *cnc,
-		      const gchar *sql, GdaCommandOptions options)
-{
-	GdaPostgresConnectionData *priv_data;
-	PGconn *pconn;
-	gchar **arr;
-
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-	if (!priv_data) {
-		gda_connection_add_event_string (cnc, _("Invalid PostgreSQL handle"));
-		return NULL;
-	}
+	PostgresConnectionData *cdata;
 
-	pconn = priv_data->pconn;
-	/* parse SQL string, which can contain several commands, separated by ';' */
-	arr = gda_delimiter_split_sql (sql);
-	if (arr) {
-		gint n = 0;
-		gboolean allok = TRUE;
-
-		while (arr[n] && allok) {
-			PGresult *pg_res;
-			GdaObject *obj;
-			gchar *cursor_name = NULL;
-
-			if (priv_data->use_cursor && !strncasecmp (arr[n], "SELECT", 6)) {
-				gchar *str;
-				struct timeval stm;
-				static guint index = 0;
-
-				gettimeofday (&stm, NULL);				
-				cursor_name = g_strdup_printf ("gda_%d_%d_%d", stm.tv_sec, stm.tv_usec, index++);
-				str = g_strdup_printf ("DECLARE %s SCROLL CURSOR WITH HOLD FOR %s", 
-						       cursor_name, arr[n]);
-				pg_res = gda_postgres_PQexec_wrap (cnc, pconn, str);
-				g_free (str);
-			}
-			else 
-				pg_res = gda_postgres_PQexec_wrap (cnc, pconn, arr[n]);
-			obj = compute_retval_from_pg_res (cnc, pconn, arr[n], pg_res, cursor_name);
-			g_free (cursor_name);
-			reclist = g_list_append (reclist, obj);
-			if (!obj && !(options & GDA_COMMAND_OPTION_IGNORE_ERRORS))
-				allok = FALSE;
-			n++;
-		}
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+	g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, NULL);
 
-		g_strfreev (arr);
-	}
+	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
 
-	return reclist;
+	return cdata->version;
 }
 
-/* get_database handler for the GdaPostgresProvider class */
+/*
+ * Get database request
+ *
+ * Returns the server version as a string, which should be stored in @cnc's associated PostgresConnectionData structure
+ */
 static const gchar *
-gda_postgres_provider_get_database (GdaServerProvider *provider,
-				    GdaConnection *cnc)
+gda_postgres_provider_get_database (GdaServerProvider *provider, GdaConnection *cnc)
 {
-	GdaPostgresConnectionData *priv_data;
-	GdaPostgresProvider *pg_prv = (GdaPostgresProvider *) provider;
+	PostgresConnectionData *cdata;
 
-	g_return_val_if_fail (GDA_IS_POSTGRES_PROVIDER (pg_prv), NULL);
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+	g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, NULL);
 
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-	if (!priv_data) {
-		gda_connection_add_event_string (cnc, _("Invalid PostgreSQL handle"));
+	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
 		return NULL;
-	}
 
-	return (const char *) PQdb ((const PGconn *) priv_data->pconn);
+	return (const char *) PQdb ((const PGconn *) cdata->pconn);
 }
 
+/*
+ * Support operation request
+ *
+ * Tells what the implemented server operations are. To add support for an operation, the following steps are required:
+ *   - create a postgres_specs_....xml.in file describing the required and optional parameters for the operation
+ *   - add it to the Makefile.am
+ *   - make this method return TRUE for the operation type
+ *   - implement the gda_postgres_provider_render_operation() and gda_postgres_provider_perform_operation() methods
+ *
+ * In this example, the GDA_SERVER_OPERATION_CREATE_TABLE is implemented
+ */
 static gboolean
 gda_postgres_provider_supports_operation (GdaServerProvider *provider, GdaConnection *cnc,
-					  GdaServerOperationType type, GdaParameterList *options)
+					  GdaServerOperationType type, GdaSet *options)
 {
-	switch (type) {
-	case GDA_SERVER_OPERATION_CREATE_DB:
-	case GDA_SERVER_OPERATION_DROP_DB:
-
-	case GDA_SERVER_OPERATION_CREATE_TABLE:
-	case GDA_SERVER_OPERATION_DROP_TABLE:
-	case GDA_SERVER_OPERATION_RENAME_TABLE:
-
-	case GDA_SERVER_OPERATION_ADD_COLUMN:
-	case GDA_SERVER_OPERATION_DROP_COLUMN:
+	if (cnc) {
+		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+		g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
+	}
 
-	case GDA_SERVER_OPERATION_CREATE_INDEX:
-	case GDA_SERVER_OPERATION_DROP_INDEX:
+	switch (type) {
+        case GDA_SERVER_OPERATION_CREATE_DB:
+        case GDA_SERVER_OPERATION_DROP_DB:
 
-	case GDA_SERVER_OPERATION_CREATE_VIEW:
-	case GDA_SERVER_OPERATION_DROP_VIEW:
-		return TRUE;
-	default:
-		return FALSE;
-	}
+        case GDA_SERVER_OPERATION_CREATE_TABLE:
+        case GDA_SERVER_OPERATION_DROP_TABLE:
+        case GDA_SERVER_OPERATION_RENAME_TABLE:
+
+        case GDA_SERVER_OPERATION_ADD_COLUMN:
+        case GDA_SERVER_OPERATION_DROP_COLUMN:
+
+        case GDA_SERVER_OPERATION_CREATE_INDEX:
+        case GDA_SERVER_OPERATION_DROP_INDEX:
+
+        case GDA_SERVER_OPERATION_CREATE_VIEW:
+        case GDA_SERVER_OPERATION_DROP_VIEW:
+                return TRUE;
+        default:
+                return FALSE;
+        }
 }
 
+/*
+ * Create operation request
+ *
+ * Creates a #GdaServerOperation. The following code is generic and should only be changed
+ * if some further initialization is required, or if operation's contents is dependant on @cnc
+ */
 static GdaServerOperation *
-gda_postgres_provider_create_operation (GdaServerProvider *provider, GdaConnection *cnc, 
-					GdaServerOperationType type, 
-					GdaParameterList *options, GError **error)
+gda_postgres_provider_create_operation (GdaServerProvider *provider, GdaConnection *cnc,
+					GdaServerOperationType type, GdaSet *options, GError **error)
 {
-	gchar *file;
-	GdaServerOperation *op;
-	gchar *str;
+        gchar *file;
+        GdaServerOperation *op;
+        gchar *str;
 	gchar *dir;
-	
-	file = g_utf8_strdown (gda_server_operation_op_type_to_string (type), -1);
-	str = g_strdup_printf ("postgres_specs_%s.xml", file);
-	g_free (file);
+
+	if (cnc) {
+		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+		g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
+	}
+
+        file = g_utf8_strdown (gda_server_operation_op_type_to_string (type), -1);
+        str = g_strdup_printf ("postgres_specs_%s.xml", file);
+        g_free (file);
 
 	dir = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, NULL);
-	file = gda_server_provider_find_file (provider, dir, str);
+        file = gda_server_provider_find_file (provider, dir, str);
 	g_free (dir);
-	g_free (str);
+        g_free (str);
 
-	if (! file) {
-		g_set_error (error, 0, 0, _("Missing spec. file '%s'"), file);
-		return NULL;
-	}
+        if (! file) {
+                g_set_error (error, 0, 0, _("Missing spec. file '%s'"), file);
+                return NULL;
+        }
 
-	op = gda_server_operation_new (type, file);
-	g_free (file);
+        op = gda_server_operation_new (type, file);
+        g_free (file);
 
-	return op;
+        return op;
 }
 
+/*
+ * Render operation request
+ */
 static gchar *
-gda_postgres_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc, 
+gda_postgres_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc,
 					GdaServerOperation *op, GError **error)
 {
-	gchar *sql = NULL;
-	gchar *file;
-	gchar *str;
+        gchar *sql = NULL;
+        gchar *file;
+        gchar *str;
 	gchar *dir;
 
-	file = g_utf8_strdown (gda_server_operation_op_type_to_string (gda_server_operation_get_op_type (op)), -1);
-	str = g_strdup_printf ("postgres_specs_%s.xml", file);
-	g_free (file);
+	if (cnc) {
+		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+		g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
+	}
+
+	/* test @op's validity */
+        file = g_utf8_strdown (gda_server_operation_op_type_to_string (gda_server_operation_get_op_type (op)), -1);
+        str = g_strdup_printf ("postgres_specs_%s.xml", file);
+        g_free (file);
 
 	dir = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, NULL);
-	file = gda_server_provider_find_file (provider, dir, str);
+        file = gda_server_provider_find_file (provider, dir, str);
 	g_free (dir);
-	g_free (str);
-
-	if (! file) {
-		g_set_error (error, 0, 0, _("Missing spec. file '%s'"), file);
-		return NULL;
-	}
-	if (!gda_server_operation_is_valid (op, file, error)) {
-		g_free (file);
-		return NULL;
-	}
-	g_free (file);
+        g_free (str);
 
-	switch (gda_server_operation_get_op_type (op)) {
-	case GDA_SERVER_OPERATION_CREATE_DB:
-		sql = gda_postgres_render_CREATE_DB (provider, cnc, op, error);
-		break;
-	case GDA_SERVER_OPERATION_DROP_DB:
-		sql = gda_postgres_render_DROP_DB (provider, cnc, op, error);
-		break;
-	case GDA_SERVER_OPERATION_CREATE_TABLE:
-		sql = gda_postgres_render_CREATE_TABLE (provider, cnc, op, error);
-		break;
-	case GDA_SERVER_OPERATION_DROP_TABLE:
-		sql = gda_postgres_render_DROP_TABLE (provider, cnc, op, error);
-		break;
-	case GDA_SERVER_OPERATION_RENAME_TABLE:
-		sql = gda_postgres_render_RENAME_TABLE (provider, cnc, op, error);
-		break;
-	case GDA_SERVER_OPERATION_ADD_COLUMN:
-		sql = gda_postgres_render_ADD_COLUMN (provider, cnc, op, error);
-		break;
-	case GDA_SERVER_OPERATION_DROP_COLUMN:
-		sql = gda_postgres_render_DROP_COLUMN (provider, cnc, op, error);
-		break;
-	case GDA_SERVER_OPERATION_CREATE_INDEX:
-		sql = gda_postgres_render_CREATE_INDEX (provider, cnc, op, error);
-		break;
-	case GDA_SERVER_OPERATION_DROP_INDEX:
-		sql = gda_postgres_render_DROP_INDEX (provider, cnc, op, error);
-		break;
-	case GDA_SERVER_OPERATION_CREATE_VIEW:
-		sql = gda_postgres_render_CREATE_VIEW (provider, cnc, op, error);
-		break;
-	case GDA_SERVER_OPERATION_DROP_VIEW:
-		sql = gda_postgres_render_DROP_VIEW (provider, cnc, op, error);
-		break;
-	default:
-		g_assert_not_reached ();
-	}
-	return sql;
+        if (! file) {
+                g_set_error (error, 0, 0, _("Missing spec. file '%s'"), file);
+                return NULL;
+        }
+        if (!gda_server_operation_is_valid (op, file, error)) {
+                g_free (file);
+                return NULL;
+        }
+        g_free (file);
+
+	/* actual rendering */
+        switch (gda_server_operation_get_op_type (op)) {
+        case GDA_SERVER_OPERATION_CREATE_DB:
+                sql = gda_postgres_render_CREATE_DB (provider, cnc, op, error);
+                break;
+        case GDA_SERVER_OPERATION_DROP_DB:
+                sql = gda_postgres_render_DROP_DB (provider, cnc, op, error);
+                break;
+        case GDA_SERVER_OPERATION_CREATE_TABLE:
+                sql = gda_postgres_render_CREATE_TABLE (provider, cnc, op, error);
+                break;
+        case GDA_SERVER_OPERATION_DROP_TABLE:
+                sql = gda_postgres_render_DROP_TABLE (provider, cnc, op, error);
+                break;
+        case GDA_SERVER_OPERATION_RENAME_TABLE:
+                sql = gda_postgres_render_RENAME_TABLE (provider, cnc, op, error);
+                break;
+        case GDA_SERVER_OPERATION_ADD_COLUMN:
+                sql = gda_postgres_render_ADD_COLUMN (provider, cnc, op, error);
+                break;
+        case GDA_SERVER_OPERATION_DROP_COLUMN:
+                sql = gda_postgres_render_DROP_COLUMN (provider, cnc, op, error);
+                break;
+        case GDA_SERVER_OPERATION_CREATE_INDEX:
+                sql = gda_postgres_render_CREATE_INDEX (provider, cnc, op, error);
+                break;
+        case GDA_SERVER_OPERATION_DROP_INDEX:
+                sql = gda_postgres_render_DROP_INDEX (provider, cnc, op, error);
+                break;
+        case GDA_SERVER_OPERATION_CREATE_VIEW:
+                sql = gda_postgres_render_CREATE_VIEW (provider, cnc, op, error);
+                break;
+        case GDA_SERVER_OPERATION_DROP_VIEW:
+                sql = gda_postgres_render_DROP_VIEW (provider, cnc, op, error);
+                break;
+        default:
+                g_assert_not_reached ();
+        }
+        return sql;
 }
 
+/*
+ * Perform operation request
+ */
 static gboolean
-gda_postgres_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc, 
-					 GdaServerOperation *op, GError **error)
-{
-	GdaServerOperationType optype;
+gda_postgres_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
+					 GdaServerOperation *op, guint *task_id, 
+					 GdaServerProviderAsyncCallback async_cb, gpointer cb_data, GError **error)
+{
+        GdaServerOperationType optype;
+
+	/* If asynchronous connection opening is not supported, then exit now */
+	if (async_cb) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+			     _("Provider does not support asynchronous server operation"));
+                return FALSE;
+	}
 
-	optype = gda_server_operation_get_op_type (op);
+	if (cnc) {
+		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+		g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
+	}
+        optype = gda_server_operation_get_op_type (op);
 	if (!cnc && 
 	    ((optype == GDA_SERVER_OPERATION_CREATE_DB) ||
 	     (optype == GDA_SERVER_OPERATION_DROP_DB))) {
@@ -1040,7 +946,7 @@
 		PGconn *pconn;
 		PGresult *pg_res;
 		GString *string;
-
+		
 		const gchar *pq_host = NULL;
 		const gchar *pq_db = NULL;
 		gint         pq_port = -1;
@@ -1107,7 +1013,7 @@
 			sql = gda_server_provider_render_operation (provider, cnc, op, error);
 			if (!sql)
 				return FALSE;
-			pg_res = gda_postgres_PQexec_wrap (cnc, pconn, sql);
+			pg_res = _gda_postgres_PQexec_wrap (cnc, pconn, sql);
 			g_free (sql);
 			if (!pg_res || PQresultStatus (pg_res) != PGRES_COMMAND_OK) {
 				g_set_error (error, 0, 0, PQresultErrorMessage (pg_res));
@@ -1121,2226 +1027,929 @@
 	}
 	else {
 		/* use the SQL from the provider to perform the action */
-		gchar *sql;
-		GdaCommand *cmd;
-		
-		sql = gda_server_provider_render_operation (provider, cnc, op, error);
-		if (!sql)
-			return FALSE;
-		
-		cmd = gda_command_new (sql, GDA_COMMAND_TYPE_SQL, GDA_COMMAND_OPTION_STOP_ON_ERRORS);
-		g_free (sql);
-		if (gda_connection_execute_non_select_command (cnc, cmd, NULL, error) != -1) {
-			gda_command_free (cmd);
-			return TRUE;
-		}
-		else {
-			gda_command_free (cmd);
-			return FALSE;
-		}
+		return gda_server_provider_perform_operation_default (provider, cnc, op, error);
 	}
 }
 
-/* execute_command handler for the GdaPostgresProvider class */
-static GList *
-gda_postgres_provider_execute_command (GdaServerProvider *provider,
-				       GdaConnection *cnc,
-				       GdaCommand *cmd,
-				       GdaParameterList *params)
+/*
+ * Begin transaction request
+ */
+static gboolean
+gda_postgres_provider_begin_transaction (GdaServerProvider *provider, GdaConnection *cnc,
+					 const gchar *name, GdaTransactionIsolation level,
+					 GError **error)
 {
-	GList *reclist = NULL;
-	gchar *str;
-	GdaPostgresProvider *pg_prv = (GdaPostgresProvider *) provider;
-	GdaCommandOptions options;
-	gboolean prev_use_cursor;
-	gint prev_chunk_size;
-	GdaPostgresConnectionData *priv_data;
+	PostgresConnectionData *cdata;
 
-	g_return_val_if_fail (GDA_IS_POSTGRES_PROVIDER (pg_prv), NULL);
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-	g_return_val_if_fail (cmd != NULL, NULL);
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
 
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-	if (!priv_data) {
-		gda_connection_add_event_string (cnc, _("Invalid PostgreSQL handle"));
-		return NULL;
-	}
+	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
 
-	/* save previous settings */
-	prev_use_cursor = priv_data->use_cursor;
-	prev_chunk_size = priv_data->chunk_size;
-
-	if (params) {
-		GdaParameter *param;
-		param = gda_parameter_list_find_param (params, "ITER_MODEL_ONLY");
-		if (param) {
-			const GValue *value;
-
-			value = gda_parameter_get_value (param);
-			if (value) {
-				if (G_VALUE_TYPE (value) != G_TYPE_BOOLEAN)
-					g_warning (_("Parameter ITER_MODEL_ONLY should be a boolean, not a '%s'"),
-						   g_type_name (G_VALUE_TYPE (value)));
-				else
-					priv_data->use_cursor = g_value_get_boolean (value);
-			}
+	/* transaction's parameters */
+	gchar *write_option = NULL;
+        gchar *isolation_level = NULL;
+	GdaStatement *stmt = NULL;
+
+	if (cdata->version_float >= 6.5){
+                if (gda_connection_get_options (cnc) & GDA_CONNECTION_OPTIONS_READ_ONLY) {
+                        if (cdata->version_float >= 7.4)
+                                write_option = "READ ONLY";
+                        else {
+				g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_NON_SUPPORTED_ERROR,
+					     _("Transactions are not supported in read-only mode"));
+                                gda_connection_add_event_string (cnc, _("Transactions are not supported in read-only mode"));
+                                return FALSE;
+                        }
+                }
+                switch (level) {
+                case GDA_TRANSACTION_ISOLATION_READ_COMMITTED :
+                        isolation_level = g_strconcat ("SET TRANSACTION ISOLATION LEVEL READ COMMITTED ", write_option, NULL);
+                        break;
+                case GDA_TRANSACTION_ISOLATION_READ_UNCOMMITTED:
+			g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_NON_SUPPORTED_ERROR,
+				     _("Transactions are not supported in read uncommitted isolation level"));
+                        gda_connection_add_event_string (cnc, 
+							 _("Transactions are not supported in read uncommitted isolation level"));
+                        return FALSE;
+                case GDA_TRANSACTION_ISOLATION_REPEATABLE_READ:
+			g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_NON_SUPPORTED_ERROR,
+				     _("Transactions are not supported in repeatable read isolation level"));
+                        gda_connection_add_event_string (cnc, 
+							 _("Transactions are not supported in repeatable read isolation level"));
+                        return FALSE;
+                case GDA_TRANSACTION_ISOLATION_SERIALIZABLE :
+                        isolation_level = g_strconcat ("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE ", write_option, NULL);
+                        break;
+                default:
+                        isolation_level = NULL;
+                }
+        }
 
-			param = gda_parameter_list_find_param (params, "ITER_CHUNCK_SIZE");
-			if (param) {
-				value = gda_parameter_get_value (param);
-				if (value) {
-					if (G_VALUE_TYPE (value) != G_TYPE_INT)
-						g_warning (_("Parameter ITER_CHUNCK_SIZE should be a gint, not a '%s'"),
-							   g_type_name (G_VALUE_TYPE (value)));
-					else
-						priv_data->chunk_size = g_value_get_int (value);
-				}
-			}
+	if (isolation_level) {
+		GdaSqlParser *parser;
+		parser = gda_server_provider_internal_get_parser (provider);
+		stmt = gda_sql_parser_parse_string (parser, isolation_level, NULL, NULL);
+		g_free (isolation_level);
+		if (!stmt) {
+			g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_INTERNAL_ERROR,
+				     _("Internal error"));
+			return FALSE;
 		}
 	}
 
-	options = gda_command_get_options (cmd);
-	switch (gda_command_get_command_type (cmd)) {
-	case GDA_COMMAND_TYPE_SQL :
-		reclist = process_sql_commands (reclist, cnc, gda_command_get_text (cmd),
-						options);
-		break;
-	case GDA_COMMAND_TYPE_TABLE :
-		str = g_strdup_printf ("SELECT * FROM %s", gda_command_get_text (cmd));
-		reclist = process_sql_commands (reclist, cnc, str, options);
-		g_free (str);
-		break;
-	default:
-		break;
-	}
+	/* BEGIN statement */
+	if (gda_connection_statement_execute_non_select (cnc, internal_stmt [I_STMT_BEGIN], NULL, NULL, error) == -1)
+		return FALSE;
 
-	/* restore previous settings */
-	priv_data->use_cursor = prev_use_cursor;
-	priv_data->chunk_size = prev_chunk_size;
+	if (stmt) {
+		if (gda_connection_statement_execute_non_select (cnc, stmt, NULL, NULL, error) == -1) {
+			g_object_unref (stmt);
+			gda_postgres_provider_rollback_transaction (provider, cnc, name, NULL);
+			return FALSE;
+		}
+		g_object_unref (stmt);
+	}
 
-	return reclist;
+	return TRUE;
 }
 
-static PGresult *
-fetch_existing_blobs (GdaConnection *cnc, PGconn *pconn, GdaQuery *query, GdaParameterList *params)
+/*
+ * Commit transaction request
+ */
+static gboolean
+gda_postgres_provider_commit_transaction (GdaServerProvider *provider, GdaConnection *cnc,
+					  const gchar *name, GError **error)
 {
-	PGresult *pg_update_blobs = NULL;
-
-	if (gda_query_is_update_query (query) || gda_query_is_delete_query (query)) {
-		GSList *list;
-		GdaParameterList *plist = NULL;
-		GdaQuery *select = NULL;
+	PostgresConnectionData *cdata;
 
-		if ((gda_query_is_update_query (query) && 
-		     !gda_server_provider_blob_list_for_update (cnc, query, &select, NULL)) ||
-		    (gda_query_is_delete_query (query) &&
-		     !gda_server_provider_blob_list_for_delete (cnc, query, &select, NULL))) {
-			if (select)
-				g_object_unref (select);
-			gda_connection_add_event_string (cnc, _("Could not create a SELECT query to "
-								"fetch existing BLOB values"));
-			return NULL;
-		}
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
 
-		/* execute select query to get BLOB ids */
-		if (select) {
-			GError *error = NULL;
-			gchar *sql;
-			
-			plist = gda_query_get_parameter_list (select);
-			if (plist) {
-				for (list = plist->parameters; list; list = list->next) {
-					GdaParameter *param = GDA_PARAMETER (list->data);
-					GdaParameter *inc_param;
-					
-					inc_param = gda_parameter_list_find_param (params, 
-										   gda_object_get_name (GDA_OBJECT (param)));
-					if (!inc_param) {
-						/* missing parameter */
-						GdaConnectionEvent *event = NULL;
-						gchar *str;
-						str = g_strdup_printf (_("Missing parameter for '%s'"), 
-								       gda_object_get_name (GDA_OBJECT (param)));
-						event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
-						gda_connection_event_set_description (event, str);
-						gda_connection_add_event (cnc, event);
-						g_free (str);
-						return NULL;
-					}
-					else 
-						gda_parameter_set_value (param, gda_parameter_get_value (inc_param));
-				}
-			}
+	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
 
-			sql = gda_renderer_render_as_sql (GDA_RENDERER (select), plist, NULL, 0, &error);
-			if (plist)
-				g_object_unref (plist);
-			g_object_unref (select);
-			if (!sql || !*sql) {
-				gchar *msg = g_strdup_printf (_("Could not render SQL for SELECT "
-								"query to fetch existing BLOB values: %s"), 
-							      error && error->message ? 
-							      error->message : _("No detail"));
-				gda_connection_add_event_string (cnc, msg);
-				g_error_free (error);
-				g_free (msg);
-				return NULL;
-			}
-			pg_update_blobs = gda_postgres_PQexec_wrap (cnc, pconn, sql);
-			g_free (sql);
-			if (!pg_update_blobs || (PQresultStatus (pg_update_blobs) != PGRES_TUPLES_OK)) {
-				gda_postgres_make_error (cnc, pconn, pg_update_blobs);
-				return NULL;
-			}
-		}
-	}
+	/* COMMIT statement */
+	if (gda_connection_statement_execute_non_select (cnc, internal_stmt [I_STMT_COMMIT], NULL, NULL, error) == -1)
+		return FALSE;
 
-	return pg_update_blobs;
+	return TRUE;
 }
 
-static GdaObject *
-split_and_execute_update_query (GdaServerProvider *provider, GdaConnection *cnc, PGresult *pg_existing_blobs, 
-				GdaQuery *query, GdaParameterList *params)
+/*
+ * Rollback transaction request
+ */
+static gboolean
+gda_postgres_provider_rollback_transaction (GdaServerProvider *provider,
+					    GdaConnection *cnc,
+					    const gchar *name, GError **error)
 {
-	GdaQuery *nquery;
-	GError *error = NULL;
-	GdaParameterList *ret = NULL;
-	
-	if (!gda_server_provider_split_update_query (cnc, query, &nquery, &error)) {
-		GdaConnectionEvent *event;
-		event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
-		gda_connection_event_set_description (event, 
-						      error && error->message ? error->message : _("No detail"));
-		if (error)
-			g_error_free (error);
-	}
-	else {
-		/* add params to @params to allow the execution of the nquery query with 
-		 * parameters from pg_existing_blobs */
-		GdaParameterList *iter_params;
-		gint affected_rows = 0;
-		GSList *list;
-		gboolean allok = TRUE;
-			
-		iter_params = gda_query_get_parameter_list (nquery);
-		g_return_val_if_fail (iter_params, NULL);
-		for (list = params ? params->parameters : NULL; list; list = list->next) {
-			GdaParameter *inc_param;
-			inc_param = gda_parameter_list_find_param (iter_params, 
-								   gda_object_get_name (GDA_OBJECT (list->data)));
-			g_assert (inc_param);
-			gda_parameter_set_value (inc_param,
-						 gda_parameter_get_value (GDA_PARAMETER (list->data)));
-		}
-
-		/* run the new update query for each row in pg_existing_blobs */
-		gint row, col, nrows, ncols, npkfields, i;
-		nrows = PQntuples (pg_existing_blobs);
-		ncols = PQnfields (pg_existing_blobs);
-		npkfields = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (nquery), "_gda_nb_key_fields"));
-		for (row = 0; (row < nrows) && allok; row++) {
-			/* set some specific parameters for this run */
-			for (i = 0, col = ncols - npkfields; col < ncols; col++, i++) {
-				GdaParameter *param;
-				gchar *str;
-					
-				str = g_strdup_printf ("_prov_EXTRA%d", i);
-				param = gda_parameter_list_find_param (iter_params, str);
-				g_free (str);
-				g_assert (param);
-
-				gboolean isnull;
-				gchar *txtvalue = PQgetvalue (pg_existing_blobs, row, col);
-				GValue *value = g_new0 (GValue, 1);
-				isnull = *txtvalue != '\0' ? FALSE : PQgetisnull (pg_existing_blobs, row, col);
-				gda_postgres_set_value (cnc, value, 
-							gda_parameter_get_g_type (param), 
-							txtvalue, isnull, PQgetlength (pg_existing_blobs, row, col));
-				gda_parameter_set_value (param, value);
-				gda_value_free (value);
-			}
-			ret = (GdaParameterList*) gda_postgres_provider_execute_query (provider, cnc, nquery, iter_params);
-			if (ret) {
-				GdaParameter *param;
-				g_assert (GDA_IS_PARAMETER_LIST (ret));
-				param = gda_parameter_list_find_param (ret, "IMPACTED_ROWS");
-				if (param) 
-					affected_rows += g_value_get_int (gda_parameter_get_value (param));
-				g_object_unref (ret);
-			}
-			else
-				allok = FALSE;
-		}
-		if (allok) 
-			ret = gda_parameter_list_new_inline (gda_object_get_dict (GDA_OBJECT (nquery)),
-							     "IMPACTED_ROWS", G_TYPE_INT, affected_rows, NULL);
-		else
-			ret = NULL;
-		g_object_unref (nquery);
-	}
+	PostgresConnectionData *cdata;
 
-	return (GdaObject *) ret;
-}
-
-static GdaObject *
-gda_postgres_provider_execute_query (GdaServerProvider *provider,
-				     GdaConnection *cnc,
-				     GdaQuery *query,
-				     GdaParameterList *params)
-{
-	GSList *list;
-	GdaObject *retval = NULL;
-	gchar *pseudo_sql;
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
 
-	PGresult *pg_existing_blobs = NULL;
-	GdaPostgresProvider *pg_prv = (GdaPostgresProvider *) provider;
-	GdaPostgresConnectionData *priv_data;
-	PGconn *pconn;
-	PGresult *pg_res;
-	gchar *prep_stm_name;
-	gint nb_params = 0;
-	gboolean allok = TRUE;
-	GSList *used_params = NULL;
+	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
 
-	char **param_values = NULL;
-	int *param_lengths = NULL;
-	int *param_formats = NULL;
+	/* ROLLBACK statement */
+	if (gda_connection_statement_execute_non_select (cnc, internal_stmt [I_STMT_ROLLBACK], NULL, NULL, error) == -1)
+		return FALSE;
 
-	g_return_val_if_fail (GDA_IS_POSTGRES_PROVIDER (pg_prv), NULL);
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-	g_return_val_if_fail (GDA_IS_QUERY (query), NULL);
+	return TRUE;
+}
 
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-	if (!priv_data) {
-		gda_connection_add_event_string (cnc, _("Invalid PostgreSQL handle"));
-		return NULL;
-	}
-	pconn = priv_data->pconn;
-	
-#ifdef GDA_DEBUG_NO
-	pseudo_sql = gda_renderer_render_as_sql (GDA_RENDERER (query), params, NULL, GDA_RENDERER_PARAMS_AS_DETAILED , NULL);
-	g_print ("Execute_query: %s\n", pseudo_sql);
-	g_free (pseudo_sql);
-#endif
-
-	/* if the query is a SELECT, we need to start a transaction if the query returns BLOB fields */
-	if (gda_query_is_select_query (query) && 
-	    gda_server_provider_select_query_has_blobs (cnc, query, NULL))
-		if (!gda_postgres_check_transaction_started (cnc))
-			return NULL;
+/*
+ * Add savepoint request
+ */
+static gboolean
+gda_postgres_provider_add_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
+				     const gchar *name, GError **error)
+{
+	PostgresConnectionData *cdata;
 
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
 
-	/* if query is an update query, then create a SELECT query to be able to fetch blob references, if
-	 * there are any blob parameters */
-	pg_existing_blobs = fetch_existing_blobs (cnc, pconn, query, params);
-	if (pg_existing_blobs && (PQntuples (pg_existing_blobs) > 1) && gda_query_is_update_query (query)) {
-		/* As the UPDATE query concerns several rows, create several UPDATE queries 
-		 * with one row each, and fail if it can't be done */
-		retval = split_and_execute_update_query (provider, cnc, pg_existing_blobs, query, params);
-		PQclear (pg_existing_blobs);
-		return retval;
-	}
-
-	/* use or create a prepared statement */
-	prep_stm_name = NULL; /* FIXME: store a ref to that prepared statement, 
-				 which must be destroyed if @query changes */
-	if (!prep_stm_name) {
-		GError *error = NULL;
-		GdaConnectionEvent *event = NULL;
-
-		pseudo_sql = gda_renderer_render_as_sql (GDA_RENDERER (query), params, &used_params, 
-							 GDA_RENDERER_PARAMS_AS_DOLLAR, &error);
-		if (!pseudo_sql) {
-			event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
-			gda_connection_event_set_description (event, error && error->message ? 
-							      error->message : _("No detail"));
-			gda_connection_add_event (cnc, event);
-			g_error_free (error);
-		}
+	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
 
-		prep_stm_name = g_strdup_printf ("gda_query_prep_stm");
-		pg_res = PQprepare (pconn, prep_stm_name, pseudo_sql, 0, NULL);
-		if (!pg_res || (PQresultStatus (pg_res) != PGRES_COMMAND_OK))
-			event = gda_postgres_make_error (cnc, pconn, pg_res);
-		PQclear (pg_res);
+	/* Statement */
+	GdaStatement *stmt;
+	GdaSqlParser *parser;
+	gchar *str;
+	const gchar *remain;
 
-		if (event) 
-			return NULL;
-	}
+	parser = gda_server_provider_internal_get_parser (provider);
+	if (name)
+		str = g_strdup_printf ("SAVEPOINT %s", name);
+	else
+		str = (gchar *) name;
+	stmt = gda_sql_parser_parse_string (parser, str, &remain, NULL);
+	if (name)
+		g_free (str);
 
-	/* bind parameters to the prepared statement */
-	if (used_params) {
-		gint index, blob_index;
-		nb_params = g_slist_length (used_params);
-		param_values = g_new0 (char *, nb_params + 1);
-		param_lengths = g_new0 (int, nb_params + 1);
-		param_formats = g_new0 (int, nb_params + 1);
-		
-		for (index = 0, blob_index = 0, list = used_params; list && allok; list = list->next, index++) {
-			GdaParameter *param = GDA_PARAMETER (list->data);
-			const GValue *value;
-				
-			value = gda_parameter_get_value (param);
-			if (!value && gda_value_is_null (value))
-				param_values [index] = NULL;
-			else {
-				GType type = G_VALUE_TYPE (value);
-				if (type == GDA_TYPE_BLOB) {
-					/* specific BLOB treatment */
-					GdaBlob *blob = (GdaBlob*) gda_value_get_blob ((GValue *) value);
-					GdaPostgresBlobOp *op;
-					
-					/* Postgres requires that a transaction be started for LOB operations */
-					allok = gda_postgres_check_transaction_started (cnc);
-					if (!allok)
-						continue;
-					
-					/* create GdaBlobOp */
-					op = (GdaPostgresBlobOp *) gda_postgres_blob_op_new (cnc);
-					
-					/* always create a new blob as there is no way to truncate an existing blob */
-					if (gda_postgres_blob_op_declare_blob (op) &&
-					    gda_blob_op_write ((GdaBlobOp*) op, blob, 0)) 
-						param_values [index] = gda_postgres_blob_op_get_id (op);
-					else
-						param_values [index] = NULL;
-					g_object_unref (op);
-					blob_index++;
-				}
-				else if (type == GDA_TYPE_BINARY) {
-					/* directly bin binary data */
-					GdaBinary *bin = (GdaBinary *) gda_value_get_binary ((GValue *) value);
-					param_values [index] = bin->data;
-					param_lengths [index] = bin->binary_length;
-					param_formats [index] = 1; /* binary format */
-				}
-				else if ((type == G_TYPE_DATE) || (type == GDA_TYPE_TIMESTAMP) ||
-					 (type == GDA_TYPE_TIME)) {
-					GdaHandlerTime *timdh;
-
-					timdh = GDA_HANDLER_TIME (gda_server_provider_get_data_handler_gtype (provider, cnc, type));
-					g_assert (timdh);
-					param_values [index] = gda_handler_time_get_no_locale_str_from_value (timdh,
-													      value);
-				}
-				else {
-					GdaDataHandler *dh;
-					
-					dh = gda_server_provider_get_data_handler_gtype (provider, cnc, type);
-					if (dh) 
-						param_values [index] = gda_data_handler_get_str_from_value (dh, value);
-					else
-						param_values [index] = NULL;
-				}
-			}
-		}
-		g_slist_free (used_params);
+	if (!stmt) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_INTERNAL_ERROR,
+			     _("Internal error"));
+		return FALSE;
 	}
 
-	if (!allok) {
-		g_free (prep_stm_name);
-		gda_postgres_provider_single_command (pg_prv, cnc, "DEALLOCATE gda_query_prep_stm"); 
-		g_strfreev (param_values);
-		g_free (param_lengths);
-		g_free (param_formats);
-		if (pg_existing_blobs) 
-			PQclear (pg_existing_blobs);
-		return NULL;
+	if (remain) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_PREPARE_STMT_ERROR,
+			     _("Wrong savepoint name '%s'"), name);
+		g_object_unref (stmt);
+		return FALSE;
 	}
 
-	GdaConnectionEvent *event;
-	event = gda_connection_event_new (GDA_CONNECTION_EVENT_COMMAND);
-	gda_connection_event_set_description (event, pseudo_sql);
-	gda_connection_add_event (cnc, event);
-
-	pg_res = PQexecPrepared (pconn, prep_stm_name, nb_params, (const char * const *) param_values, 
-				 param_lengths, param_formats, 0);
-	g_free (prep_stm_name);
-	gda_postgres_provider_single_command (pg_prv, cnc, "DEALLOCATE gda_query_prep_stm"); 
-	g_strfreev (param_values);
-	g_free (param_lengths);
-	g_free (param_formats);
-	retval = compute_retval_from_pg_res (cnc, pconn, pseudo_sql, pg_res, NULL);
-
-	if (retval) {
-		if (pg_existing_blobs) {
-			/* delete the blobs from the existing blobs */
-			gint row, nrows, col, ncols;
-			nrows = PQntuples (pg_existing_blobs);
-			ncols = PQnfields (pg_existing_blobs);
-			for (row = 0; row < nrows; row++) {
-				for (col = 0; col < ncols; col++) {
-					if (PQftype (pg_existing_blobs, col) == 26 /*OIDOID*/) {
-						gchar *blobid = PQgetvalue (pg_existing_blobs, row, col);
-						if (atoi (blobid) != InvalidOid) {
-							/* add a savepoint to prevent a blob unlink 
-							   failure from rendering the transaction unuseable */
-							gda_connection_add_savepoint (cnc, 
-										      "__gda_blob_read_svp", 
-										      NULL);
-							if (lo_unlink (pconn, atoi (blobid)) !=  1)
-								gda_connection_rollback_savepoint (cnc, 
-								    "__gda_blob_read_svp", NULL);
-							else
-								gda_connection_delete_savepoint (cnc, 
-								    "__gda_blob_read_svp", NULL);	
-						}
-					}
-					else
-						ncols = col;
-				}
-			}
-			PQclear (pg_existing_blobs);
-		}
+	if (gda_connection_statement_execute_non_select (cnc, stmt, NULL, NULL, error) == -1) {
+		g_object_unref (stmt);
+		return FALSE;
 	}
 
-	return retval;
+	g_object_unref (stmt);
+	return TRUE;
 }
 
-static gchar *
-gda_postgres_provider_get_last_insert_id (GdaServerProvider *provider,
-					  GdaConnection *cnc,
-					  GdaDataModel *recset)
-{
-	Oid oid;
-	PGresult *pgres;
-	GdaPostgresConnectionData *priv_data;
-	GdaPostgresProvider *pg_prv = (GdaPostgresProvider *) provider;
+/*
+ * Rollback savepoint request
+ */
+static gboolean
+gda_postgres_provider_rollback_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
+					  const gchar *name, GError **error)
+{
+	PostgresConnectionData *cdata;
 
-	g_return_val_if_fail (GDA_IS_POSTGRES_PROVIDER (pg_prv), NULL);
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
 
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-	if (!priv_data) {
-		gda_connection_add_event_string (cnc, _("Invalid PostgreSQL handle"));
-		return NULL;
-	}
+	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
 
-	if (recset) {
-		g_return_val_if_fail (GDA_IS_POSTGRES_RECORDSET (recset), NULL);
-		/* get the PQresult from the recordset */
-		pgres = gda_postgres_recordset_get_pgresult (GDA_POSTGRES_RECORDSET (recset));
-		if (pgres) {
-			oid = PQoidValue (pgres);
-			if (oid != InvalidOid)
-				return g_strdup_printf ("%d", oid);
-		}
-		return NULL;
-	}
+	/* Statement */
+	GdaStatement *stmt;
+	GdaSqlParser *parser;
+	gchar *str;
+	const gchar *remain;
 
-	/* get the last inserted OID kept */
-	if (priv_data->last_insert_id)
-		return g_strdup_printf ("%d", priv_data->last_insert_id);
+	parser = gda_server_provider_internal_get_parser (provider);
+	if (name)
+		str = g_strdup_printf ("ROLLBACK TO SAVEPOINT %s", name);
 	else
-		return NULL;
-}
-
-static gboolean 
-gda_postgres_provider_begin_transaction (GdaServerProvider *provider,
-				         GdaConnection *cnc,
-					 const gchar *name, GdaTransactionIsolation level,
-					 GError **error)
-{
-        gboolean result;
-	GdaPostgresProvider *pg_prv = (GdaPostgresProvider *) provider;
-	GdaPostgresConnectionData *priv_data;
-
-	gchar * write_option=NULL;
-	gchar * isolation_level=NULL;
-
-	g_return_val_if_fail (GDA_IS_POSTGRES_PROVIDER (pg_prv), FALSE);
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+		str = (gchar *) name;
+	stmt = gda_sql_parser_parse_string (parser, str, &remain, NULL);
+	if (name)
+		g_free (str);
 
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-	if (priv_data->version_float >= 6.5){
-	        if (gda_connection_get_options (cnc) & GDA_CONNECTION_OPTIONS_READ_ONLY) {
-	                if (priv_data->version_float >= 7.4){
-		                write_option = "READ ONLY";
-           	        } 
-                        else {
-		                gda_connection_add_event_string (cnc, _("Transactions are not supported in read-only mode"));
-				return FALSE;
-			}
-		}
-		switch (level) {
-		case GDA_TRANSACTION_ISOLATION_READ_COMMITTED :
-		        isolation_level = g_strconcat ("SET TRANSACTION ISOLATION LEVEL READ COMMITTED ", write_option, NULL);
-		        break;
-		case GDA_TRANSACTION_ISOLATION_READ_UNCOMMITTED :
-		        gda_connection_add_event_string (cnc, _("Transactions are not supported in read uncommitted isolation level"));
-		        return FALSE;
-		case GDA_TRANSACTION_ISOLATION_REPEATABLE_READ :
-		        gda_connection_add_event_string (cnc, _("Transactions are not supported in repeatable read isolation level"));
-		        return FALSE;
-		case GDA_TRANSACTION_ISOLATION_SERIALIZABLE :
-		        isolation_level = g_strconcat ("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE ", write_option, NULL);
-		        break;
-		default: 
-		        isolation_level = NULL;
-		}
+	if (!stmt) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_INTERNAL_ERROR,
+			     _("Internal error"));
+		return FALSE;
 	}
 
-	result = gda_postgres_provider_single_command (pg_prv, cnc, "BEGIN"); 
-	if (result && isolation_level != NULL) {
-	        result = gda_postgres_provider_single_command (pg_prv, cnc, isolation_level) ;
-	} 
-	g_free(isolation_level);
-
-	return result;
-}
-
-static gboolean 
-gda_postgres_provider_commit_transaction (GdaServerProvider *provider,
-					  GdaConnection *cnc,
-					  const gchar *name, GError **error)
-{
-	GdaPostgresProvider *pg_prv = (GdaPostgresProvider *) provider;
+	if (remain) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_PREPARE_STMT_ERROR,
+			     _("Wrong savepoint name '%s'"), name);
+		g_object_unref (stmt);
+		return FALSE;
+	}
 
-	g_return_val_if_fail (GDA_IS_POSTGRES_PROVIDER (pg_prv), FALSE);
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	if (gda_connection_statement_execute_non_select (cnc, stmt, NULL, NULL, error) == -1) {
+		g_object_unref (stmt);
+		return FALSE;
+	}
 
-	return gda_postgres_provider_single_command (pg_prv, cnc, "COMMIT"); 
+	g_object_unref (stmt);
+	return TRUE;
 }
 
-static gboolean 
-gda_postgres_provider_rollback_transaction (GdaServerProvider *provider,
-					    GdaConnection *cnc,
-					    const gchar *name, GError **error)
+/*
+ * Delete savepoint request
+ */
+static gboolean
+gda_postgres_provider_delete_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
+					const gchar *name, GError **error)
 {
-	GdaPostgresProvider *pg_prv = (GdaPostgresProvider *) provider;
+	PostgresConnectionData *cdata;
 
-	g_return_val_if_fail (GDA_IS_POSTGRES_PROVIDER (pg_prv), FALSE);
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
 
-	return gda_postgres_provider_single_command (pg_prv, cnc, "ROLLBACK"); 
-}
+	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
 
-static gboolean
-gda_postgres_provider_add_savepoint (GdaServerProvider *provider,
-				     GdaConnection *cnc,
-				     const gchar *name,
-				     GError **error)
-{
-	GdaPostgresProvider *pg_prv = (GdaPostgresProvider *) provider;
+	/* Statement */
+	GdaStatement *stmt;
+	GdaSqlParser *parser;
 	gchar *str;
-	gboolean retval;
-
-	g_return_val_if_fail (GDA_IS_POSTGRES_PROVIDER (pg_prv), FALSE);
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	const gchar *remain;
 
-	str = g_strdup_printf ("SAVEPOINT %s", name);
-	retval = gda_postgres_provider_single_command (pg_prv, cnc, str); 
-	g_free (str);
-	return retval;
-}
+	parser = gda_server_provider_internal_get_parser (provider);
+	if (name)
+		str = g_strdup_printf ("DELETE SAVEPOINT %s", name);
+	else
+		str = (gchar *) name;
+	stmt = gda_sql_parser_parse_string (parser, str, &remain, NULL);
+	if (name)
+		g_free (str);
 
-static gboolean
-gda_postgres_provider_rollback_savepoint (GdaServerProvider *provider,
-					  GdaConnection *cnc,
-					  const gchar *name,
-					  GError **error)
-{
-	GdaPostgresProvider *pg_prv = (GdaPostgresProvider *) provider;
-	gchar *str;
-	gboolean retval;
+	if (!stmt) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_INTERNAL_ERROR,
+			     _("Internal error"));
+		return FALSE;
+	}
 
-	g_return_val_if_fail (GDA_IS_POSTGRES_PROVIDER (pg_prv), FALSE);
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	if (remain) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_PREPARE_STMT_ERROR,
+			     _("Wrong savepoint name '%s'"), name);
+		g_object_unref (stmt);
+		return FALSE;
+	}
 
-	str = g_strdup_printf ("ROLLBACK TO SAVEPOINT %s", name);
-	retval = gda_postgres_provider_single_command (pg_prv, cnc, str); 
-	g_free (str);
-	return retval;
+	if (gda_connection_statement_execute_non_select (cnc, stmt, NULL, NULL, error) == -1) {
+		g_object_unref (stmt);
+		return FALSE;
+	}
 
+	g_object_unref (stmt);
+	return TRUE;
 }
 
+/*
+ * Feature support request
+ */
 static gboolean
-gda_postgres_provider_delete_savepoint (GdaServerProvider *provider,
-					GdaConnection *cnc,
-					const gchar *name,
-					GError **error)
+gda_postgres_provider_supports_feature (GdaServerProvider *provider, GdaConnection *cnc, GdaConnectionFeature feature)
 {
-	GdaPostgresProvider *pg_prv = (GdaPostgresProvider *) provider;
-	gchar *str;
-	gboolean retval;
+	if (cnc) {
+		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+		g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
+	}
 
-	g_return_val_if_fail (GDA_IS_POSTGRES_PROVIDER (pg_prv), FALSE);
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	switch (feature) {
+        case GDA_CONNECTION_FEATURE_AGGREGATES:
+        case GDA_CONNECTION_FEATURE_INDEXES:
+        case GDA_CONNECTION_FEATURE_INHERITANCE:
+        case GDA_CONNECTION_FEATURE_PROCEDURES:
+        case GDA_CONNECTION_FEATURE_SEQUENCES:
+        case GDA_CONNECTION_FEATURE_SQL:
+        case GDA_CONNECTION_FEATURE_TRANSACTIONS:
+        case GDA_CONNECTION_FEATURE_SAVEPOINTS:
+        case GDA_CONNECTION_FEATURE_SAVEPOINTS_REMOVE:
+        case GDA_CONNECTION_FEATURE_TRIGGERS:
+        case GDA_CONNECTION_FEATURE_USERS:
+        case GDA_CONNECTION_FEATURE_VIEWS:
+        case GDA_CONNECTION_FEATURE_BLOBS:
+                return TRUE;
+        case GDA_CONNECTION_FEATURE_NAMESPACES:
+                if (cnc) {
+			PostgresConnectionData *cdata;
 
-	str = g_strdup_printf ("RELEASE SAVEPOINT %s", name);
-	retval = gda_postgres_provider_single_command (pg_prv, cnc, str); 
-	g_free (str);
-	return retval;
+			cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+			if (!cdata) 
+				return FALSE;
+                        if (cdata->version_float >= 7.3)
+                                return TRUE;
+                }
+                else
+                        return TRUE;
+        default:
+                break;
+        }
+
+        return FALSE;
 }
 
-static gboolean 
-gda_postgres_provider_single_command (const GdaPostgresProvider *provider,
-				      GdaConnection *cnc,
-				      const gchar *command)
+/*
+ * Get data handler request
+ *
+ * This method allows one to obtain a pointer to a #GdaDataHandler object specific to @type or @dbms_type (@dbms_type
+ * must be considered only if @type is not a valid GType).
+ *
+ * A data handler allows one to convert a value between its different representations which are a human readable string,
+ * an SQL representation and a GValue.
+ *
+ * The recommended method is to create GdaDataHandler objects only when they are needed and to keep a reference to them
+ * for further usage, using the gda_server_provider_handler_declare() method.
+ *
+ * The implementation shown here does not define any specific data handler, but there should be some for at least 
+ * binary and time related types.
+ */
+static GdaDataHandler *
+gda_postgres_provider_get_data_handler (GdaServerProvider *provider, GdaConnection *cnc,
+					GType type, const gchar *dbms_type)
 {
-	GdaPostgresConnectionData *priv_data;
-	PGconn *pconn;
-	PGresult *pg_res;
-	gboolean result;
-	GdaConnectionEvent *error = NULL;
-
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-	if (!priv_data) {
-		gda_connection_add_event_string (cnc, _("Invalid PostgreSQL handle"));
-		return FALSE;
+	GdaDataHandler *dh;
+	if (cnc) {
+		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+		g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
 	}
 
-	pconn = priv_data->pconn;
-	result = FALSE;
-	pg_res = gda_postgres_PQexec_wrap (cnc, pconn, command);
-	if (pg_res != NULL){		
-		result = PQresultStatus (pg_res) == PGRES_COMMAND_OK;
-		if (result == FALSE) 
-			error = gda_postgres_make_error (cnc, pconn, pg_res);
-
-		PQclear (pg_res);
+	if (type == G_TYPE_INVALID) {
+		TO_IMPLEMENT; /* use @dbms_type */
+		dh = NULL;
+	}
+	else if ((type == GDA_TYPE_BINARY) ||
+		 (type == GDA_TYPE_BLOB)) {
+		dh = gda_server_provider_handler_find (provider, cnc, type, NULL);
+                if (!dh) {
+                        dh = gda_postgres_handler_bin_new (cnc);
+                        if (dh) {
+                                gda_server_provider_handler_declare (provider, dh, cnc, GDA_TYPE_BINARY, NULL);
+                                gda_server_provider_handler_declare (provider, dh, cnc, GDA_TYPE_BLOB, NULL);
+                                g_object_unref (dh);
+                        }
+                }
+	}
+	else if ((type == GDA_TYPE_TIME) ||
+		 (type == GDA_TYPE_TIMESTAMP) ||
+		 (type == G_TYPE_DATE)) {
+		dh = gda_server_provider_handler_find (provider, NULL, type, NULL);
+                if (!dh) {
+                        dh = gda_handler_time_new ();
+                        gda_handler_time_set_sql_spec   ((GdaHandlerTime *) dh, G_DATE_YEAR,
+                                                         G_DATE_MONTH, G_DATE_DAY, '-', FALSE);
+                        gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_DATE, NULL);
+                        gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_TIME, NULL);
+                        gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_TIMESTAMP, NULL);
+                        g_object_unref (dh);
+                }
 	}
 	else
-		error = gda_postgres_make_error (cnc, pconn, NULL);
+		dh = gda_server_provider_get_data_handler_default (provider, cnc, type, dbms_type);
 
-	gda_connection_internal_treat_sql (cnc, command, error);
-
-	return result;
+	return dh;
 }
 
-static gboolean gda_postgres_provider_supports (GdaServerProvider *provider,
-						GdaConnection *cnc,
-						GdaConnectionFeature feature)
+/*
+ * Get default DBMS type request
+ *
+ * This method returns the "preferred" DBMS type for GType
+ */
+static const gchar*
+gda_postgres_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConnection *cnc, GType type)
 {
-	GdaPostgresProvider *pgprv = (GdaPostgresProvider *) provider;
-	GdaPostgresConnectionData *priv_data;
+	if (cnc) {
+		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+		g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
+	}
 
-	g_return_val_if_fail (GDA_IS_POSTGRES_PROVIDER (pgprv), FALSE);
-	if (cnc)
-		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);	
+	if (type == G_TYPE_INT64)
+                return "int8";
+        if (type == G_TYPE_UINT64)
+                return "int8";
+        if (type == GDA_TYPE_BINARY)
+                return "bytea";
+        if (type == GDA_TYPE_BLOB)
+                return "oid";
+        if (type == G_TYPE_BOOLEAN)
+                return "bool";
+        if (type == G_TYPE_DATE)
+                return "date";
+        if (type == G_TYPE_DOUBLE)
+                return "float8";
+        if (type == GDA_TYPE_GEOMETRIC_POINT)
+                return "point";
+        if (type == G_TYPE_OBJECT)
+                return "text";
+        if (type == G_TYPE_INT)
+                return "int4";
+        if (type == GDA_TYPE_LIST)
+                return "text";
+        if (type == GDA_TYPE_NUMERIC)
+                return "numeric";
+        if (type == G_TYPE_FLOAT)
+                return "float4";
+        if (type == GDA_TYPE_SHORT)
+                return "int2";
+        if (type == GDA_TYPE_USHORT)
+                return "int2";
+        if (type == G_TYPE_STRING)
+                return "varchar";
+        if (type == GDA_TYPE_TIME)
+                return "time";
+        if (type == GDA_TYPE_TIMESTAMP)
+                return "timestamp";
+        if (type == G_TYPE_CHAR)
+                return "smallint";
+        if (type == G_TYPE_UCHAR)
+                return "smallint";
+        if (type == G_TYPE_ULONG)
+                return "int8";
+        if (type == G_TYPE_UINT)
+                return "int4";
+        if (type == G_TYPE_INVALID)
+                return "text";
 
-	switch (feature) {
-	case GDA_CONNECTION_FEATURE_AGGREGATES:
-	case GDA_CONNECTION_FEATURE_INDEXES:
-	case GDA_CONNECTION_FEATURE_INHERITANCE:
-	case GDA_CONNECTION_FEATURE_PROCEDURES:
-	case GDA_CONNECTION_FEATURE_SEQUENCES:
-	case GDA_CONNECTION_FEATURE_SQL:
-	case GDA_CONNECTION_FEATURE_TRANSACTIONS:
-	case GDA_CONNECTION_FEATURE_SAVEPOINTS:
-	case GDA_CONNECTION_FEATURE_SAVEPOINTS_REMOVE:
-	case GDA_CONNECTION_FEATURE_TRIGGERS:
-	case GDA_CONNECTION_FEATURE_USERS:
-	case GDA_CONNECTION_FEATURE_VIEWS:
-	case GDA_CONNECTION_FEATURE_BLOBS:
-		return TRUE;
-	case GDA_CONNECTION_FEATURE_NAMESPACES:
-		if (cnc) {
-			g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
-			priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-			if (priv_data->version_float >= 7.3)
-				return TRUE;
-		}
-		else
-			return FALSE;
-	default:
-		break;
-	}
- 
-	return FALSE;
+        return "text";
 }
 
-static GdaServerProviderInfo *
-gda_postgres_provider_get_info (GdaServerProvider *provider, GdaConnection *cnc)
+/*
+ * Create parser request
+ *
+ * This method is responsible for creating a #GdaSqlParser object specific to the SQL dialect used
+ * by the database. See the PostgreSQL provider implementation for an example.
+ */
+static GdaSqlParser *
+gda_postgres_provider_create_parser (GdaServerProvider *provider, GdaConnection *cnc)
 {
-	static GdaServerProviderInfo info = {
-		"PostgreSQL",
-		TRUE, 
-		TRUE,
-		TRUE,
-		TRUE,
-		TRUE,
-		TRUE
-	};
-	
-	return &info;
+	return (GdaSqlParser*) g_object_new (GDA_TYPE_POSTGRES_PARSER, "tokenizer-flavour",
+                                             GDA_SQL_PARSER_FLAVOUR_POSTGRESQL, NULL);
 }
 
-static const GdaPostgresTypeOid *
-find_data_type_from_oid (GdaPostgresConnectionData *priv_data, const gchar *oid)
+/*
+ * GdaStatement to SQL request
+ * 
+ * This method renders a #GdaStatement into its SQL representation.
+ *
+ * The implementation show here simply calls gda_statement_to_sql_extended() but the rendering
+ * can be specialized to the database's SQL dialect, see the implementation of gda_statement_to_sql_extended()
+ * and SQLite's specialized rendering for more details
+ */
+static gchar *
+gda_postgres_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection *cnc,
+					GdaStatement *stmt, GdaSet *params, GdaStatementSqlFlag flags,
+					GSList **params_used, GError **error)
 {
-	GdaPostgresTypeOid *retval = NULL;
-	gint i = 0;
-
-	while ((i < priv_data->ntypes) && !retval) {
-		if (priv_data->type_data[i].oid == atoi (oid))
-			retval = &(priv_data->type_data[i]);
-		i++;
+	g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
+	if (cnc) {
+		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+		g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, NULL);
 	}
-	
-	return retval;
+
+	return gda_statement_to_sql_extended (stmt, cnc, params, flags, params_used, error);
 }
 
-static GList *
-gda_postgres_fill_procs_data (GdaDataModelArray *recset,
-			      GdaPostgresConnectionData *priv_data)
+/*
+ * Statement prepare request
+ *
+ * This methods "converts" @stmt into a prepared statement. A prepared statement is a notion
+ * specific in its implementation details to the C API used here. If successfull, it must create
+ * a new #GdaPostgresPStmt object and declare it to @cnc.
+ */
+static gboolean
+gda_postgres_provider_statement_prepare (GdaServerProvider *provider, GdaConnection *cnc,
+					 GdaStatement *stmt, GError **error)
 {
-	gchar *query;
-	PGresult *pg_res;
-	gint row_count, i;
-	GList *list = NULL;
+	GdaPostgresPStmt *ps;
+	PostgresConnectionData *cdata;
 
-	if (priv_data->version_float < 7.3) 
-		query = g_strdup_printf (
-                         "SELECT pg_proc.oid, proname, usename, obj_description (pg_proc.oid), typname, "
-			 "pronargs, proargtypes, prosrc "
-			 "FROM pg_proc, pg_user, pg_type "
-			 "WHERE pg_type.oid=prorettype AND usesysid=proowner AND "
-			 "pg_type.oid in (SELECT ty.oid FROM pg_type ty WHERE ty.typrelid = 0 AND "
-			 "ty.typname !~ '^_' AND  ty.oid not in (%s)) "
-			 "AND proretset = 'f' AND ((pronargs != 0 AND oidvectortypes (proargtypes)!= '') "
-			 "OR pronargs=0) "
-			 "ORDER BY proname, pronargs",
-			 priv_data->avoid_types_oids);
-	else
-		query = g_strdup_printf (
-                         "SELECT p.oid, p.proname, u.usename, pg_catalog.obj_description (p.oid), "
-			 "t.typname, p.pronargs, p.proargtypes, p.prosrc "
-			 "FROM pg_catalog.pg_proc p, pg_catalog.pg_user u, pg_catalog.pg_type t, "
-			 "pg_catalog.pg_namespace n "
-			 "WHERE t.oid=p.prorettype AND u.usesysid=p.proowner AND n.oid = p.pronamespace "
-			 "AND p.prorettype <> 'pg_catalog.cstring'::pg_catalog.regtype "
-			 "AND p.proargtypes[0] <> 'pg_catalog.cstring'::pg_catalog.regtype "
-			 "AND t.oid in (SELECT ty.oid FROM pg_catalog.pg_type ty WHERE ty.typrelid = 0 AND "
-			 "ty.typname !~ '^_' AND (ty.oid not in (%s) OR ty.oid = '%s')) "
-			 "AND p.proretset = 'f' "
-			 "AND NOT p.proisagg "
-			 "AND pg_catalog.pg_function_is_visible(p.oid) "
-			 "ORDER BY proname, pronargs",
-			 priv_data->avoid_types_oids, priv_data->any_type_oid);
-
-	pg_res = gda_postgres_PQexec_wrap (priv_data->cnc, priv_data->pconn, query);
-	g_free (query);
-	if (pg_res == NULL)
-		return NULL;
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
+	g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE);
 
-	row_count = PQntuples (pg_res);
-	for (i = 0; i < row_count; i++) {
-		GValue *value;
-		gchar *thevalue, *procname, *instr, *ptr;
-		GString *gstr;
-		gint nbargs, argcounter;
-		GList *rowlist = NULL;
-		gboolean insert = TRUE;
-
-		/* Proc name */
-		procname = thevalue = PQgetvalue(pg_res, i, 1);
-		g_value_set_string (value = gda_value_new (G_TYPE_STRING), thevalue);
-		rowlist = g_list_append (rowlist, value);
-
-		/* Proc_Id */
-		thevalue = PQgetvalue (pg_res, i, 0);
-		g_value_set_string (value = gda_value_new (G_TYPE_STRING), thevalue);
-		rowlist = g_list_append (rowlist, value);
-
-		/* Owner */
-		thevalue = PQgetvalue(pg_res, i, 2);
-		g_value_set_string (value = gda_value_new (G_TYPE_STRING), thevalue);
-		rowlist = g_list_append (rowlist, value);
-
-		/* Comments */ 
-		thevalue = PQgetvalue(pg_res, i, 3);
-		g_value_set_string (value = gda_value_new (G_TYPE_STRING), thevalue);
-		rowlist = g_list_append (rowlist, value);
-
-		/* Out type */ 
-		thevalue = PQgetvalue(pg_res, i, 4);
-		g_value_set_string (value = gda_value_new (G_TYPE_STRING), thevalue);
-		rowlist = g_list_append (rowlist, value);
-
-		/* Number of args */
-		thevalue = PQgetvalue(pg_res, i, 5);
-		nbargs = atoi (thevalue);
-		g_value_set_int (value = gda_value_new (G_TYPE_INT), nbargs);
-		rowlist = g_list_append (rowlist, value);
-
-		/* In types */
-		argcounter = 0;
-		gstr = NULL;
-		if (PQgetvalue(pg_res, i, 6)) {
-			instr = g_strdup (PQgetvalue(pg_res, i, 6));
-			ptr = strtok (instr, " ");
-			while (ptr && *ptr && insert) {
-				const GdaPostgresTypeOid *typeoid = NULL;
+	/* fetch prepares stmt if already done */
+	ps = gda_connection_get_prepared_statement (cnc, stmt);
+	if (ps)
+		return TRUE;
 
-				if (!strcmp (ptr, priv_data->any_type_oid)) {
-					thevalue = "-";
-				}
-				else {
-					typeoid = find_data_type_from_oid (priv_data, ptr);
-					if (typeoid) {
-						thevalue = typeoid->name;
-					}
-					else {
-						insert = FALSE;
-					}
-				}
+	/* get private connection data */
+	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
 
-				if (insert) {
-					if (!gstr) 
-						gstr = g_string_new (thevalue);
-					else
-						g_string_append_printf (gstr, ",%s", thevalue);
-				}
-					
-				ptr = strtok (NULL, " ");
-				argcounter ++;
-			}
-			g_free (instr);
-		}
-		else 
-			insert = FALSE;
+	/* render as SQL understood by PostgreSQL */
+	GdaSet *params = NULL;
+	gchar *sql;
+	GSList *used_params = NULL;
+	if (! gda_statement_get_parameters (stmt, &params, error))
+                return FALSE;
+        sql = gda_postgres_provider_statement_to_sql (provider, cnc, stmt, params, GDA_STATEMENT_SQL_PARAMS_AS_DOLLAR,
+						      &used_params, error);
+        if (!sql)
+                goto out_err;
 
-		if (gstr) {
-			g_value_take_string (value = gda_value_new (G_TYPE_STRING), gstr->str);
-			g_string_free (gstr, FALSE);
-		}
-		else
-			g_value_set_string (value = gda_value_new (G_TYPE_STRING), NULL);
-		rowlist = g_list_append (rowlist, value);
-		
-		if (argcounter != nbargs)
-			insert = FALSE;
-		
-		
-		
-		/* Definition */
-		thevalue = PQgetvalue(pg_res, i, 7);
-		if (!strcmp (thevalue, procname))
-			g_value_set_string (value = gda_value_new (G_TYPE_STRING), NULL);
-		else
-			g_value_set_string (value = gda_value_new (G_TYPE_STRING), thevalue);
-		rowlist = g_list_append (rowlist, value);
+	/* actually prepare statement */
+	PGresult *pg_res;
+	gchar *prep_stm_name;
+	GdaConnectionEvent *event = NULL;
 
-		if (insert)
-			list = g_list_append (list, rowlist);
-		else {
-			g_list_foreach (rowlist, (GFunc) gda_value_free, NULL);
-			g_list_free (rowlist);
-		}
-			
-		rowlist = NULL;
+	prep_stm_name = g_strdup_printf ("PS%p", stmt);
+	pg_res = PQprepare (cdata->pconn, prep_stm_name, sql, 0, NULL);
+	if (!pg_res || (PQresultStatus (pg_res) != PGRES_COMMAND_OK)) {
+		event = _gda_postgres_make_error (cnc, cdata->pconn, pg_res, error);
+		g_free (prep_stm_name);
+		if (pg_res)
+			PQclear (pg_res);
+		goto out_err;
 	}
-
 	PQclear (pg_res);
 
-	return list;
-}
-
-/* defined later */
-static void add_g_list_row (gpointer data, gpointer user_data);
-
-static GdaDataModel *
-get_postgres_procedures (GdaConnection *cnc, GdaParameterList *params)
-{
-	GList *list;
-	GdaPostgresConnectionData *priv_data;
-	GdaDataModelArray *recset;
-
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
+	/* make a list of the parameter names used in the statement */
+        GSList *param_ids = NULL;
+        if (used_params) {
+                GSList *list;
+                for (list = used_params; list; list = list->next) {
+                        const gchar *cid;
+                        cid = gda_holder_get_id (GDA_HOLDER (list->data));
+                        if (cid) {
+                                param_ids = g_slist_append (param_ids, g_strdup (cid));
+                                g_print ("PostgreSQL's PREPARATION: param ID: %s\n", cid);
+                        }
+                        else {
+                                g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_PREPARE_STMT_ERROR,
+                                             _("Unnammed parameter is not allowed in prepared statements"));
+                                g_slist_foreach (param_ids, (GFunc) g_free, NULL);
+                                g_slist_free (param_ids);
+                                goto out_err;
+                        }
+                }
+        }
 
-	recset = GDA_DATA_MODEL_ARRAY (gda_data_model_array_new 
-				       (gda_server_provider_get_schema_nb_columns (GDA_CONNECTION_SCHEMA_PROCEDURES)));
-	gda_server_provider_init_schema_model (GDA_DATA_MODEL (recset), GDA_CONNECTION_SCHEMA_PROCEDURES);
-	list = gda_postgres_fill_procs_data (recset, priv_data);
-	g_list_foreach (list, add_g_list_row, recset);
-	g_list_free (list);
-
-	return GDA_DATA_MODEL (recset);
-}
-
-static GdaDataModel *
-get_postgres_tables (GdaConnection *cnc, GdaParameterList *params)
-{
-	GList *reclist;
-	GdaPostgresConnectionData *priv_data;
-	GdaDataModel *recset;
-	GdaParameter *par = NULL;
-	const gchar *namespace = NULL;
-	const gchar *tablename = NULL;
+        /* create a prepared statement */
+        ps = gda_postgres_pstmt_new (cnc, cdata->pconn, prep_stm_name);
+	gda_pstmt_set_gda_statement (_GDA_PSTMT (ps), stmt);
+        _GDA_PSTMT (ps)->param_ids = param_ids;
+        _GDA_PSTMT (ps)->sql = sql;
 	
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-
-	if (params) {
-		par = gda_parameter_list_find_param (params, "namespace");
-		if (par)
-			namespace = g_value_get_string ((GValue *) gda_parameter_get_value (par));
-
-		par = gda_parameter_list_find_param (params, "name");
-		if (par)
-			tablename = g_value_get_string ((GValue *) gda_parameter_get_value (par));
-	}
-
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-	if (priv_data->version_float < 7.3) {
-		reclist = process_sql_commands (NULL, cnc,
-						"SELECT relname, usename, obj_description(pg_class.oid), NULL "
-						"FROM pg_class, pg_user "
-						"WHERE usesysid=relowner AND relkind = 'r' AND relname !~ '^pg_' "
-						"ORDER BY relname",
-						GDA_COMMAND_OPTION_STOP_ON_ERRORS);
-	}
-	else {
-		if (namespace) {
-			gchar *part = NULL;
-			gchar *query;
-
-			if (tablename)
-				part = g_strdup_printf ("AND c.relname = '%s' ", tablename);
-
-			query = g_strdup_printf ("SELECT c.relname, u.usename, pg_catalog.obj_description(c.oid), NULL "
-						 "FROM pg_catalog.pg_class c, pg_catalog.pg_user u, pg_catalog.pg_namespace n "
-						 "WHERE u.usesysid=c.relowner AND c.relkind = 'r' "
-						 "AND c.relnamespace=n.oid "
-						 "%s"
-						 "AND n.nspname ='%s' "
-						 "AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "
-						 "ORDER BY relname", part ? part : "", namespace);
-			if (part) g_free (part);
-			reclist = process_sql_commands (NULL, cnc,
-							query,
-							GDA_COMMAND_OPTION_STOP_ON_ERRORS);
-			g_free (query);
-		}
-		else {
-			gchar *part = NULL;
-			gchar *query;
-
-			if (tablename)
-				part = g_strdup_printf ("AND c.relname = '%s' ", tablename);
-
-			query = g_strdup_printf ("SELECT c.relname, u.usename, pg_catalog.obj_description(c.oid), NULL "
-						 "FROM pg_catalog.pg_class c, pg_catalog.pg_user u, pg_catalog.pg_namespace n "
-						 "WHERE u.usesysid=c.relowner AND c.relkind = 'r' "
-						 "AND c.relnamespace=n.oid "
-						 "%s"
-						 "AND pg_catalog.pg_table_is_visible (c.oid) "
-						 "AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "
-						 "ORDER BY relname", 
-						 part ? part : "");
-			if (part) g_free (part);
-			reclist = process_sql_commands (NULL, cnc,
-							query,
-							GDA_COMMAND_OPTION_STOP_ON_ERRORS);
-			g_free (query);
-		}
-	}
-
-	if (!reclist)
-		return NULL;
-
-	recset = GDA_DATA_MODEL (reclist->data);
-	g_list_free (reclist);
-
-	/* Set it here instead of the SQL query to allow i18n */
-	gda_server_provider_init_schema_model (recset, GDA_CONNECTION_SCHEMA_TABLES);
-
-	return recset;
-}
-
-static GdaDataModel *
-get_postgres_types (GdaConnection *cnc, GdaParameterList *params)
-{
-	GdaDataModelArray *recset;
-	GdaPostgresConnectionData *priv_data;
-	gint i;
-	static GHashTable *synonyms = NULL;
-
-	if (!synonyms) {
-		synonyms = g_hash_table_new (g_str_hash, g_str_equal);
-
-		g_hash_table_insert (synonyms, "int4", "int,integer");
-		g_hash_table_insert (synonyms, "int8", "bigint");
-		g_hash_table_insert (synonyms, "serial8", "bigserial");
-		g_hash_table_insert (synonyms, "varbit", "bit varying");
-		g_hash_table_insert (synonyms, "bool", "boolean");
-		g_hash_table_insert (synonyms, "varchar", "character varying");
-		g_hash_table_insert (synonyms, "char", "character");
-		g_hash_table_insert (synonyms, "float8", "double precision");
-		g_hash_table_insert (synonyms, "numeric", "decimal");
-		g_hash_table_insert (synonyms, "float4", "real");
-		g_hash_table_insert (synonyms, "int2", "smallint");
-		g_hash_table_insert (synonyms, "serial4", "serial");
-	}
-
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-
-	/* create the recordset */
-	recset = GDA_DATA_MODEL_ARRAY (gda_data_model_array_new 
-				       (gda_server_provider_get_schema_nb_columns (GDA_CONNECTION_SCHEMA_TYPES)));
-	gda_server_provider_init_schema_model (GDA_DATA_MODEL (recset), GDA_CONNECTION_SCHEMA_TYPES);
-
-	/* fill the recordset */
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-
-	for (i = 0; i < priv_data->ntypes; i++) {
-		GList *value_list = NULL;
-		gchar *syn;
-		GValue *tmpval;
-
-		g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), priv_data->type_data[i].name);
-		value_list = g_list_append (value_list, tmpval);
-
-		g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), priv_data->type_data[i].owner);
-		value_list = g_list_append (value_list, tmpval);
-
-		g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), priv_data->type_data[i].comments);
-		value_list = g_list_append (value_list, tmpval);
-
-		g_value_set_ulong (tmpval = gda_value_new (G_TYPE_ULONG), priv_data->type_data[i].type);
-		value_list = g_list_append (value_list, tmpval);
-
-		syn = g_hash_table_lookup (synonyms, priv_data->type_data[i].name);
-		g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), syn);
-		value_list = g_list_append (value_list, tmpval);
-
-		gda_data_model_append_values (GDA_DATA_MODEL (recset), value_list, NULL);
-
-		g_list_foreach (value_list, (GFunc) gda_value_free, NULL);
-		g_list_free (value_list);
-	}
+	gda_connection_add_prepared_statement (cnc, stmt, ps);
+	return TRUE;
 
-	return GDA_DATA_MODEL (recset);
+ out_err:
+	if (used_params)
+                g_slist_free (used_params);
+        if (params)
+                g_object_unref (params);
+	g_free (sql);
+	return FALSE;
 }
 
-static GdaDataModel *
-get_postgres_views (GdaConnection *cnc, GdaParameterList *params)
+static gboolean
+check_transaction_started (GdaConnection *cnc)
 {
-	GList *reclist;
-	GdaPostgresConnectionData *priv_data;
-	GdaDataModel *recset;
-
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-	if (priv_data->version_float < 7.3) 
-		reclist = process_sql_commands (
-			       NULL, cnc, 
-			       "SELECT relname, usename, obj_description(pg_class.oid), NULL "
-			       "FROM pg_class, pg_user "
-			       "WHERE usesysid=relowner AND relkind = 'v' AND relname !~ '^pg_' ORDER BY relname",
-			       GDA_COMMAND_OPTION_STOP_ON_ERRORS);
-	else
-		reclist = process_sql_commands (
-			       NULL, cnc, 
-			       "SELECT c.relname, u.usename, pg_catalog.obj_description(c.oid), "
-			       "pg_catalog.pg_get_viewdef (c.oid) "
-			       "FROM pg_catalog.pg_class c, pg_catalog.pg_user u, pg_catalog.pg_namespace n "
-			       "WHERE u.usesysid=c.relowner AND c.relkind = 'v' "
-			       "AND c.relnamespace=n.oid AND pg_catalog.pg_table_is_visible (c.oid) "
-			       "AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "
-			       "ORDER BY relname",
-			       GDA_COMMAND_OPTION_STOP_ON_ERRORS);
-
-	if (!reclist)
-		return NULL;
-
-	recset = GDA_DATA_MODEL (reclist->data);
-	g_list_free (reclist);
-
-	/* Set it here instead of the SQL query to allow i18n */
-	gda_server_provider_init_schema_model (recset, GDA_CONNECTION_SCHEMA_VIEWS);
-
-	return recset;
+        GdaTransactionStatus *trans;
+        trans = gda_connection_get_transaction_status (cnc);
+        if (!trans && !gda_connection_begin_transaction (cnc, NULL,
+							 GDA_TRANSACTION_ISOLATION_UNKNOWN, NULL))
+                return FALSE;
+        else
+                return TRUE;
 }
 
-static GdaDataModel *
-get_postgres_indexes (GdaConnection *cnc, GdaParameterList *params)
+/*
+ * Creates a "simple" prepared statement which has no variable, but does not call 
+ * gda_connection_add_prepared_statement()
+ */
+static GdaPostgresPStmt *
+prepare_stmt_simple (PostgresConnectionData *cdata, const gchar *sql, GError **error)
 {
-	GList *reclist;
-	GdaPostgresConnectionData *priv_data;
-	GdaDataModel *recset;
-
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-	if (priv_data->version_float < 7.3) 
-		reclist = process_sql_commands (NULL, cnc, 
-						"SELECT relname FROM pg_class WHERE relkind = 'i' AND "
-						"relname !~ '^pg_' ORDER BY relname",
-						GDA_COMMAND_OPTION_STOP_ON_ERRORS);
-	else
-		reclist = process_sql_commands (NULL, cnc, 
-						"SELECT c.relname "
-						"FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "
-						"WHERE relkind = 'i' "
-						"AND n.oid = c.relnamespace "
-						"AND pg_catalog.pg_table_is_visible(c.oid) "
-						"AND n.nspname NOT IN ('pg_catalog', 'pg_toast') "
-						"ORDER BY relname",
-						GDA_COMMAND_OPTION_STOP_ON_ERRORS);
+	static guint counter = 0; /* each prepared statement MUST have a unique name, ensured with this counter */
+	PGresult *pg_res;
+	gchar *prep_stm_name;
+	GdaConnectionEvent *event = NULL;
 
-	if (!reclist)
+	prep_stm_name = g_strdup_printf ("PS%d", counter++);
+	pg_res = PQprepare (cdata->pconn, prep_stm_name, sql, 0, NULL);
+	if (!pg_res || (PQresultStatus (pg_res) != PGRES_COMMAND_OK)) {
+		event = _gda_postgres_make_error (cdata->cnc, cdata->pconn, pg_res, error);
+		g_free (prep_stm_name);
+		if (pg_res)
+			PQclear (pg_res);
 		return NULL;
-
-	recset = GDA_DATA_MODEL (reclist->data);
-	g_list_free (reclist);
-
-	/* Set it here instead of the SQL query to allow i18n */
-	gda_server_provider_init_schema_model (recset, GDA_CONNECTION_SCHEMA_INDEXES);
-
-	return recset;
-}
-
-static GdaDataModel *
-get_postgres_aggregates (GdaConnection *cnc, GdaParameterList *params)
-{
-	GList *reclist;
-	GdaPostgresConnectionData *priv_data;
-	GdaDataModel *recset;
-	GdaParameter *par = NULL;
-	const gchar *namespace = NULL;
-	
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-
-	if (params)
-		par = gda_parameter_list_find_param (params, "namespace");
-
-	if (par)
-		namespace = g_value_get_string ((GValue *) gda_parameter_get_value (par));
-
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-	if (priv_data->version_float < 7.3) {
-		reclist = process_sql_commands (
-			   NULL, cnc, 
-			   "(SELECT a.aggname, a.oid::varchar, usename, obj_description (a.oid), t2.typname, t1.typname, NULL "
-			   "FROM pg_aggregate a, pg_type t1, pg_type t2, pg_user u "
-			   "WHERE a.aggbasetype = t1.oid AND a.aggfinaltype = t2.oid AND u.usesysid=aggowner) UNION "
-			   "(SELECT a.aggname, a.oid, usename, obj_description (a.oid), t2.typname , '-', NULL "
-			   "FROM pg_aggregate a, pg_type t2, pg_user u "
-			   "WHERE a.aggfinaltype = t2.oid AND u.usesysid=aggowner AND a.aggbasetype = 0) ORDER BY 2",
-			   GDA_COMMAND_OPTION_STOP_ON_ERRORS);
 	}
 	else {
-		if (namespace) {
-			gchar *query;
-
-			query = g_strdup_printf ("%s", namespace);
-			reclist = process_sql_commands (NULL, cnc, query, GDA_COMMAND_OPTION_STOP_ON_ERRORS);
-			g_free (query);
-		}
-		else {
-			gchar *query;
-
-			query = g_strdup_printf (
-                                  "SELECT p.proname, p.oid::varchar, u.usename, pg_catalog.obj_description(p.oid),"
-				  "typo.typname,"
-				  "CASE p.proargtypes[0] "
-				  "WHEN 'pg_catalog.\"any\"'::pg_catalog.regtype "
-				  "THEN CAST('-' AS pg_catalog.text) "
-				  "ELSE typi.typname "
-				  "END,"
-				  "NULL "
-				  "FROM pg_catalog.pg_proc p, pg_catalog.pg_user u, pg_catalog.pg_namespace n, "
-				  "pg_catalog.pg_type typi, pg_catalog.pg_type typo "
-				  "WHERE u.usesysid=p.proowner "
-				  "AND n.oid = p.pronamespace "
-				  "AND p.prorettype = typo.oid "
-				  "AND (typo.oid NOT IN (%s) OR typo.oid='%s') "
-				  "AND p.proargtypes[0] = typi.oid "
-				  "AND (typi.oid NOT IN (%s) OR typi.oid='%s') "
-				  "AND p.proisagg "
-				  "AND pg_catalog.pg_function_is_visible(p.oid) "
-				  "ORDER BY 2", priv_data->avoid_types_oids, priv_data->any_type_oid,
-				  priv_data->avoid_types_oids, priv_data->any_type_oid);
-			reclist = process_sql_commands (NULL, cnc, query, GDA_COMMAND_OPTION_STOP_ON_ERRORS);
-			g_free (query);
-		}
+		GdaPostgresPStmt *ps;
+		PQclear (pg_res);
+		ps = gda_postgres_pstmt_new (cdata->cnc, cdata->pconn, prep_stm_name);
+		_GDA_PSTMT (ps)->param_ids = NULL;
+		_GDA_PSTMT (ps)->sql = g_strdup (sql);
+		return ps;
 	}
-
-	if (!reclist)
-		return NULL;
-
-	recset = GDA_DATA_MODEL (reclist->data);
-	g_list_free (reclist);
-
-	/* Set it here instead of the SQL query to allow i18n */
-	gda_server_provider_init_schema_model (recset, GDA_CONNECTION_SCHEMA_AGGREGATES);
-
-	return recset;
 }
 
-static GdaDataModel *
-get_postgres_triggers (GdaConnection *cnc, GdaParameterList *params)
+/*
+ * Execute statement request
+ *
+ * Executes a statement. This method should do the following:
+ *    - try to prepare the statement if not yet done
+ *    - optionnally reset the prepared statement
+ *    - bind the variables's values (which are in @params)
+ *    - add a connection event to log the execution
+ *    - execute the prepared statement
+ *
+ * If @stmt is an INSERT statement and @last_inserted_row is not NULL then additional actions must be taken to return the
+ * actual inserted row
+ */
+static GObject *
+gda_postgres_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
+					 GdaStatement *stmt, GdaSet *params,
+					 GdaStatementModelUsage model_usage, 
+					 GType *col_types, GdaSet **last_inserted_row, 
+					 guint *task_id, 
+					 GdaServerProviderAsyncCallback async_cb, gpointer cb_data, GError **error)
 {
-	GList *reclist;
-	GdaDataModel *recset;
-	GdaPostgresConnectionData *priv_data;
+	GdaPostgresPStmt *ps;
+	PostgresConnectionData *cdata;
 
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+	g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, NULL);
+	g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
 
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-	if (priv_data->version_float < 7.3) 
-		reclist = process_sql_commands (NULL, cnc, 
-						"SELECT tgname FROM pg_trigger "
-						"WHERE tgisconstraint = false "
-						"ORDER BY tgname ",
-						GDA_COMMAND_OPTION_STOP_ON_ERRORS);
-	else
-		/* REM: the triggers don't seem to belong to a particular schema... */
-		reclist = process_sql_commands (NULL, cnc, 
-						"SELECT t.tgname "
-						"FROM pg_catalog.pg_trigger t "
-						"WHERE t.tgisconstraint = false "
-						"ORDER BY t.tgname",
-						GDA_COMMAND_OPTION_STOP_ON_ERRORS);
-	if (!reclist)
-		return NULL;
-
-	recset = GDA_DATA_MODEL (reclist->data);
-	g_list_free (reclist);
-
-	/* Set it here instead of the SQL query to allow i18n */
-	gda_server_provider_init_schema_model (recset, GDA_CONNECTION_SCHEMA_TRIGGERS);
+	/* If asynchronous connection opening is not supported, then exit now */
+	if (async_cb) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+			     _("Provider does not support asynchronous statement execution"));
+                return NULL;
+	}
 
-	return recset;
-}
+	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return NULL;
 
-static GList *
-gda_postgres_get_idx_data (GdaPostgresConnectionData *priv_data, const gchar *tblname)
-{
-	gint nidx, i;
-	GList *idx_list = NULL;
-	GdaPostgresIdxData *idx_data;
-	gchar *query;
-	PGresult *pg_idx;
+	/* 
+	 * execute prepared statement using C API: CURSOR based 
+	 */
+	if (!(model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS) &&
+	    (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT)) {
+		static guint counter = 0; /* each cursor MUST have a unique name, ensured with this counter */
+		gchar *cursor_name;
+		gchar *cursor_sql;
+		PGresult *pg_res;
+		gchar *sql;
+		GdaDataModel *recset;
+		GdaConnectionEvent *event;
 
-	if (priv_data->version_float < 7.3)
-		query = g_strdup_printf ("SELECT i.indkey, i.indisprimary, i.indisunique "
-					 "FROM pg_class c, pg_class c2, pg_index i "
-					 "WHERE c.relname = '%s' AND c.oid = i.indrelid "
-					 "AND i.indexrelid = c2.oid", tblname);
-	else
-		query = g_strdup_printf ("SELECT i.indkey, i.indisprimary, i.indisunique "
-					 /*",pg_get_indexdef (i.indexrelid, 1, false) ": to get index definition */
-					 "FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i "
-					 "WHERE c.relname = '%s' "
-					 "AND c.oid = i.indrelid "
-					 "AND i.indexrelid = c2.oid "
-					 "AND pg_catalog.pg_table_is_visible(c.oid) AND i.indkey [0] <> 0", tblname);
-
-	pg_idx = gda_postgres_PQexec_wrap (priv_data->cnc, priv_data->pconn, query);
-	g_free (query);
-	if (pg_idx == NULL)
-		return NULL;
+		/* convert to SQL to remove any reference to a variable */
+		sql = gda_postgres_provider_statement_to_sql (provider, cnc, stmt, params, 0, NULL, error);
+		if (!sql)
+			return NULL;
 
-	nidx = PQntuples (pg_idx);
+		/* create a prepared statement object for @sql */
+		ps = prepare_stmt_simple (cdata, sql, error);
+		if (!ps) {
+			g_free (sql);
+			return NULL;
+		}
 
-	idx_data = g_new (GdaPostgresIdxData, nidx);
-	for (i = 0; i < nidx; i++){
-		gchar **arr, **ptr;
-		gint ncolumns;
-		gchar *value;
-		gint k;
-
-		value = PQgetvalue (pg_idx, i, 0);
-		if (value && *value) 
-			arr = g_strsplit (value, " ", 0);
-		else {
-			idx_data[i].ncolumns = 0;
-			continue;
+		/* declare a CURSOR and add a connection event for the execution*/
+		cursor_name = g_strdup_printf ("CURSOR%d", counter++);
+		cursor_sql = g_strdup_printf ("DECLARE %s SCROLL CURSOR WITH HOLD FOR %s", cursor_name, sql);
+		g_free (sql);
+		pg_res = _gda_postgres_PQexec_wrap (cnc, cdata->pconn, cursor_sql);
+		event = gda_connection_event_new (GDA_CONNECTION_EVENT_COMMAND);
+		gda_connection_event_set_description (event, cursor_sql);
+		gda_connection_add_event (cnc, event);
+		g_free (cursor_sql);
+		if (!pg_res || (PQresultStatus (pg_res) != PGRES_COMMAND_OK)) {
+			_gda_postgres_make_error (cnc, cdata->pconn, pg_res, error);
+			if (pg_res)
+				PQclear (pg_res);
+			g_object_unref (ps);
+			return NULL;
 		}
+		PQclear (pg_res);
 		
-		value = PQgetvalue (pg_idx, i, 1);
-		idx_data[i].primary = (*value == 't') ? TRUE : FALSE;
-		value = PQgetvalue (pg_idx, i, 2);
-		idx_data[i].unique = (*value == 't') ? TRUE : FALSE;
-
-		ptr = arr;
-		ncolumns = 0;
-		while (*ptr++)
-			ncolumns++;
-
-		idx_data[i].ncolumns = ncolumns;
-		idx_data[i].columns = g_new (gint, ncolumns);
-		for (k = 0; k < ncolumns; k++)
-			idx_data[i].columns[k] = atoi (arr[k]) - 1;
-
-		idx_list = g_list_append (idx_list, &idx_data[i]);
-		g_strfreev (arr);
+		/* create data model in CURSOR mode */
+		recset = gda_postgres_recordset_new_cursor (cnc, ps, cursor_name, col_types);
+		gda_connection_internal_statement_executed (cnc, stmt, NULL); /* required: help @cnc keep some stats */
+		return (GObject*) recset;
 	}
 
-	PQclear (pg_idx);
-
-	return idx_list;
-}
-
-static gboolean
-gda_postgres_index_type (gint colnum, GList *idx_list, IdxType type)
-{
-	GList *list;
-	GdaPostgresIdxData *idx_data;
-	gint i;
-
-	if (idx_list == NULL || g_list_length (idx_list) == 0)
-		return FALSE;
+	/* get/create new prepared statement */
+	ps = gda_connection_get_prepared_statement (cnc, stmt);
+	if (!ps) {
+		if (!gda_postgres_provider_statement_prepare (provider, cnc, stmt, NULL)) {
+			/* this case can appear for example if some variables are used in places
+			 * where the C API cannot allow them (for example if the variable is the table name
+			 * in a SELECT statement). The action here is to get the actual SQL code for @stmt,
+			 * and use that SQL instead of @stmt to create another GdaPostgresPStmt object.
+			 */
+			gchar *sql;
 
-	for (list = idx_list; list; list = list->next) {
-		idx_data = (GdaPostgresIdxData *) list->data;
-		for (i = 0; i < idx_data->ncolumns; i++) {
-			if (idx_data->columns[i] == colnum){
-				return (type == IDX_PRIMARY) ? 
-					idx_data->primary : idx_data->unique;
-			}
+			sql = gda_postgres_provider_statement_to_sql (provider, cnc, stmt, params, 0, NULL, error);
+			if (!sql)
+				return NULL;
+			ps = prepare_stmt_simple (cdata, sql, error);
+			g_free (sql);
+			if (!ps)
+				return NULL;
 		}
+		else
+			ps = gda_connection_get_prepared_statement (cnc, stmt);
 	}
+	g_assert (ps);
 
-	return FALSE;
-}
-
-/* Converts a single dimension array in the form of '{AA,BB,CC}' to a list of
- * strings (here ->"AA"->"BB"->"CC) which must be freed by the caller
- */
-static GSList *
-gda_postgres_itemize_simple_array (const gchar *array)
-{
-	GSList *list = NULL;
-	gchar *str, *ptr, *tok;
-
-	g_return_val_if_fail (array, NULL);
-
-	str = g_strdup (array);
-	ptr = str;
-
-	/* stripping { and } */
-	if (*str == '{')
-		ptr++;
-	if (str [strlen (str)-1] == '}')
-		str [strlen (str)-1] = 0;
-
-	/* splitting */
-	ptr = strtok_r (ptr, ",", &tok);
-	while (ptr && *ptr) {
-		list = g_slist_append (list, g_strdup (ptr));
-		ptr = strtok_r (NULL, ",", &tok);
-	}
-	
-	g_free (str);
-
-	return list;
-}
-
-static void
-gda_postgres_itemize_simple_array_free (GSList *list)
-{
-	GSList *list2;
-
-	list2 = list;
-	while (list2) {
-		g_free (list2->data);
-		list2 = g_slist_next (list2);
-	}
-	g_slist_free (list);
-}
-
-static GList *
-gda_postgres_get_ref_data (GdaPostgresConnectionData *priv_data, const gchar *tblname)
-{
-	gint nref, i;
-	GList *ref_list = NULL;
-	GdaPostgresRefData *ref_data;
-	gchar *query;
-	PGresult *pg_ref;
-
-	if (priv_data->version_float < 7.3) 
-		query = g_strdup_printf ("SELECT tr.tgargs "
-					 "FROM pg_class c, pg_trigger tr "
-					 "WHERE c.relname = '%s' AND c.oid = tr.tgrelid AND "
-					 "tr.tgisconstraint = true AND tr.tgnargs = 6", tblname);
-	else
-		query = g_strdup_printf ("SELECT o.conkey, o.confkey, fc.relname "
-					 "FROM pg_catalog.pg_class c "
-					 "INNER JOIN pg_catalog.pg_constraint o ON (o.conrelid = c.oid) "
-					 "LEFT JOIN pg_catalog.pg_class fc ON (fc.oid=o.confrelid) "
-					 "WHERE c.relname = '%s' AND contype = 'f' "
-					 "AND pg_catalog.pg_table_is_visible (c.oid) "
-					 "AND pg_catalog.pg_table_is_visible (fc.oid)", tblname);
-
-	pg_ref = gda_postgres_PQexec_wrap (priv_data->cnc, priv_data->pconn, query);
-	g_free (query);
-	if (pg_ref == NULL)
-		return NULL;
-
-	nref = PQntuples (pg_ref);
+	/* bind statement's parameters */
+	GSList *list;
+	GdaConnectionEvent *event = NULL;
+	int i;
+	char **param_values = NULL;
+        int *param_lengths = NULL;
+        int *param_formats = NULL;
+	gint nb_params;
+	
+	nb_params = g_slist_length (_GDA_PSTMT (ps)->param_ids);
+	param_values = g_new0 (char *, nb_params + 1);
+	param_lengths = g_new0 (int, nb_params + 1);
+	param_formats = g_new0 (int, nb_params + 1);
+
+	for (i = 0, list = _GDA_PSTMT (ps)->param_ids; list; list = list->next, i++) {
+		const gchar *pname = (gchar *) list->data;
+		GdaHolder *h;
+		
+		/* find requested parameter */
+		if (!params) {
+			event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+			gda_connection_event_set_description (event, _("Missing parameter(s) to execute query"));
+			g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+				     GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR,
+				     _("Missing parameter(s) to execute query"));
+			break;
+		}
+
+		h = gda_set_get_holder (params, pname);
+		if (!h) {
+			gchar *tmp = gda_alphanum_to_text (g_strdup (pname + 1));
+			if (tmp) {
+				h = gda_set_get_holder (params, tmp);
+				g_free (tmp);
+			}
+		}
+		if (!h) {
+			gchar *str;
+			str = g_strdup_printf (_("Missing parameter '%s' to execute query"), pname);
+			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_MISSING_PARAM_ERROR, str);
+			g_free (str);
+			break;
+		}
 
-	for (i = 0; i < nref; i++){
-		if (priv_data->version_float < 7.3) {
-			gint lentblname;
-			gchar **arr;
-			gchar *value;
+		/* actual binding using the C API, for parameter at position @i */
+		const GValue *value = gda_holder_get_value (h);
+		if (!value || gda_value_is_null (value))
+			param_values [i] = NULL;
+		else if (G_VALUE_TYPE (value) == GDA_TYPE_BLOB) {
+			/* specific BLOB treatment */
+			GdaBlob *blob = (GdaBlob*) gda_value_get_blob ((GValue *) value);
+			GdaPostgresBlobOp *op;
 			
-			lentblname = strlen (tblname);
-			ref_data = g_new0 (GdaPostgresRefData, 1);
-			value = PQgetvalue (pg_ref, i, 0);
-			arr = g_strsplit (value, "\\000", 0);
-			if (!strncmp (tblname, arr[1], lentblname)) {
-				ref_data->colname = g_strdup (arr[4]);
-				ref_data->reference = g_strdup_printf ("%s.%s", arr[2], arr[5]);
-				ref_list = g_list_append (ref_list, ref_data);
+			/* Postgres requires that a transaction be started for LOB operations */
+			if (!check_transaction_started (cnc)) {
+				event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+				gda_connection_event_set_description (event, _("Cannot start transaction"));
+				g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR,
+					     _("Cannot start transaction"));
+				break;
 			}
 			
-			g_strfreev (arr);
-		}
-		else {
-			gchar *value;
-			GSList *itemf, *listf;
-			GSList *itemp, *listp;
-			
-			value = PQgetvalue (pg_ref, i, 0);
-			listf = gda_postgres_itemize_simple_array (value);
-			itemf = listf;
-
-			value = PQgetvalue (pg_ref, i, 1);
-			listp = gda_postgres_itemize_simple_array (value);
-			itemp = listp;
-
-			g_assert (g_slist_length (listf) == g_slist_length (listp));
-			while (itemp && itemf) {
-				PGresult *pg_res;
-				query = g_strdup_printf ("SELECT a.attname FROM pg_catalog.pg_class c "
-							 "LEFT JOIN pg_catalog.pg_attribute a ON (a.attrelid = c.oid) "
-							 "WHERE c.relname = '%s' AND pg_catalog.pg_table_is_visible (c.oid) "
-							 "AND a.attnum = %d AND NOT a.attisdropped", 
-							 PQgetvalue (pg_ref, i, 2), atoi (itemp->data));
-				pg_res = gda_postgres_PQexec_wrap (priv_data->cnc, priv_data->pconn, query);
-				/*g_print ("Query: %s\n", query);*/
-				g_free (query);
-				if (pg_res == NULL)
-					return NULL;
-				
-				g_assert (PQntuples (pg_res) == 1);
-
-				ref_data = g_new0 (GdaPostgresRefData, 1);
-				ref_data->colname = NULL;
-				ref_data->colnum = atoi (itemf->data);
-				ref_data->reference = g_strdup_printf ("%s.%s", 
-								       PQgetvalue (pg_ref, i, 2), PQgetvalue (pg_res, 0, 0));
-				PQclear (pg_res);
-				ref_list = g_list_append (ref_list, ref_data);
-				itemp = g_slist_next (itemp);
-				itemf = g_slist_next (itemf);
-			}
-			gda_postgres_itemize_simple_array_free (listf);
-			gda_postgres_itemize_simple_array_free (listp);
-		}
-	}
-	PQclear (pg_ref);
-		
-	return ref_list;
-}
-
-static void
-free_idx_data (gpointer data, gpointer user_data)
-{
-	GdaPostgresIdxData *idx_data = (GdaPostgresIdxData *) data;
-
-	g_free (idx_data->columns);
-}
-
-static void
-free_ref_data (gpointer data, gpointer user_data)
-{
-	GdaPostgresRefData *ref_data = (GdaPostgresRefData *) data;
-
-	if (ref_data->colname)
-		g_free (ref_data->colname);
-	g_free (ref_data->reference);
-	g_free (ref_data);
-}
-
-/* FIXME: a and b are of the same type! */
-static gint
-ref_custom_compare (gconstpointer a, gconstpointer b)
-{
-	GdaPostgresRefData *ref_data = (GdaPostgresRefData *) a;
-	gchar *colname = (gchar *) b;
-
-	if (!strcmp (ref_data->colname, colname))
-		return 0;
-
-	return 1;
-}
-
-static GList *
-gda_postgres_fill_md_data (const gchar *tblname, GdaDataModelArray *recset,
-			   GdaPostgresConnectionData *priv_data)
-{
-	gchar *query;
-	PGresult *pg_res;
-	gint row_count, i;
-	GList *list = NULL;
-	GList *idx_list;
-	GList *ref_list;
-
-	if (priv_data->version_float < 7.3)
-		query = g_strdup_printf (
-			"(SELECT a.attname, b.typname, a.atttypmod, b.typlen, a.attnotnull, d.adsrc, "
-			"a.attnum FROM pg_class c, pg_attribute a, pg_type b, pg_attrdef d "
-			"WHERE c.relname = '%s' AND a.attnum > 0 AND "
-			"a.attrelid = c.oid and b.oid = a.atttypid AND "
-			"a.atthasdef = 't' and d.adrelid=c.oid and d.adnum=a.attnum) "
-			"UNION (SELECT a.attname, b.typname, a.atttypmod, b.typlen, a.attnotnull, NULL, "
-			"a.attnum FROM pg_class c, pg_attribute a, pg_type b "
-			  "WHERE c.relname = '%s' AND a.attnum > 0 AND "
-			"a.attrelid = c.oid and b.oid = a.atttypid AND a.atthasdef = 'f') ORDER BY 7",
-			tblname, tblname);
-	else 
-		query = g_strdup_printf (
-			"SELECT a.attname, t.typname, a.atttypmod, t.typlen, a.attnotnull, pg_get_expr (d.adbin, c.oid), a.attnum "
-			"FROM pg_catalog.pg_class c "
-			"LEFT JOIN pg_catalog.pg_attribute a ON (a.attrelid = c.oid) "
-			"FULL JOIN pg_catalog.pg_attrdef d ON (a.attnum = d.adnum AND d.adrelid=c.oid) "
-			"LEFT JOIN pg_catalog.pg_type t ON (t.oid = a.atttypid) "
-			"WHERE c.relname = '%s' AND pg_catalog.pg_table_is_visible (c.oid) AND a.attnum > 0 "
-			"AND NOT a.attisdropped ORDER BY 7", tblname);
-
-	pg_res = gda_postgres_PQexec_wrap (priv_data->cnc, priv_data->pconn, query);
-	g_free (query);
-	if (pg_res == NULL)
-		return NULL;
-
-	idx_list = gda_postgres_get_idx_data (priv_data, tblname);
-	ref_list = gda_postgres_get_ref_data (priv_data, tblname);
-
-	row_count = PQntuples (pg_res);
-	for (i = 0; i < row_count; i++) {
-		GValue *value;
-		gchar *thevalue, *colname, *ref = NULL;
-		GType type;
-		gint32 integer;
-		GList *rowlist = NULL;
-		GList *rlist;
-
-		/* Field name */
-		colname = thevalue = PQgetvalue (pg_res, i, 0);
-		g_value_set_string (value = gda_value_new (G_TYPE_STRING), thevalue);
-		rowlist = g_list_append (rowlist, value);
-
-		/* Data type */
-		thevalue = PQgetvalue(pg_res, i, 1);
-		type = gda_postgres_type_name_to_gda (priv_data->h_table, 
-						      thevalue);
-		g_value_set_string (value = gda_value_new (G_TYPE_STRING), thevalue);
-		rowlist = g_list_append (rowlist, value);
-
-		/* Defined size */
-		thevalue = PQgetvalue(pg_res, i, 3);
-		integer = atoi (thevalue);
-		if (integer == -1 && type == G_TYPE_STRING) {
-			thevalue = PQgetvalue(pg_res, i, 2);
-			integer = atoi (thevalue) - 4; /* don't know where the -4 comes from! */
-		}
-		if (integer == -1 && type == GDA_TYPE_NUMERIC) {
-			thevalue = PQgetvalue(pg_res, i, 2);
-			integer = atoi(thevalue) / 65536;
-		}
+			/* create GdaBlobOp */
+			op = (GdaPostgresBlobOp *) gda_postgres_blob_op_new (cnc);
 			
-		g_value_set_int (value = gda_value_new (G_TYPE_INT), (integer != -1) ? integer : 0);
-		rowlist = g_list_append (rowlist, value);
-
-		/* Scale */ 
-		integer = 0;
-		if (type == GDA_TYPE_NUMERIC) {
-			thevalue = PQgetvalue(pg_res, i, 2);
-			integer = (atoi(thevalue) % 65536) - 4;
-		}
-		g_value_set_int (value = gda_value_new (G_TYPE_INT), integer);
-		rowlist = g_list_append (rowlist, value);
-
-		/* Not null? */
-		thevalue = PQgetvalue(pg_res, i, 4);
-		g_value_set_boolean (value = gda_value_new (G_TYPE_BOOLEAN), (*thevalue == 't' ? TRUE : FALSE));
-		rowlist = g_list_append (rowlist, value);
-
-		/* Primary key? */
-		g_value_set_boolean (value = gda_value_new (G_TYPE_BOOLEAN),
-				     gda_postgres_index_type (i, idx_list, IDX_PRIMARY));
-		rowlist = g_list_append (rowlist, value);
-
-		/* Unique index? */
-		g_value_set_boolean (value = gda_value_new (G_TYPE_BOOLEAN),
-				     gda_postgres_index_type (i, idx_list, IDX_UNIQUE));
-		rowlist = g_list_append (rowlist, value);
-
-		/* References */
-		if (priv_data->version_float < 7.3) {
-			rlist = g_list_find_custom (ref_list, colname, ref_custom_compare); 
-			if (rlist)
-				ref = ((GdaPostgresRefData *) rlist->data)->reference;
+			/* always create a new blob as there is no way to truncate an existing blob */
+			if (gda_postgres_blob_op_declare_blob (op) &&
+			    gda_blob_op_write ((GdaBlobOp*) op, blob, 0))
+				param_values [i] = gda_postgres_blob_op_get_id (op);
 			else
-				ref = "";
+				param_values [i] = NULL;
+			g_object_unref (op);
 		}
-		else {
-			GList *plist = ref_list;
-			ref = NULL;
+		else if (G_VALUE_TYPE (value) == GDA_TYPE_BINARY) {
+			/* directly bin binary data */
+			GdaBinary *bin = (GdaBinary *) gda_value_get_binary ((GValue *) value);
+			param_values [i] = (gchar*) bin->data;
+			param_lengths [i] = bin->binary_length;
+			param_formats [i] = 1; /* binary format */
+		}
+		else if ((G_VALUE_TYPE (value) == G_TYPE_DATE) || 
+			 (G_VALUE_TYPE (value) == GDA_TYPE_TIMESTAMP) ||
+			 (G_VALUE_TYPE (value) == GDA_TYPE_TIME)) {
+			GdaHandlerTime *timdh;
 			
-			while (plist && !ref) {
-				if (((GdaPostgresRefData *) plist->data)->colnum == atoi (PQgetvalue(pg_res, i, 6)))
-					ref = ((GdaPostgresRefData *) plist->data)->reference;
-				plist = g_list_next (plist);
-			}
-			if (!ref)
-				ref = "";
+			timdh = GDA_HANDLER_TIME (gda_server_provider_get_data_handler_gtype (provider, cnc, 
+											      G_VALUE_TYPE (value)));
+			g_assert (timdh);
+			param_values [i] = gda_handler_time_get_no_locale_str_from_value (timdh, value);
 		}
-		g_value_set_string (value = gda_value_new (G_TYPE_STRING), ref);
-		rowlist = g_list_append (rowlist, value);
+		else {
+			GdaDataHandler *dh;
 
-		/* Default value */
-		if (!PQgetisnull (pg_res, i, 5)) {
-			thevalue = PQgetvalue (pg_res, i, 5);
-			g_value_set_string (value = gda_value_new (G_TYPE_STRING), thevalue);
+			dh = gda_server_provider_get_data_handler_gtype (provider, cnc, G_VALUE_TYPE (value));
+			if (dh)
+				param_values [i] = gda_data_handler_get_str_from_value (dh, value);
+			else
+				param_values [i] = NULL;
 		}
-		else
-			value = gda_value_new_null ();
-	        rowlist = g_list_append (rowlist, value);
-
-		/* Extra attributes */
-		if (strstr (PQgetvalue (pg_res, i, 5), "nextval"))
-			g_value_set_string (value = gda_value_new (G_TYPE_STRING), "AUTO_INCREMENT");
-		else
-			g_value_set_string (value = gda_value_new (G_TYPE_STRING), "");
-	        rowlist = g_list_append (rowlist, value);			
-
-		list = g_list_append (list, rowlist);
-		rowlist = NULL;
 	}
-
-	PQclear (pg_res);
-
-	if (idx_list && idx_list->data) {
-		g_list_foreach (idx_list, free_idx_data, NULL);
-		g_free (idx_list->data);
-	}
-
-	if (ref_list && ref_list->data) 
-		g_list_foreach (ref_list, free_ref_data, NULL);
-
-	g_list_free (ref_list);
-	g_list_free (idx_list);
-
-	return list;
-}
-
-static void
-add_g_list_row (gpointer data, gpointer user_data)
-{
-	GList *rowlist = data;
-	GdaDataModelArray *recset = user_data;
-
-	gda_data_model_append_values (GDA_DATA_MODEL (recset), rowlist, NULL);
-	g_list_foreach (rowlist, (GFunc) gda_value_free, NULL);
-	g_list_free (rowlist);
-}
-
-static GdaDataModel *
-get_postgres_fields_metadata (GdaConnection *cnc, GdaParameterList *params)
-{
-	GList *list;
-	GdaPostgresConnectionData *priv_data;
-	GdaDataModelArray *recset;
-	GdaParameter *par;
-	const gchar *tblname;
-
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-	g_return_val_if_fail (params != NULL, NULL);
-
-	par = gda_parameter_list_find_param (params, "name");
-	g_return_val_if_fail (par != NULL, NULL);
-
-	tblname = g_value_get_string ((GValue *) gda_parameter_get_value (par));
-	g_return_val_if_fail (tblname != NULL, NULL);
-	
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-
-	recset = GDA_DATA_MODEL_ARRAY (gda_data_model_array_new 
-				       (gda_server_provider_get_schema_nb_columns (GDA_CONNECTION_SCHEMA_FIELDS)));
-	gda_server_provider_init_schema_model (GDA_DATA_MODEL (recset), GDA_CONNECTION_SCHEMA_FIELDS);
-	list = gda_postgres_fill_md_data (tblname, recset, priv_data);
-	g_list_foreach (list, add_g_list_row, recset);
-	g_list_free (list);
-
-	return GDA_DATA_MODEL (recset);
-}
-
-static GdaDataModel *
-get_postgres_databases (GdaConnection *cnc, GdaParameterList *params)
-{
-	GList *reclist;
-	GdaPostgresConnectionData *priv_data;
-	GdaDataModel *recset;
-	
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-
-	if (priv_data->version_float < 7.3)
-		reclist = process_sql_commands (NULL, cnc, 
-						"SELECT datname "
-						"FROM pg_database "
-						"ORDER BY 1",
-						GDA_COMMAND_OPTION_STOP_ON_ERRORS);
-	else
-		reclist = process_sql_commands (NULL, cnc, 
-						"SELECT datname "
-						"FROM pg_catalog.pg_database "
-						"ORDER BY 1",
-						GDA_COMMAND_OPTION_STOP_ON_ERRORS);
-
-	if (!reclist)
-		return NULL;
-
-	recset = GDA_DATA_MODEL (reclist->data);
-	g_list_free (reclist);
-
-	/* Set it here instead of the SQL query to allow i18n */
-	gda_server_provider_init_schema_model (recset, GDA_CONNECTION_SCHEMA_DATABASES);
-
-	return recset;
-}
-
-static GdaDataModel *
-get_postgres_users (GdaConnection *cnc, GdaParameterList *params)
-{
-	GList *reclist;
-	GdaDataModel *recset;
-	GdaPostgresConnectionData *priv_data;
-
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-	
-	if (priv_data->version_float < 7.3)
-		reclist = process_sql_commands (NULL, cnc, 
-						"SELECT usename "
-						"FROM pg_user "
-						"ORDER BY usename",
-						GDA_COMMAND_OPTION_STOP_ON_ERRORS);
-	else
-		reclist = process_sql_commands (NULL, cnc, 
-						"SELECT u.usename "
-						"FROM pg_catalog.pg_user u"
-						"ORDER BY u.usename",
-						GDA_COMMAND_OPTION_STOP_ON_ERRORS);	
-
-	if (!reclist)
-		return NULL;
-
-	recset = GDA_DATA_MODEL (reclist->data);
-	g_list_free (reclist);
-
-	/* Set it here instead of the SQL query to allow i18n */
-	gda_server_provider_init_schema_model (recset, GDA_CONNECTION_SCHEMA_USERS);
-
-	return recset;
-}
-
-static GdaDataModel *
-get_postgres_sequences (GdaConnection *cnc, GdaParameterList *params)
-{
-	GList *reclist;
-	GdaDataModel *recset;
-	GdaPostgresConnectionData *priv_data;
-
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-
-	
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-	
-	if (priv_data->version_float < 7.3)
-		reclist = process_sql_commands (
-                            NULL, cnc, 
-			    "SELECT relname, usename, obj_description(pg_class.oid), NULL "
-			    "FROM pg_class, pg_user "
-			    "WHERE usesysid=relowner AND relkind = 'S' AND relname !~ '^pg_' ORDER BY relname",
-			    GDA_COMMAND_OPTION_STOP_ON_ERRORS);
-	else
-		reclist = process_sql_commands (
-                            NULL, cnc, 
-			    "SELECT c.relname, u.usename, obj_description (c.oid), NULL "
-			    "FROM pg_catalog.pg_class c, pg_catalog.pg_user u "
-			    "WHERE u.usesysid = c.relowner "
-			    "AND c.relkind = 'S' "
-			    "AND pg_catalog.pg_table_is_visible(c.oid) "
-			    "ORDER BY relname",
-			    GDA_COMMAND_OPTION_STOP_ON_ERRORS);
-
-	if (!reclist)
-		return NULL;
-
-	recset = GDA_DATA_MODEL (reclist->data);
-	g_list_free (reclist);
-
-	/* Set it here instead of the SQL query to allow i18n */
-	gda_server_provider_init_schema_model (recset, GDA_CONNECTION_SCHEMA_SEQUENCES);
-
-	return recset;
-}
-
-static GdaDataModel *
-get_postgres_parent_tables (GdaConnection *cnc, GdaParameterList *params)
-{
-	GList *reclist;
-	GdaDataModel *recset;
-	gchar *query;
-	const gchar *tblname;
-	GdaParameter *par;
-	GdaPostgresConnectionData *priv_data;
-	
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-	g_return_val_if_fail (params != NULL, NULL);
-
-	par = gda_parameter_list_find_param (params, "name");
-	g_return_val_if_fail (par != NULL, NULL);
-
-	tblname = g_value_get_string ((GValue *) gda_parameter_get_value (par));
-	g_return_val_if_fail (tblname != NULL, NULL);
-
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-
-	if (priv_data->version_float < 7.3)
-		query = g_strdup_printf ("SELECT a.relname, b.inhseqno "
-					 "FROM pg_inherits b, pg_class a, pg_class c "
-					 "WHERE a.oid=b.inhparent AND b.inhrelid = c.oid "
-					 "AND c.relname = '%s' ORDER BY b.inhseqno",
-					 tblname);
-	else
-		query = g_strdup_printf ("SELECT p.relname, h.inhseqno "
-					 "FROM pg_catalog.pg_inherits h, pg_catalog.pg_class p, pg_catalog.pg_class c "
-					 "WHERE pg_catalog.pg_table_is_visible(c.oid) "
-					 "AND pg_catalog.pg_table_is_visible(p.oid) "
-					 "AND p.oid = h.inhparent "
-					 "AND h.inhrelid = c.oid "
-					 "AND c.relname = '%s' "
-					 "ORDER BY h.inhseqno", 
-					 tblname);
 		
-
-	reclist = process_sql_commands (NULL, cnc, query,
-					GDA_COMMAND_OPTION_STOP_ON_ERRORS);
-	g_free (query);
-	if (!reclist)
-		return NULL;
-
-	recset = GDA_DATA_MODEL (reclist->data);
-	g_list_free (reclist);
-
-	/* Set it here instead of the SQL query to allow i18n */
-	gda_server_provider_init_schema_model (recset, GDA_CONNECTION_SCHEMA_PARENT_TABLES);
-
-	return recset;
-}
-
-static GdaDataModel *
-get_postgres_constraints (GdaConnection *cnc, GdaParameterList *params)
-{
-	GdaPostgresConnectionData *priv_data;
-	GdaDataModelArray *recset;
-	GdaParameter *par;
-	const gchar *tblname;
-
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-	g_return_val_if_fail (params != NULL, NULL);
-
-	par = gda_parameter_list_find_param (params, "name");
-	g_return_val_if_fail (par != NULL, NULL);
-
-	tblname = g_value_get_string ((GValue *) gda_parameter_get_value (par));
-	g_return_val_if_fail (tblname != NULL, NULL);
-	
-	priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-
-	recset = GDA_DATA_MODEL_ARRAY (gda_data_model_array_new 
-				       (gda_server_provider_get_schema_nb_columns (GDA_CONNECTION_SCHEMA_CONSTRAINTS)));
-	gda_server_provider_init_schema_model (GDA_DATA_MODEL (recset), GDA_CONNECTION_SCHEMA_CONSTRAINTS);
-
-	TO_IMPLEMENT;
-
-	return GDA_DATA_MODEL (recset);
-}
-
-
-/* get_schema handler for the GdaPostgresProvider class */
-static GdaDataModel *
-gda_postgres_provider_get_schema (GdaServerProvider *provider,
-				  GdaConnection *cnc,
-				  GdaConnectionSchema schema,
-				  GdaParameterList *params)
-{
-	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
-	if (cnc)
-		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-	else
+	if (event) {
+		gda_connection_add_event (cnc, event);
+		g_strfreev (param_values);
+                g_free (param_lengths);
+                g_free (param_formats);
 		return NULL;
-
-	switch (schema) {
-	case GDA_CONNECTION_SCHEMA_AGGREGATES :
-		return get_postgres_aggregates (cnc, params);
-	case GDA_CONNECTION_SCHEMA_DATABASES :
-		return get_postgres_databases (cnc, params);
-	case GDA_CONNECTION_SCHEMA_INDEXES :
-		return get_postgres_indexes (cnc, params);
-	case GDA_CONNECTION_SCHEMA_FIELDS :
-		return get_postgres_fields_metadata (cnc, params);
-	case GDA_CONNECTION_SCHEMA_PROCEDURES :
-		return get_postgres_procedures (cnc, params);
-	case GDA_CONNECTION_SCHEMA_SEQUENCES :
-		return get_postgres_sequences (cnc, params);
-	case GDA_CONNECTION_SCHEMA_TABLES :
-		return get_postgres_tables (cnc, params);
-	case GDA_CONNECTION_SCHEMA_TRIGGERS :
-		return get_postgres_triggers (cnc, params);
-	case GDA_CONNECTION_SCHEMA_TYPES :
-		return get_postgres_types (cnc, params);
-	case GDA_CONNECTION_SCHEMA_USERS :
-		return get_postgres_users (cnc, params);
-	case GDA_CONNECTION_SCHEMA_VIEWS :
-		return get_postgres_views (cnc, params);
-	case GDA_CONNECTION_SCHEMA_PARENT_TABLES :
-		return get_postgres_parent_tables (cnc, params);
-	case GDA_CONNECTION_SCHEMA_CONSTRAINTS :
-		return get_postgres_constraints (cnc, params);
-	default:
-		break;
 	}
-
-	return NULL;
-}
-
-static GdaDataHandler *
-gda_postgres_provider_get_data_handler (GdaServerProvider *provider,
-					GdaConnection *cnc,
-					GType type,
-					const gchar *dbms_type)
-{
-	GdaDataHandler *dh = NULL;
 	
-	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
+	/* add a connection event for the execution */
+	event = gda_connection_event_new (GDA_CONNECTION_EVENT_COMMAND);
+        gda_connection_event_set_description (event, _GDA_PSTMT (ps)->sql);
+        gda_connection_add_event (cnc, event);
 
-        if ((type == G_TYPE_INT64) ||
-	    (type == G_TYPE_UINT64) ||
-	    (type == G_TYPE_DOUBLE) ||
-	    (type == G_TYPE_INT) ||
-	    (type == GDA_TYPE_NUMERIC) ||
-	    (type == G_TYPE_FLOAT) ||
-	    (type == GDA_TYPE_SHORT) ||
-	    (type == GDA_TYPE_USHORT) ||
-	    (type == G_TYPE_CHAR) ||
-	    (type == G_TYPE_UCHAR) ||
-	    (type == G_TYPE_UINT)) {
-		dh = gda_server_provider_handler_find (provider, NULL, type, NULL);
-		if (!dh) {
-			dh = gda_handler_numerical_new ();
-			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_INT64, NULL);
-			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_UINT64, NULL);
-			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_DOUBLE, NULL);
-			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_INT, NULL);
-			gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_NUMERIC, NULL);
-			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_FLOAT, NULL);
-			gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_SHORT, NULL);
-			gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_USHORT, NULL);
-			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_CHAR, NULL);
-			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_UCHAR, NULL);
-			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_UINT, NULL);
-			g_object_unref (dh);
-		}
-	}
-        else if ((type == GDA_TYPE_BINARY) ||
-		 (type == GDA_TYPE_BLOB)){ 
-		dh = gda_server_provider_handler_find (provider, cnc, type, NULL);
-		if (!dh) {
-			dh = gda_postgres_handler_bin_new (cnc);
-			if (dh) {
-				gda_server_provider_handler_declare (provider, dh, cnc, GDA_TYPE_BINARY, NULL);
-				gda_server_provider_handler_declare (provider, dh, cnc, GDA_TYPE_BLOB, NULL);
-				g_object_unref (dh);
-			}
-		}
-	}
-        else if (type == G_TYPE_BOOLEAN) {
-		dh = gda_server_provider_handler_find (provider, NULL, type, NULL);
-		if (!dh) {
-			dh = gda_handler_boolean_new ();
-			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_BOOLEAN, NULL);
-			g_object_unref (dh);
-		}
-	}
-	else if ((type == G_TYPE_DATE) ||
-		 (type == GDA_TYPE_TIME) ||
-		 (type == GDA_TYPE_TIMESTAMP)) {
-		dh = gda_server_provider_handler_find (provider, NULL, type, NULL);
-		if (!dh) {
-			dh = gda_handler_time_new ();
-			gda_handler_time_set_sql_spec   ((GdaHandlerTime *) dh, G_DATE_YEAR,
-							 G_DATE_MONTH, G_DATE_DAY, '-', FALSE);
-			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_DATE, NULL);
-			gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_TIME, NULL);
-			gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_TIMESTAMP, NULL);
-			g_object_unref (dh);
-		}
-	}
-	else if (type == G_TYPE_STRING) {
-		dh = gda_server_provider_handler_find (provider, NULL, type, NULL);
-		if (!dh) {
-			dh = gda_handler_string_new_with_provider (provider, cnc);
-			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_STRING, NULL);
-			g_object_unref (dh);
-		}
-	}
-	else if (type == G_TYPE_ULONG) {
-		dh = gda_server_provider_handler_find (provider, NULL, type, NULL);
-		if (!dh) {
-			dh = gda_handler_type_new ();
-			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_ULONG, NULL);
-			g_object_unref (dh);
-		}
-	}
+	/* execute prepared statement using C API: random access based */
+	PGresult *pg_res;
+	GObject *retval = NULL;
+	pg_res = PQexecPrepared (cdata->pconn, ps->prep_name, nb_params, (const char * const *) param_values,
+				 param_lengths, param_formats, 0);
+	if (!pg_res) 
+		event = _gda_postgres_make_error (cnc, cdata->pconn, NULL, error);
 	else {
-		if (dbms_type) {
-			GdaPostgresConnectionData *priv_data = NULL;
-
-			if (cnc) {
-				g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
-				priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-			}
-			if (priv_data) {
-				gint i;
-				GdaPostgresTypeOid *td = NULL;
-				
-				for (i = 0; i < priv_data->ntypes; i++) {
-					if (!strcmp (priv_data->type_data[i].name, dbms_type))
-						td = &(priv_data->type_data[i]);
-				}
-				
-				if (td) {
-					dh = gda_postgres_provider_get_data_handler (provider, cnc, td->type, NULL);
-					gda_server_provider_handler_declare (provider, dh, cnc, 
-									     G_TYPE_INVALID, dbms_type);
+		int status;
+		status = PQresultStatus (pg_res);
+		if (status == PGRES_EMPTY_QUERY ||
+                    status == PGRES_TUPLES_OK ||
+                    status == PGRES_COMMAND_OK) {
+                        if (status == PGRES_COMMAND_OK) {
+                                gchar *str;
+                                GdaConnectionEvent *event;
+                                
+                                event = gda_connection_event_new (GDA_CONNECTION_EVENT_NOTICE);
+                                str = g_strdup (PQcmdStatus (pg_res));
+                                gda_connection_event_set_description (event, str);
+                                g_free (str);
+                                gda_connection_add_event (cnc, event);
+                                retval = (GObject *) gda_set_new_inline (1, "IMPACTED_ROWS", G_TYPE_INT,
+									 atoi (PQcmdTuples (pg_res)));
+                           
+                                if ((PQoidValue (pg_res) != InvalidOid) && last_inserted_row) {
+					TO_IMPLEMENT;
+					/* use PQoidValue (pg_res); */
 				}
-			}
-			else {
-				dh = gda_postgres_provider_get_data_handler (provider, cnc, 
-									     postgres_name_to_g_type (dbms_type, NULL), 
-									     NULL);
-				gda_server_provider_handler_declare (provider, dh, cnc, 
-								     G_TYPE_INVALID, dbms_type);
-			}
-		}
-	}
-
-	return dh;
-}
-	
-static const gchar* 
-gda_postgres_provider_get_default_dbms_type (GdaServerProvider *provider,
-					     GdaConnection *cnc,
-					     GType type)
-{
-	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
-
-	if (type == G_TYPE_INT64)
-		return "int8";
-	if (type == G_TYPE_UINT64)
-		return "int8";
-	if (type == GDA_TYPE_BINARY)
-		return "bytea";
-	if (type == GDA_TYPE_BLOB)
-		return "oid";
-	if (type == G_TYPE_BOOLEAN)
-		return "bool";
-	if (type == G_TYPE_DATE)
-		return "date";
-	if (type == G_TYPE_DOUBLE)
-		return "float8";
-	if (type == GDA_TYPE_GEOMETRIC_POINT)
-		return "point";
-	if (type == G_TYPE_OBJECT)
-		return "text";
-	if (type == G_TYPE_INT)
-		return "int4";
-	if (type == GDA_TYPE_LIST)
-		return "text";
-	if (type == GDA_TYPE_NUMERIC)
-		return "numeric";
-	if (type == G_TYPE_FLOAT)
-		return "float4";
-	if (type == GDA_TYPE_SHORT)
-		return "int2";
-	if (type == GDA_TYPE_USHORT)
-		return "int2";
-	if (type == G_TYPE_STRING)
-		return "varchar";
-	if (type == GDA_TYPE_TIME)
-		return "time";
-	if (type == GDA_TYPE_TIMESTAMP)
-		return "timestamp";
-	if (type == G_TYPE_CHAR)
-		return "smallint";
-	if (type == G_TYPE_UCHAR)
-		return "smallint";
-	if (type == G_TYPE_ULONG)
-		return "int8";
-        if (type == G_TYPE_UINT)
-		return "int4";
-	if (type == G_TYPE_INVALID)
-		return "text";
-
-	return "text";
-}
-
-static gchar *
-gda_postgres_provider_escape_string (GdaServerProvider *provider, GdaConnection *cnc, const gchar *str)
-{
-	GdaPostgresConnectionData *priv_data = NULL;
-	gchar *dest;
-	gint length;
-
-	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
-	if (cnc) {
-		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-		
-		priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
-		if (!priv_data) {
-			gda_connection_add_event_string (cnc, _("Invalid PostgreSQL handle"));
-			return NULL;
-		}
-	}
-
-	length = strlen (str);
-	dest = g_new (gchar, 2*length + 1);
-	if (0 && priv_data) {
-		/* FIXME: use this call but it's only defined for Postgres >= 8.1 */
-		/*PQescapeStringConn (priv_data->pconnpconn, dest, str, length, NULL);*/
+                                PQclear (pg_res);
+                        }
+                        else if (status == PGRES_TUPLES_OK) 
+				retval = (GObject*) gda_postgres_recordset_new_random (cnc, ps, pg_res, col_types);
+                        else {
+                                PQclear (pg_res);
+                                retval = (GObject *) gda_data_model_array_new (0);
+                        }
+                }
+		else 
+			event = _gda_postgres_make_error (cnc, cdata->pconn, NULL, error);
 	}
-	else
-		PQescapeString (dest, str, length);
 
-	return dest;
+	gda_connection_internal_statement_executed (cnc, stmt, NULL); /* required: help @cnc keep some stats */
+	return retval;
 }
 
-static gchar *
-gda_postgres_provider_unescape_string (GdaServerProvider *provider, GdaConnection *cnc, const gchar *str)
+/*
+ * Free connection's specific data
+ */
+static void
+gda_postgres_free_cnc_data (PostgresConnectionData *cdata)
 {
-	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
-
-	return gda_default_unescape_string (str);
-}
+	if (!cdata)
+		return;
 
-static GdaSqlParser *
-gda_postgres_provider_create_parser (GdaServerProvider *provider, GdaConnection *cnc)
-{
-        g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
-        return (GdaSqlParser*) g_object_new (GDA_TYPE_POSTGRES_PARSER, "tokenizer-flavour", 
-					     GDA_SQL_PARSER_FLAVOUR_POSTGRESQL, NULL);
+	if (cdata->pconn)
+                PQfinish (cdata->pconn);
+	TO_IMPLEMENT;
+	g_free (cdata);
 }

Modified: branches/V4-branch/providers/postgres/gda-postgres-provider.h
==============================================================================
--- branches/V4-branch/providers/postgres/gda-postgres-provider.h	(original)
+++ branches/V4-branch/providers/postgres/gda-postgres-provider.h	Wed Feb 20 20:36:04 2008
@@ -1,31 +1,31 @@
-/* GNOME DB Postgres Provider
- * Copyright (C) 1998 - 2007 The GNOME Foundation
+/* GDA postgres provider
+ * Copyright (C) 1998 - 2008 The GNOME Foundation.
  *
  * AUTHORS:
  *         Vivien Malerba <malerba gnome-db org>
  *         Rodrigo Moya <rodrigo gnome-db org>
  *         Gonzalo Paniagua Javier <gonzalo 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 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,
+ * 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; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 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_POSTGRES_PROVIDER_H__
 #define __GDA_POSTGRES_PROVIDER_H__
 
 #include <libgda/gda-server-provider.h>
-#include <libpq-fe.h>
 
 #define GDA_TYPE_POSTGRES_PROVIDER            (gda_postgres_provider_get_type())
 #define GDA_POSTGRES_PROVIDER(obj)            (G_TYPE_CHECK_INSTANCE_CAST (obj, GDA_TYPE_POSTGRES_PROVIDER, GdaPostgresProvider))
@@ -33,72 +33,21 @@
 #define GDA_IS_POSTGRES_PROVIDER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE (obj, GDA_TYPE_POSTGRES_PROVIDER))
 #define GDA_IS_POSTGRES_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDA_TYPE_POSTGRES_PROVIDER))
 
-#define PARENT_TYPE GDA_TYPE_SERVER_PROVIDER
-#define OBJECT_DATA_POSTGRES_HANDLE "GDA_Postgres_PostgresHandle"
-
-
 typedef struct _GdaPostgresProvider      GdaPostgresProvider;
 typedef struct _GdaPostgresProviderClass GdaPostgresProviderClass;
 
 struct _GdaPostgresProvider {
-	GdaServerProvider  provider;
+	GdaServerProvider      provider;
 };
 
 struct _GdaPostgresProviderClass {
 	GdaServerProviderClass parent_class;
 };
 
-/* Connection data. */
-typedef struct {
-	gchar              *name;
-	Oid                 oid;
-	GType               type;
-	gchar              *comments;
-	gchar              *owner;
-} GdaPostgresTypeOid;
-
-typedef struct {
-	GdaConnection      *cnc;
-	PGconn             *pconn;
-	gint                ntypes;
-	GdaPostgresTypeOid *type_data;
-	GHashTable         *h_table;
-
-	/* Version of the backend to which we are connected */
-	gchar              *version;
-	gfloat              version_float;
-
-	/* Internal data types not returned */
-	gchar              *avoid_types;
-	gchar              *avoid_types_oids;
-	gchar              *any_type_oid; /* oid for the 'any' data type, used to fetch aggregates and functions */
-
-	/* OID of the last inserted tuple */
-	Oid                 last_insert_id;
-
-	/* Cursor usage */
-	gboolean            use_cursor;
-	gint                chunk_size;
-} GdaPostgresConnectionData;
-
-/* NOTE ABOUT THE POSTGRES VERSIONS:
- * 
- * From Postgres versions <= 7.2.x to version 7.3:
- *  => introduction of schemas (namespaces) and the pg_namespace table
- *  => introduction of the "qualified name" construction for the database objects
- *  => introduction of dropped columns means that the column numbering may have gaps
- *     to be teste with the "attisdropped" attribute
- *  => tables names can start with "pg_" (so don't exclude them anymore)
- *  => aggregates now haves entries in the pg_proc table (pg_aggregate is now only
- *     an extension of pg_proc)
- */
-
 G_BEGIN_DECLS
 
-GType              gda_postgres_provider_get_type (void) G_GNUC_CONST;
-GdaServerProvider *gda_postgres_provider_new (void);
+GType gda_postgres_provider_get_type (void) G_GNUC_CONST;
 
 G_END_DECLS
 
 #endif
-

Added: branches/V4-branch/providers/postgres/gda-postgres-pstmt.c
==============================================================================
--- (empty file)
+++ branches/V4-branch/providers/postgres/gda-postgres-pstmt.c	Wed Feb 20 20:36:04 2008
@@ -0,0 +1,111 @@
+/* GDA postgres provider
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *         Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include "gda-postgres-pstmt.h"
+#include "gda-postgres-util.h"
+
+static void gda_postgres_pstmt_class_init (GdaPostgresPStmtClass *klass);
+static void gda_postgres_pstmt_init       (GdaPostgresPStmt *pstmt, GdaPostgresPStmtClass *klass);
+static void gda_postgres_pstmt_finalize    (GObject *object);
+
+static GObjectClass *parent_class = NULL;
+
+/**
+ * gda_postgres_pstmt_get_type
+ *
+ * Returns: the #GType of GdaPostgresPStmt.
+ */
+GType
+gda_postgres_pstmt_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo info = {
+			sizeof (GdaPostgresPStmtClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) gda_postgres_pstmt_class_init,
+			NULL,
+			NULL,
+			sizeof (GdaPostgresPStmt),
+			0,
+			(GInstanceInitFunc) gda_postgres_pstmt_init
+		};
+
+		type = g_type_register_static (GDA_TYPE_PSTMT, "GdaPostgresPStmt", &info, 0);
+	}
+	return type;
+}
+
+static void 
+gda_postgres_pstmt_class_init (GdaPostgresPStmtClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	parent_class = g_type_class_peek_parent (klass);
+
+	/* virtual functions */
+	object_class->finalize = gda_postgres_pstmt_finalize;
+}
+
+static void
+gda_postgres_pstmt_init (GdaPostgresPStmt *pstmt, GdaPostgresPStmtClass *klass)
+{
+	g_return_if_fail (GDA_IS_PSTMT (pstmt));
+	
+	pstmt->prep_name = NULL;
+}
+
+static void
+gda_postgres_pstmt_finalize (GObject *object)
+{
+	GdaPostgresPStmt *pstmt = (GdaPostgresPStmt *) object;
+
+	g_return_if_fail (GDA_IS_PSTMT (pstmt));
+
+	/* deallocate statement */
+	gchar *sql;
+	sql = g_strdup_printf ("DEALLOCATE %s", pstmt->prep_name);
+	_gda_postgres_PQexec_wrap (pstmt->cnc, pstmt->pconn, sql);
+	g_free (sql);
+	
+	/* free memory */
+	g_free (pstmt->prep_name);
+
+	/* chain to parent class */
+	parent_class->finalize (object);
+}
+
+GdaPostgresPStmt *
+gda_postgres_pstmt_new (GdaConnection *cnc, PGconn *pconn, const gchar *prep_name)
+{
+	GdaPostgresPStmt *pstmt;
+
+	pstmt = (GdaPostgresPStmt *) g_object_new (GDA_TYPE_POSTGRES_PSTMT, NULL);
+	pstmt->prep_name = g_strdup (prep_name);
+	pstmt->cnc = cnc;
+	pstmt->pconn = pconn;
+
+	return pstmt;
+}

Added: branches/V4-branch/providers/postgres/gda-postgres-pstmt.h
==============================================================================
--- (empty file)
+++ branches/V4-branch/providers/postgres/gda-postgres-pstmt.h	Wed Feb 20 20:36:04 2008
@@ -0,0 +1,61 @@
+/* GDA postgres provider
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *         Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GDA_POSTGRES_PSTMT_H__
+#define __GDA_POSTGRES_PSTMT_H__
+
+#include <providers-support/gda-pstmt.h>
+#include "gda-postgres.h"
+
+G_BEGIN_DECLS
+
+#define GDA_TYPE_POSTGRES_PSTMT            (gda_postgres_pstmt_get_type())
+#define GDA_POSTGRES_PSTMT(obj)            (G_TYPE_CHECK_INSTANCE_CAST (obj, GDA_TYPE_POSTGRES_PSTMT, GdaPostgresPStmt))
+#define GDA_POSTGRES_PSTMT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST (klass, GDA_TYPE_POSTGRES_PSTMT, GdaPostgresPStmtClass))
+#define GDA_IS_POSTGRES_PSTMT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE(obj, GDA_TYPE_POSTGRES_PSTMT))
+#define GDA_IS_POSTGRES_PSTMT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GDA_TYPE_POSTGRES_PSTMT))
+
+typedef struct _GdaPostgresPStmt        GdaPostgresPStmt;
+typedef struct _GdaPostgresPStmtClass   GdaPostgresPStmtClass;
+
+struct _GdaPostgresPStmt {
+	GdaPStmt        object;
+	
+	/* PostgreSQL identifies a prepared statement by its name, which we'll keep here,
+	 * along with a pointer to a GdaConnection and a PGconn because when the prepared
+	 * statement is destroyed, we need to call "DEALLOCATE..."
+	 */
+	GdaConnection  *cnc;
+	PGconn         *pconn;
+	gchar          *prep_name;
+};
+
+struct _GdaPostgresPStmtClass {
+	GdaPStmtClass  parent_class;
+};
+
+GType             gda_postgres_pstmt_get_type  (void) G_GNUC_CONST;
+GdaPostgresPStmt *gda_postgres_pstmt_new       (GdaConnection *cnc, PGconn *pconn, const gchar *prep_name);
+
+G_END_DECLS
+
+#endif

Modified: branches/V4-branch/providers/postgres/gda-postgres-recordset.c
==============================================================================
--- branches/V4-branch/providers/postgres/gda-postgres-recordset.c	(original)
+++ branches/V4-branch/providers/postgres/gda-postgres-recordset.c	Wed Feb 20 20:36:04 2008
@@ -1,12 +1,8 @@
 /* GDA Postgres provider
- * Copyright (C) 1998 - 2007 The GNOME Foundation
+ * Copyright (C) 2008 The GNOME Foundation.
  *
  * AUTHORS:
- *      Michael Lausch <michael lausch at>
- *	Rodrigo Moya <rodrigo gnome-db org>
- *      Vivien Malerba <malerba gnome-db org>
- *      Gonzalo Paniagua Javier <gonzalo gnome-db org>
- *      Bas Driessen <bas driessen xobas com>
+ *      TO_ADD: your name and email
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -24,631 +20,1016 @@
  * Boston, MA 02111-1307, USA.
  */
 
-#include <glib/gi18n-lib.h>
-#include <libgda/gda-data-model.h>
-#include <libgda/gda-data-model-private.h>
+#include <stdarg.h>
 #include <string.h>
+#include <glib/gi18n-lib.h>
+#include <libgda/gda-util.h>
+#include <libgda/gda-connection-private.h>
 #include "gda-postgres.h"
 #include "gda-postgres-recordset.h"
-
-#ifdef PARENT_TYPE
-#undef PARENT_TYPE
+#include "gda-postgres-provider.h"
+#include "gda-postgres-blob-op.h"
+#include "gda-postgres-util.h"
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
 #endif
 
-#define PARENT_TYPE GDA_TYPE_DATA_MODEL_HASH
-
-struct _GdaPostgresRecordsetPrivate {
-	GdaConnection *cnc;
-	PGresult      *pg_res;
-
-	GType         *column_types;
-	gint           ncolumns;
-	gint           nrows;
-
-	gchar         *table_name;
-};
+#define _GDA_PSTMT(x) ((GdaPStmt*)(x))
 
 static void gda_postgres_recordset_class_init (GdaPostgresRecordsetClass *klass);
 static void gda_postgres_recordset_init       (GdaPostgresRecordset *recset,
 					       GdaPostgresRecordsetClass *klass);
-static void gda_postgres_recordset_finalize   (GObject *object);
+static void gda_postgres_recordset_dispose   (GObject *object);
+
+static void gda_postgres_recordset_set_property (GObject *object,
+						 guint param_id,
+						 const GValue *value,
+						 GParamSpec *pspec);
+static void gda_postgres_recordset_get_property (GObject *object,
+						 guint param_id,
+						 GValue *value,
+						 GParamSpec *pspec);
+
+/* virtual methods */
+static gint     gda_postgres_recordset_fetch_nb_rows (GdaPModel *model);
+static gboolean gda_postgres_recordset_fetch_random (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error);
+static gboolean gda_postgres_recordset_store_all (GdaPModel *model, GError **error);
+static gboolean gda_postgres_recordset_fetch_next (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error);
+static gboolean gda_postgres_recordset_fetch_prev (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error);
+static gboolean gda_postgres_recordset_fetch_at (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error);
+
+/* static helper functions */
+static void make_point (GdaGeometricPoint *point, const gchar *value);
+static void make_time (GdaTime *timegda, const gchar *value);
+static void make_timestamp (GdaTimestamp *timestamp, const gchar *value);
+static void set_value (GdaConnection *cnc, GValue *value, GType type, const gchar *thevalue, gboolean isNull, gint length);
+
+static GdaPRow *new_row_from_pg_res (GdaPostgresRecordset *imodel, gint pg_res_rownum);
+static gboolean row_is_in_current_pg_res (GdaPostgresRecordset *model, gint row);
+static gboolean fetch_next_chunk (GdaPostgresRecordset *model, gboolean *fetch_error, GError **error);
+static gboolean fetch_prev_chunk (GdaPostgresRecordset *model, gboolean *fetch_error, GError **error);
+static gboolean fetch_row_number_chunk (GdaPostgresRecordset *model, int row_index, gboolean *fetch_error, GError **error);
 
-static const GValue *gda_postgres_recordset_get_value_at    (GdaDataModelRow *model, gint col, gint row);
-static gint gda_postgres_recordset_get_n_rows 		      (GdaDataModelRow *model);
-static GdaRow *gda_postgres_recordset_get_row 	      (GdaDataModelRow *model, gint rownum, GError **error);
-static gboolean gda_postgres_recordset_append_row	      (GdaDataModelRow *model, GdaRow *row, GError **error);
-static gboolean gda_postgres_recordset_remove_row 	      (GdaDataModelRow *model, GdaRow *row, GError **error);
-static gboolean gda_postgres_recordset_update_row 	      (GdaDataModelRow *model, GdaRow *row, GError **error);
 
+struct _GdaPostgresRecordsetPrivate {
+	GdaConnection    *cnc;
+
+	/* random access attributes */
+	PGresult         *pg_res;
+
+	/* cursor access attributes */
+	GdaPRow          *tmp_row; /* used to store a reference to the last #GdaPRow returned */
+	gchar            *cursor_name;
+	PGconn           *pconn;
+	gint              chunk_size; /* Number of rows to fetch at a time when iterating forward or backwards. */
+        gint              chunks_read; /* Effectively equal to the number of times that we have iterated forwards or backwards. */
+        
+        /* Pg cursor's information */
+        gint              pg_pos; /* from G_MININT to G_MAXINT */
+        gint              pg_res_size; /* The number of rows in the current chunk - usually equal to chunk_size when iterating forward or backward. */
+        gint              pg_res_inf; /* The row number of the first row in the current chunk. Don't use if (@pg_res_size <= 0). */
+};
 static GObjectClass *parent_class = NULL;
 
-/*
- * Private functions
- */
+/* properties */
+enum
+{
+        PROP_0,
+        PROP_CHUNCK_SIZE,
+        PROP_CHUNCKS_READ
+};
 
 /*
  * Object init and finalize
  */
 static void
-gda_postgres_recordset_init (GdaPostgresRecordset *recset,
-			     GdaPostgresRecordsetClass *klass)
+gda_postgres_recordset_init (GdaPostgresRecordset *recset, GdaPostgresRecordsetClass *klass)
 {
 	g_return_if_fail (GDA_IS_POSTGRES_RECORDSET (recset));
-
 	recset->priv = g_new0 (GdaPostgresRecordsetPrivate, 1);
+	recset->priv->cnc = NULL;
+
+	recset->priv->pg_res = NULL;
+        recset->priv->pg_pos = G_MININT;
+        recset->priv->pg_res_size = 0;
+
+	recset->priv->chunk_size = 10;
+        recset->priv->chunks_read = 0;
 }
 
 static void
 gda_postgres_recordset_class_init (GdaPostgresRecordsetClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
-	GdaDataModelRowClass *model_class = GDA_DATA_MODEL_ROW_CLASS (klass);
+	GdaPModelClass *pmodel_class = GDA_PMODEL_CLASS (klass);
 
 	parent_class = g_type_class_peek_parent (klass);
 
-	object_class->finalize = gda_postgres_recordset_finalize;
-	model_class->get_n_rows = gda_postgres_recordset_get_n_rows;
-	model_class->get_value_at = gda_postgres_recordset_get_value_at;
-	model_class->get_row = gda_postgres_recordset_get_row;
-	model_class->append_row = gda_postgres_recordset_append_row;
-	model_class->remove_row = gda_postgres_recordset_remove_row;
-	model_class->update_row = gda_postgres_recordset_update_row;
+	object_class->dispose = gda_postgres_recordset_dispose;
+	pmodel_class->fetch_nb_rows = gda_postgres_recordset_fetch_nb_rows;
+	pmodel_class->fetch_random = gda_postgres_recordset_fetch_random;
+	pmodel_class->store_all = gda_postgres_recordset_store_all;
+
+	pmodel_class->fetch_next = gda_postgres_recordset_fetch_next;
+	pmodel_class->fetch_prev = gda_postgres_recordset_fetch_prev;
+	pmodel_class->fetch_at = gda_postgres_recordset_fetch_at;
+
+	/* properties */
+        object_class->set_property = gda_postgres_recordset_set_property;
+        object_class->get_property = gda_postgres_recordset_get_property;
+        g_object_class_install_property (object_class, PROP_CHUNCK_SIZE,
+                                         g_param_spec_int ("chunk_size", _("Number of rows fetched at a time"), NULL,
+                                                           1, G_MAXINT - 1, 10,
+                                                           G_PARAM_CONSTRUCT | G_PARAM_READABLE | G_PARAM_WRITABLE));
+        g_object_class_install_property (object_class, PROP_CHUNCKS_READ,
+                                         g_param_spec_int ("chunks_read",
+                                                           _("Number of rows chunks read since the object creation"), NULL,
+                                                           0, G_MAXINT - 1, 0,
+                                                           G_PARAM_READABLE));
 }
 
 static void
-gda_postgres_recordset_finalize (GObject * object)
+gda_postgres_recordset_dispose (GObject *object)
 {
 	GdaPostgresRecordset *recset = (GdaPostgresRecordset *) object;
 
 	g_return_if_fail (GDA_IS_POSTGRES_RECORDSET (recset));
 
-	if (recset->priv->pg_res != NULL) {
-		PQclear (recset->priv->pg_res);
-		recset->priv->pg_res = NULL;
+	if (recset->priv) {
+		if (recset->priv->tmp_row)
+			g_object_unref (recset->priv->tmp_row);
+
+		if (recset->priv->cnc) 
+			g_object_unref (recset->priv->cnc);
+
+		if (recset->priv->pg_res)
+			PQclear (recset->priv->pg_res);
+
+		if (recset->priv->cursor_name) {
+			gchar *str;
+			PGresult *pg_res;
+			str = g_strdup_printf ("CLOSE %s", recset->priv->cursor_name);
+			pg_res = PQexec (recset->priv->pconn, str);
+			g_free (str);
+			PQclear (pg_res);
+			g_free (recset->priv->cursor_name);
+		}
+
+		g_free (recset->priv);
+		recset->priv = NULL;
 	}
 
-	g_free (recset->priv->column_types);
-	recset->priv->column_types = NULL;
-	g_free (recset->priv);
-	recset->priv = NULL;
+	parent_class->dispose (object);
+}
 
-	parent_class->finalize (object);
+static void
+gda_postgres_recordset_set_property (GObject *object,
+				     guint param_id,
+				     const GValue *value,
+				     GParamSpec *pspec)
+{
+        GdaPostgresRecordset *model = (GdaPostgresRecordset *) object;
+        if (model->priv) {
+                switch (param_id) {
+                case PROP_CHUNCK_SIZE:
+                        model->priv->chunk_size = g_value_get_int (value);
+                        break;
+                default:
+                        break;
+                }
+        }
 }
 
-static GdaRow *
-get_row (GdaDataModel *model, GdaPostgresRecordsetPrivate *priv, gint rownum, GError **error)
+static void
+gda_postgres_recordset_get_property (GObject *object,
+				     guint param_id,
+				     GValue *value,
+				     GParamSpec *pspec)
 {
-	gchar *thevalue;
-	GType ftype;
-	gboolean isNull;
-	GValue *value;
-	GdaRow *row;
-	gint i;
-	gchar *id;
-	gint length;
-	
-	row = gda_row_new (model, priv->ncolumns);
-	for (i = 0; i < priv->ncolumns; i++) {
-		thevalue = PQgetvalue (priv->pg_res, rownum, i);
-		length = PQgetlength (priv->pg_res, rownum, i);
-		ftype = priv->column_types [i];
-		isNull = thevalue && *thevalue != '\0' ? FALSE : PQgetisnull (priv->pg_res, rownum, i);
-		value = (GValue *) gda_row_get_value (row, i);
-		gda_postgres_set_value (priv->cnc, value, ftype, thevalue, isNull, length);
-	}
-
-	gda_row_set_number (row, rownum);
-	id = g_strdup_printf ("%d", rownum);
-   	/* Use oid or figure out primary keys ? could use libsql to add oid to every query. */
-	gda_row_set_id (row, id); /* FIXME: by now, the rowid is just the row number */
-	g_free (id);
-	return row;
+        GdaPostgresRecordset *model = (GdaPostgresRecordset *) object;
+        if (model->priv) {
+                switch (param_id) {
+                case PROP_CHUNCK_SIZE:
+                        g_value_set_int (value, model->priv->chunk_size);
+                        break;
+                case PROP_CHUNCKS_READ:
+                        g_value_set_int (value, model->priv->chunks_read);
+                        break;
+                default:
+                        break;
+                }
+        }
 }
 
 /*
- * Overrides
+ * Public functions
  */
 
-static GdaRow *
-gda_postgres_recordset_get_row (GdaDataModelRow *model, gint row, GError **error)
+GType
+gda_postgres_recordset_get_type (void)
 {
-	GdaPostgresRecordset *recset = (GdaPostgresRecordset *) model;
-	GdaPostgresRecordsetPrivate *priv_data;
-	GdaRow *row_list;
-	
-	g_return_val_if_fail (GDA_IS_POSTGRES_RECORDSET (recset), NULL);
-	g_return_val_if_fail (recset->priv != NULL, 0);
-
-	row_list = (GdaRow *) GDA_DATA_MODEL_ROW_CLASS (parent_class)->get_row (model, row, 
-										error);
-	if (row_list != NULL)
-		return row_list;
-
-	priv_data = recset->priv;
-	if (!priv_data->pg_res) {
-		gda_connection_add_event_string (priv_data->cnc,
-						 _("Invalid PostgreSQL handle"));
-		return NULL;
-	}
-
-	if (row == priv_data->nrows)
-		return NULL; /* For the last row don't add an error. */
+	static GType type = 0;
 
-	if (row < 0 || row > priv_data->nrows) {
-		gda_connection_add_event_string (priv_data->cnc,
-						_("Row number out of range"));
-		return NULL;
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo info = {
+			sizeof (GdaPostgresRecordsetClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) gda_postgres_recordset_class_init,
+			NULL,
+			NULL,
+			sizeof (GdaPostgresRecordset),
+			0,
+			(GInstanceInitFunc) gda_postgres_recordset_init
+		};
+		type = g_type_register_static (GDA_TYPE_PMODEL, "GdaPostgresRecordset", &info, 0);
 	}
 
-	row_list = get_row (GDA_DATA_MODEL (model), priv_data, row, error);
-	gda_data_model_hash_insert_row (GDA_DATA_MODEL_HASH (model),
-					row, row_list);
-
-	return row_list;
+	return type;
 }
 
-static gboolean
-gda_postgres_recordset_append_row (GdaDataModelRow *model, GdaRow *row, GError **error)
+static void
+finish_prep_stmt_init (PostgresConnectionData *cdata, GdaPostgresPStmt *ps, PGresult *pg_res, GType *col_types)
 {
-	GdaPostgresRecordset *recset = (GdaPostgresRecordset *) model;
-	GdaPostgresRecordsetPrivate *priv_data;
-	GString *sql, *sql_value;
-	gchar *cur_val;
-	gint i;
-	PGresult *pg_res;
-	GdaPostgresConnectionData *cnc_priv_data;
-	PGconn *pg_conn;
-
-	g_return_val_if_fail (GDA_IS_POSTGRES_RECORDSET (recset), FALSE);
-	g_return_val_if_fail (row != NULL, FALSE);
-	g_return_val_if_fail (gda_data_model_is_updatable (GDA_DATA_MODEL (model)), FALSE);
-	g_return_val_if_fail (recset->priv != NULL, FALSE);
-	priv_data = recset->priv;
-	pg_res = priv_data->pg_res;
-	cnc_priv_data = g_object_get_data (G_OBJECT (priv_data->cnc),
-					   OBJECT_DATA_POSTGRES_HANDLE);
-	pg_conn = cnc_priv_data->pconn;
-
-	/* checks if the table name has been guessed */
-	if (priv_data->table_name == NULL) {
-		gda_connection_add_event_string (priv_data->cnc,
-						 _("Table name could not be guessed."));
-		return FALSE;
+	/* make sure @ps reports the correct number of columns */
+        if (_GDA_PSTMT (ps)->ncols < 0) {
+		if (pg_res)
+			_GDA_PSTMT (ps)->ncols = PQnfields (pg_res);
+		else
+			_GDA_PSTMT (ps)->ncols = 0;
 	}
 
-	/* checks for correct number of columns */
-        if (priv_data->ncolumns != gda_row_get_length (row)) {
-                gda_connection_add_event_string (priv_data->cnc,
-                                                _("Attempt to insert a row with an invalid number of columns"));
-                return FALSE;
+        /* completing @ps if not yet done */
+        if (!_GDA_PSTMT (ps)->types && (_GDA_PSTMT (ps)->ncols > 0)) {
+		/* create prepared statement's columns */
+		GSList *list;
+		gint i;
+		for (i = 0; i < _GDA_PSTMT (ps)->ncols; i++)
+			_GDA_PSTMT (ps)->tmpl_columns = g_slist_prepend (_GDA_PSTMT (ps)->tmpl_columns, 
+									 gda_column_new ());
+		_GDA_PSTMT (ps)->tmpl_columns = g_slist_reverse (_GDA_PSTMT (ps)->tmpl_columns);
+
+		/* create prepared statement's types */
+		_GDA_PSTMT (ps)->types = g_new0 (GType, _GDA_PSTMT (ps)->ncols); /* all types are initialized to GDA_TYPE_NULL */
+		if (col_types) {
+			for (i = 0; ; i++) {
+				if (col_types [i] > 0) {
+					if (col_types [i] == G_TYPE_NONE)
+						break;
+					if (i >= _GDA_PSTMT (ps)->ncols)
+						g_warning (_("Column %d is out of range (0-%d), ignoring its specified type"), i,
+							   _GDA_PSTMT (ps)->ncols - 1);
+					else
+						_GDA_PSTMT (ps)->types [i] = col_types [i];
+				}
+			}
+		}
+		
+		/* fill GdaColumn's data */
+		for (i=0, list = _GDA_PSTMT (ps)->tmpl_columns; 
+		     i < GDA_PSTMT (ps)->ncols; 
+		     i++, list = list->next) {
+			GdaColumn *column;
+			Oid postgres_type;
+			GType gtype;
+			column = GDA_COLUMN (list->data);
+			postgres_type = PQftype (pg_res, i);
+			gtype = _gda_postgres_type_oid_to_gda (cdata, postgres_type);
+			_GDA_PSTMT (ps)->types [i] = gtype;
+			gda_column_set_g_type (column, gtype);
+			gda_column_set_name (column, PQfname (pg_res, i));
+			gda_column_set_title (column, PQfname (pg_res, i));
+			gda_column_set_scale (column, (gtype == G_TYPE_DOUBLE) ? DBL_DIG :
+					      (gtype == G_TYPE_FLOAT) ? FLT_DIG : 0);
+			gda_column_set_defined_size (column, PQfsize (pg_res, i));
+			gda_column_set_references (column, "");
+
+			/*
+			  FIXME: Use @cnc's associated GdaMetaStore to get the following information:
+			  gda_column_set_references (column, "");
+			  gda_column_set_table (column, ...);
+			  gda_column_set_primary_key (column, ...);
+			  gda_column_set_unique_key (column, ...);
+			  gda_column_set_allow_null (column, ...);
+			  gda_column_set_auto_increment (column, ...);
+			*/
+		}
         }
+}
 
-	/* Prepare the SQL command */
-	sql = g_string_new ("INSERT INTO ");
-	g_string_append_printf (sql, "%s (",  priv_data->table_name);
+GdaDataModel *
+gda_postgres_recordset_new_random (GdaConnection *cnc, GdaPostgresPStmt *ps, PGresult *pg_res, GType *col_types)
+{
+	GdaPostgresRecordset *model;
+        PostgresConnectionData *cdata;
 
-	sql_value = g_string_new ("VALUES (");
+        g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+        g_return_val_if_fail (ps, NULL);
 
-	for (i = 0; i < priv_data->ncolumns; i++) {
+	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata)
+		return NULL;
 
-		if (i != 0)
-		{
-			sql = g_string_append (sql, ", ");
-			sql_value = g_string_append (sql_value, ", ");
-		}
+	/* finish prepared statement's init */
+	finish_prep_stmt_init (cdata, ps, pg_res, col_types);
 
-		sql = g_string_append (sql, "\"");
-		sql = g_string_append (sql, PQfname (priv_data->pg_res, i));
-		sql = g_string_append (sql, "\"");
+	/* create data model */
+        model = g_object_new (GDA_TYPE_POSTGRES_RECORDSET, "prepared-stmt", ps, 
+			      "model-usage", GDA_DATA_MODEL_ACCESS_RANDOM, NULL);
+        model->priv->cnc = cnc;
+	g_object_ref (cnc);
+	model->priv->pg_res = pg_res;
+	((GdaPModel*) model)->advertized_nrows = PQntuples (model->priv->pg_res);
 
-		cur_val = gda_value_stringify (gda_row_get_value ((GdaRow *) row, i));
-		sql_value = g_string_append (sql_value, "'");
-		sql_value = g_string_append (sql_value, cur_val);
-		sql_value = g_string_append (sql_value, "'");
-		g_free (cur_val);
-	}
+        return GDA_DATA_MODEL (model);
+}
 
-	/* concatenate SQL statement */
-        sql = g_string_append (sql, ") ");
-	sql = g_string_append (sql, sql_value->str);
-	sql = g_string_append (sql, ")");
+/*
+ * Takes ownership of @cursor_name
+ */
+GdaDataModel *
+gda_postgres_recordset_new_cursor (GdaConnection *cnc, GdaPostgresPStmt *ps, gchar *cursor_name, GType *col_types)
+{
+	GdaPostgresRecordset *model;
+        PostgresConnectionData *cdata;
 
-	/* execute the SQL query */
-	pg_res = gda_postgres_PQexec_wrap (priv_data->cnc, pg_conn, sql->str);
+        g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+        g_return_val_if_fail (ps, NULL);
 
-	g_string_free (sql, TRUE);
-        g_string_free (sql_value, TRUE);
+	cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata)
+		return NULL;
 
-	if (pg_res != NULL) {
-		/* update ok! */
-		if (PQresultStatus (pg_res) != PGRES_COMMAND_OK) {
-			gda_postgres_make_error (priv_data->cnc, pg_conn, pg_res);
+	/* Fetch the 1st row to finish initialization of @ps */
+	gchar *str;
+	int status;
+	PGresult *pg_res;
+	
+	str = g_strdup_printf ("FETCH FORWARD 1 FROM %s;", cursor_name);
+	pg_res = PQexec (cdata->pconn, str);
+	g_free (str);
+	status = PQresultStatus (pg_res);
+	if (!pg_res || (PQresultStatus (pg_res) != PGRES_TUPLES_OK)) {
+		_gda_postgres_make_error (cdata->cnc, cdata->pconn, pg_res, NULL);
+		if (pg_res) {
 			PQclear (pg_res);
-			return FALSE;
+			pg_res = NULL;
 		}
-		PQclear (pg_res);
 	}
-	else
-		gda_postgres_make_error (priv_data->cnc, pg_conn, NULL);
+	else {
+		PGresult *tmp_res;
+		str = g_strdup_printf ("MOVE BACKWARD 1 FROM %s;", cursor_name);
+		tmp_res = PQexec (cdata->pconn, str);
+		g_free (str);
+		if (tmp_res)
+			PQclear (tmp_res);
+	}
+
+	/* finish prepared statement's init */
+	finish_prep_stmt_init (cdata, ps, pg_res, col_types);
+	if (pg_res)
+		PQclear (pg_res);
+
+	/* create model */
+	model = g_object_new (GDA_TYPE_POSTGRES_RECORDSET, "prepared-stmt", ps, "model-usage", 
+			      GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD | GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD, NULL);
+        model->priv->cnc = cnc;
+	g_object_ref (cnc);
+	model->priv->pconn = cdata->pconn;
+	model->priv->cursor_name = cursor_name;
+	gboolean fetch_error;
+	fetch_next_chunk (model, &fetch_error, NULL);
+
+	return GDA_DATA_MODEL (model);
+}
+
+/*
+ * Get the number of rows in @model, if possible
+ */
+static gint
+gda_postgres_recordset_fetch_nb_rows (GdaPModel *model)
+{
+	GdaPostgresRecordset *imodel;
+
+	imodel = GDA_POSTGRES_RECORDSET (model);
+	if (model->advertized_nrows >= 0)
+		return model->advertized_nrows;
+
+	/* use C API to determine number of rows,if possible */
+	if (!imodel->priv->cursor_name)
+		model->advertized_nrows = PQntuples (imodel->priv->pg_res);
+
+	return model->advertized_nrows;
+}
+
+/*
+ * Create a new filled #GdaPRow object for the row at position @rownum.
+ *
+ * Each new #GdaPRow created is "given" to the #GdaPModel implementation using gda_pmodel_take_row ().
+ */
+static gboolean
+gda_postgres_recordset_fetch_random (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error)
+{
+	GdaPostgresRecordset *imodel = (GdaPostgresRecordset *) model;
 
-	/* append row in hash table */
-	if (! GDA_DATA_MODEL_ROW_CLASS (parent_class)->append_row (model, row, error)) {
-		gda_postgres_make_error (priv_data->cnc, pg_conn, pg_res);
+	if (*prow)
+		return TRUE;
+
+	if (!imodel->priv->pg_res) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_INTERNAL_ERROR,
+			     _("Internal error"));
 		return FALSE;
 	}
 
+	*prow = new_row_from_pg_res (imodel, rownum);
+	gda_pmodel_take_row (model, *prow, rownum);
+
+	if (model->nb_stored_rows == model->advertized_nrows) {
+		/* all the rows have been converted from PGresult to GdaPRow objects => we can
+		 * discard the PGresult */
+		PQclear (imodel->priv->pg_res);
+		imodel->priv->pg_res = NULL;
+	}
+
 	return TRUE;
 }
 
+/*
+ * Create and "give" filled #GdaPRow object for all the rows in the model
+ */
 static gboolean
-gda_postgres_recordset_remove_row (GdaDataModelRow *model, GdaRow *row, GError **error)
+gda_postgres_recordset_store_all (GdaPModel *model, GError **error)
 {
-	GdaPostgresRecordset *recset = (GdaPostgresRecordset *) model;
-	GdaPostgresRecordsetPrivate *priv_data;
-	gint colnum, uk;
-	PGresult *pg_res, *pg_rm_res;
-	gchar *query, *query_where, *tmp;
-	GdaPostgresConnectionData *cnc_priv_data;
-	PGconn *pg_conn;
-	gboolean status = FALSE;
-
-	g_return_val_if_fail (GDA_IS_POSTGRES_RECORDSET (recset), FALSE);
-	g_return_val_if_fail (recset->priv != NULL, FALSE);
-	g_return_val_if_fail (row != NULL, FALSE);
-
-	priv_data = recset->priv;
-	pg_res = priv_data->pg_res;
-	cnc_priv_data = g_object_get_data (G_OBJECT (priv_data->cnc),
-					   OBJECT_DATA_POSTGRES_HANDLE);
-	pg_conn = cnc_priv_data->pconn;
-
-	/* checks if the given row belongs to the given model */
-	if (gda_row_get_model ((GdaRow *) row) != GDA_DATA_MODEL (model)) {
-		gda_connection_add_event_string (priv_data->cnc,
-						_("Given row doesn't belong to the model."));
+	GdaPostgresRecordset *imodel = (GdaPostgresRecordset*) model;
+	gint i;
+	
+	if (!imodel->priv->pg_res) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_INTERNAL_ERROR,
+			     _("Internal error"));
 		return FALSE;
 	}
 
-	/* checks if the table name has been guessed */
-	if (priv_data->table_name == NULL) {
-		gda_connection_add_event_string (priv_data->cnc,
-						_("Table name could not be guessed."));
-		return FALSE;
+	for (i = 0; i < model->advertized_nrows; i++) {
+		GdaPRow *prow;
+		if (! gda_postgres_recordset_fetch_random (model, &prow, i, error))
+			return FALSE;
 	}
+	return TRUE;
+}
 
-	query_where = g_strdup ("WHERE TRUE ");
+/*
+ * Create a new filled #GdaPRow object for the next cursor row
+ *
+ * Each new #GdaPRow created is referenced only by imodel->priv->tmp_row (the #GdaPModel implementation
+ * never keeps a reference to it). Before a new #GdaPRow gets created, the previous one, if set, is discarded.
+ */
+static gboolean
+gda_postgres_recordset_fetch_next (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error)
+{
+	GdaPostgresRecordset *imodel = (GdaPostgresRecordset*) model;
+
+	if (*prow)
+		return TRUE;
 
-	for (colnum = uk = 0;
-	     colnum != gda_data_model_get_n_columns (GDA_DATA_MODEL(model));
-	     colnum++)
-	{
-		GdaColumn *attrs = gda_data_model_describe_column (GDA_DATA_MODEL(model), colnum);
-		const gchar *column_name = PQfname (pg_res, colnum);
-		gchar *curval = gda_value_stringify (gda_row_get_value ((GdaRow *) row, colnum));
-
-		/* unique column: we will use it as an index */
-		if (gda_column_get_primary_key (attrs) ||
-		    gda_column_get_unique_key (attrs))
-		{
-			/* fills the 'where' part of the update command */
-			tmp = g_strdup_printf ("AND \"%s\" = '%s' ",
-					       column_name,
-					       curval);
-			query_where = g_strconcat (query_where, tmp, NULL);
-			g_free (tmp);
-			uk++;
-		}
-
-		g_free (curval);
-	}
-
-	if (uk == 0) {
-		gda_connection_add_event_string (priv_data->cnc,
-						_("Model doesn't have at least one unique key."));
+	if (imodel->priv->tmp_row) {
+		g_object_unref (imodel->priv->tmp_row);
+		imodel->priv->tmp_row = NULL;
+	}
+
+	if (row_is_in_current_pg_res (imodel, rownum)) {
+		*prow = new_row_from_pg_res (imodel, rownum - imodel->priv->pg_res_inf);
+		imodel->priv->tmp_row = *prow;
+		return TRUE;
 	}
 	else {
-		/* build the delete command */
-		query = g_strdup_printf ("DELETE FROM %s %s",
-					 priv_data->table_name,
-					 query_where);
-
-		/* remove the row */
-		pg_rm_res = gda_postgres_PQexec_wrap (priv_data->cnc, pg_conn, query);
-		g_free (query);
-
-		if (pg_rm_res != NULL) {
-			/* removal ok! */
-			if (PQresultStatus (pg_rm_res) == PGRES_COMMAND_OK)
-				status = TRUE;
-			else
-				gda_postgres_make_error (priv_data->cnc, pg_conn, pg_rm_res);
-			PQclear (pg_rm_res);
+		gboolean fetch_error = FALSE;
+		if (fetch_next_chunk (imodel, &fetch_error, error)) {
+			*prow = new_row_from_pg_res (imodel, rownum - imodel->priv->pg_res_inf);
+			imodel->priv->tmp_row = *prow;
+			return TRUE;
 		}
 		else
-			gda_postgres_make_error (priv_data->cnc, pg_conn, NULL);
+			return !fetch_error;
 	}
-
-	g_free (query_where);
-
-	/* remove entry from data model */
-	if (status == TRUE)
-		status = GDA_DATA_MODEL_ROW_CLASS (parent_class)->remove_row (model, row, error);
-
-	return status;
 }
 
+/*
+ * Create a new filled #GdaPRow object for the previous cursor row
+ *
+ * Each new #GdaPRow created is referenced only by imodel->priv->tmp_row (the #GdaPModel implementation
+ * never keeps a reference to it). Before a new #GdaPRow gets created, the previous one, if set, is discarded.
+ */
 static gboolean
-gda_postgres_recordset_update_row (GdaDataModelRow *model, GdaRow *row, GError **error)
+gda_postgres_recordset_fetch_prev (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error)
 {
-	GdaPostgresRecordset *recset = (GdaPostgresRecordset *) model;
-	GdaPostgresRecordsetPrivate *priv_data;
-	gint colnum, rownum, uk, nuk;
-	PGresult *pg_res, *pg_upd_res;
-	gchar *query, *query_where, *query_set, *tmp;
-	gchar *oldval, *newval;
-	const gchar *column_name;
-	GdaPostgresConnectionData *cnc_priv_data;
-	PGconn *pg_conn;
-	gboolean status = FALSE;
-
-	g_return_val_if_fail (GDA_IS_POSTGRES_RECORDSET (recset), FALSE);
-	g_return_val_if_fail (recset->priv != NULL, FALSE);
-	g_return_val_if_fail (row != NULL, FALSE);
-	priv_data = recset->priv;
-	pg_res = priv_data->pg_res;
-	cnc_priv_data = g_object_get_data (G_OBJECT (priv_data->cnc),
-					   OBJECT_DATA_POSTGRES_HANDLE);
-	pg_conn = cnc_priv_data->pconn;
-	
-	/* checks if the given row belongs to the given model */
-	if (gda_row_get_model ((GdaRow *) row) != GDA_DATA_MODEL (model)) {
-		gda_connection_add_event_string (priv_data->cnc,
-						_("Given row doesn't belong to the model."));
-		return FALSE;
-	}
+	GdaPostgresRecordset *imodel = (GdaPostgresRecordset*) model;
 
-	/* checks if the table name has been guessed */
-	if (priv_data->table_name == NULL) {
-		gda_connection_add_event_string (priv_data->cnc,
-						_("Table name could not be guessed."));
-		return FALSE;
-	}
-
-	rownum = gda_row_get_number ((GdaRow *) row);
+	if (*prow)
+		return TRUE;
 
-	query_where = g_strdup ("WHERE TRUE ");
-	query_set = g_strdup ("SET ");
+	if (imodel->priv->tmp_row) {
+		g_object_unref (imodel->priv->tmp_row);
+		imodel->priv->tmp_row = NULL;
+	}
 
-	for (colnum = uk = nuk = 0;
-	     colnum != gda_data_model_get_n_columns (GDA_DATA_MODEL (model));
-	     colnum++) 
-	{
-		GdaColumn *attrs = gda_data_model_describe_column (GDA_DATA_MODEL (model), colnum);
-		column_name = PQfname (pg_res, colnum);
-		newval = gda_value_stringify (gda_row_get_value ((GdaRow *) row, colnum));
-
-		/* for data from mysql result we can retrieve original values to avoid
-		   unique columns to be updated */
-		if (rownum < priv_data->nrows)
-			oldval = PQgetvalue (pg_res, gda_row_get_number ((GdaRow *) row), colnum);
+	if (row_is_in_current_pg_res (imodel, rownum)) {
+		*prow = new_row_from_pg_res (imodel, rownum - imodel->priv->pg_res_inf);
+		imodel->priv->tmp_row = *prow;
+		return TRUE;
+	}
+	else {
+		gboolean fetch_error = FALSE;
+		if (fetch_prev_chunk (imodel, &fetch_error, error)) {
+			*prow = new_row_from_pg_res (imodel, rownum - imodel->priv->pg_res_inf);
+			imodel->priv->tmp_row = *prow;
+			return TRUE;
+		}
 		else
-			oldval = newval;
+			return !fetch_error;
+	}
+}
 
-		/* unique column: we won't update it, but we will use it as
-		   an index */
-		if (gda_column_get_primary_key (attrs) ||
-		    gda_column_get_unique_key (attrs)) 
-		{
-			/* checks if it hasn't be modified anyway */
-			if (oldval == NULL ||
-	   		    newval == NULL ||
-			    strcmp (oldval, newval) != 0)
-			    	continue;
-
-			/* fills the 'where' part of the update command */
-			tmp = g_strdup_printf ("AND \"%s\" = '%s' ",
-					       column_name,
-					       newval);
-			query_where = g_strconcat (query_where, tmp, NULL);
-			g_free (tmp);
-			uk++;
-		}
-		/* non-unique column: update it */
-		else {
-			/* fills the 'set' part of the update command */
-			tmp = g_strdup_printf ("\"%s\" = '%s', ", 
-					       column_name,
-					       newval);
-			query_set = g_strconcat (query_set, tmp, NULL);
-			g_free (tmp);
-			nuk++;
-		}
+/*
+ * Create a new filled #GdaPRow object for the cursor row at position @rownum
+ *
+ * Each new #GdaPRow created is referenced only by imodel->priv->tmp_row (the #GdaPModel implementation
+ * never keeps a reference to it). Before a new #GdaPRow gets created, the previous one, if set, is discarded.
+ */
+static gboolean
+gda_postgres_recordset_fetch_at (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error)
+{
+	GdaPostgresRecordset *imodel = (GdaPostgresRecordset*) model;
 
-		g_free (newval);
-	}
+	if (*prow)
+		return TRUE;
 
-	if (uk == 0) {
-		gda_connection_add_event_string (priv_data->cnc,
-						_("Model doesn't have at least one non-modified unique key."));
+	if (imodel->priv->tmp_row) {
+		g_object_unref (imodel->priv->tmp_row);
+		imodel->priv->tmp_row = NULL;
 	}
-	else if (nuk == 0) {
-		gda_connection_add_event_string (priv_data->cnc,
-						_("Model doesn't have any non-unique values to update."));
+
+	if (row_is_in_current_pg_res (imodel, rownum)) {
+		*prow = new_row_from_pg_res (imodel, rownum - imodel->priv->pg_res_inf);
+		imodel->priv->tmp_row = *prow;
+		return TRUE;
 	}
 	else {
-		/* remove the last ',' in the SET part */
-		tmp = strrchr (query_set, ',');
-		if (tmp != NULL)
-			*tmp = ' ';
-		
-		/* build the update command */
-		query = g_strdup_printf ("UPDATE %s %s %s", 
-					 priv_data->table_name,
-					 query_set,
-					 query_where);
-	
-		/* update the row */
-		pg_upd_res = gda_postgres_PQexec_wrap (priv_data->cnc, pg_conn, query);
-		g_free (query);
-	
-		if (pg_upd_res != NULL) {
-			/* update ok! */
-			if (PQresultStatus (pg_upd_res) == PGRES_COMMAND_OK)
-				status = TRUE;
-			else
-				gda_postgres_make_error (priv_data->cnc, pg_conn, pg_upd_res);
-			PQclear (pg_upd_res);
+		gboolean fetch_error = FALSE;
+		if (fetch_row_number_chunk (imodel, rownum, &fetch_error, error)) {
+			*prow = new_row_from_pg_res (imodel, rownum - imodel->priv->pg_res_inf);
+			imodel->priv->tmp_row = *prow;
+			return TRUE;
 		}
 		else
-			gda_postgres_make_error (priv_data->cnc, pg_conn, NULL);
+			return !fetch_error;
 	}
-	
-	g_free (query_set);
-	g_free (query_where);
+}
+
+
 
-	/* emit update signals */
-	gda_data_model_row_updated (GDA_DATA_MODEL (model), gda_row_get_number ((GdaRow *) row));
 
-	return status;
+
+
+/*
+ * Static helper functions
+ */
+
+/* Makes a point from a string like "(3.2,5.6)" */
+static void
+make_point (GdaGeometricPoint *point, const gchar *value)
+{
+	value++;
+	point->x = atof (value);
+	value = strchr (value, ',');
+	value++;
+	point->y = atof (value);
 }
 
-static const GValue *
-gda_postgres_recordset_get_value_at (GdaDataModelRow *model, gint col, gint row)
+/* Makes a GdaTime from a string like "12:30:15+01" */
+static void
+make_time (GdaTime *timegda, const gchar *value)
 {
-	GdaPostgresRecordset *recset = (GdaPostgresRecordset *) model;
-	GdaPostgresRecordsetPrivate *priv_data;
-	PGresult *pg_res;
-	GdaRow *row_list;
-	const GValue *value;
+	timegda->hour = atoi (value);
+	value += 3;
+	timegda->minute = atoi (value);
+	value += 3;
+	timegda->second = atoi (value);
+	value += 2;
+	if (*value)
+		timegda->timezone = atoi (value);
+	else
+		timegda->timezone = GDA_TIMEZONE_INVALID;
+}
 
-	g_return_val_if_fail (GDA_IS_POSTGRES_RECORDSET (recset), NULL);
-	g_return_val_if_fail (recset->priv != NULL, 0);
-	
-	value = GDA_DATA_MODEL_ROW_CLASS (parent_class)->get_value_at (model, col, row);
-	if (value != NULL)
-		return value;
-
-	priv_data = recset->priv;
-	pg_res = priv_data->pg_res;
-	if (!pg_res) {
-		gda_connection_add_event_string (priv_data->cnc,
-						 _("Invalid PostgreSQL handle"));
-		return NULL;
-	}
+/* Makes a GdaTimestamp from a string like "2003-12-13 13:12:01.12+01" */
+static void
+make_timestamp (GdaTimestamp *timestamp, const gchar *value)
+{
+	timestamp->year = atoi (value);
+	value += 5;
+	timestamp->month = atoi (value);
+	value += 3;
+	timestamp->day = atoi (value);
+	value += 3;
+	timestamp->hour = atoi (value);
+	value += 3;
+	timestamp->minute = atoi (value);
+	value += 3;
+	timestamp->second = atoi (value);
+	value += 2;
+	if (*value != '.') {
+		timestamp->fraction = 0;
+	} else {
+		gint ndigits = 0;
+		gint64 fraction;
+
+		value++;
+		fraction = atol (value);
+		while (*value && *value != '+') {
+			value++;
+			ndigits++;
+		}
 
-	if (row == priv_data->nrows)
-		return NULL; /* For the last row don't add an error. */
+		while (ndigits < 3) {
+			fraction *= 10;
+			ndigits++;
+		}
 
-	if (row < 0 || row > priv_data->nrows) {
-		gda_connection_add_event_string (priv_data->cnc,
-						_("Row number out of range"));
-		return NULL;
+		while (fraction > 0 && ndigits > 3) {
+			fraction /= 10;
+			ndigits--;
+		}
+		
+		timestamp->fraction = fraction;
 	}
 
-	if (col >= priv_data->ncolumns) {
-		gda_connection_add_event_string (priv_data->cnc,
-						_("Column number out of range"));
-		return NULL;
+	if (*value != '+') {
+		timestamp->timezone = 0;
+	} else {
+		value++;
+		timestamp->timezone = atol (value) * 60 * 60;
 	}
-	
-	row_list = get_row (GDA_DATA_MODEL (model), priv_data, row, NULL);
-	gda_data_model_hash_insert_row (GDA_DATA_MODEL_HASH (model),
-					 row, row_list);
-	return gda_row_get_value (row_list, col);
 }
 
-static gint
-gda_postgres_recordset_get_n_rows (GdaDataModelRow *model)
+static void
+set_value (GdaConnection *cnc, GValue *value, GType type,
+	   const gchar *thevalue, gboolean isNull, gint length)
 {
-	gint parent_row_num;
-	GdaPostgresRecordset *recset = (GdaPostgresRecordset *) model;
-
-	g_return_val_if_fail (GDA_IS_POSTGRES_RECORDSET (model), 0);
-	g_return_val_if_fail (recset->priv != NULL, 0);
-
-	parent_row_num = GDA_DATA_MODEL_ROW_CLASS (parent_class)->get_n_rows (model);
+	if (isNull) {
+		gda_value_set_null (value);
+		return;
+	}
+
+	gda_value_reset_with_type (value, type);
+
+	if (type == G_TYPE_BOOLEAN)
+		g_value_set_boolean (value, (*thevalue == 't') ? TRUE : FALSE);
+	else if (type == G_TYPE_STRING)
+		g_value_set_string (value, thevalue);
+	else if (type == G_TYPE_INT64)
+		g_value_set_int64 (value, atoll (thevalue));
+	else if (type == G_TYPE_ULONG)
+		g_value_set_ulong (value, atoll (thevalue));
+	else if (type == G_TYPE_LONG)
+		g_value_set_ulong (value, atoll (thevalue));
+	else if (type == G_TYPE_INT)
+		g_value_set_int (value, atol (thevalue));
+	else if (type == GDA_TYPE_SHORT)
+		gda_value_set_short (value, atoi (thevalue));
+	else if (type == G_TYPE_FLOAT) {
+		setlocale (LC_NUMERIC, "C");
+		g_value_set_float (value, atof (thevalue));
+		setlocale (LC_NUMERIC, "");
+	}
+	else if (type == G_TYPE_DOUBLE) {
+		setlocale (LC_NUMERIC, "C");
+		g_value_set_double (value, atof (thevalue));
+		setlocale (LC_NUMERIC, "");
+	}
+	else if (type == GDA_TYPE_NUMERIC) {
+		GdaNumeric numeric;
+		numeric.number = g_strdup (thevalue);
+		numeric.precision = 0; /* FIXME */
+		numeric.width = 0; /* FIXME */
+		gda_value_set_numeric (value, &numeric);
+		g_free (numeric.number);
+	}
+	else if (type == G_TYPE_DATE) {
+		GDate *gdate;
+		gdate = g_date_new ();
+		g_date_set_parse (gdate, thevalue);
+		if (!g_date_valid (gdate)) {
+			g_warning (_("Could not parse date '%s', assuming 01/01/0001"), thevalue);
+			g_date_clear (gdate, 1);
+			g_date_set_dmy (gdate, 1, 1, 1);
+		}
+		g_value_take_boxed (value, gdate);
+	}
+	else if (type == GDA_TYPE_GEOMETRIC_POINT) {
+		GdaGeometricPoint point;
+		make_point (&point, thevalue);
+		gda_value_set_geometric_point (value, &point);
+	}
+	else if (type == GDA_TYPE_TIMESTAMP) {
+		GdaTimestamp timestamp;
+		make_timestamp (&timestamp, thevalue);
+		gda_value_set_timestamp (value, &timestamp);
+	}
+	else if (type == GDA_TYPE_TIME) {
+		GdaTime timegda;
+		make_time (&timegda, thevalue);
+		gda_value_set_time (value, &timegda);
+	}
+	else if (type == GDA_TYPE_BINARY) {
+		/*
+		 * Requires PQunescapeBytea in libpq (present since 7.3.x)
+		 */
+		guchar *unescaped;
+                size_t pqlength = 0;
+
+		unescaped = PQunescapeBytea ((guchar*)thevalue, &pqlength);
+		if (unescaped != NULL) {
+			GdaBinary bin;
+			bin.data = unescaped;
+			bin.binary_length = pqlength;
+			gda_value_set_binary (value, &bin);
+			PQfreemem (unescaped);
+		}
+	}
+	else if (type == GDA_TYPE_BLOB) {
+		GdaBlob *blob;
+		GdaBlobOp *op;
+		blob = g_new0 (GdaBlob, 1);
+		op = gda_postgres_blob_op_new_with_id (cnc, thevalue);
+		gda_blob_set_op (blob, op);
+		g_object_unref (op);
 
-	/* if not initialized return number of PQ Tuples */
-	if (parent_row_num == 0)
-		return recset->priv->nrows;
-	else
-		return parent_row_num;
+		gda_value_take_blob (value, blob);
+	}
+	else if (type == G_TYPE_STRING) 
+		g_value_set_string (value, thevalue);
+	else {
+		g_warning ("Type %s not translated for value '%s' => set as string", g_type_name (type), thevalue);
+		gda_value_reset_with_type (value, G_TYPE_STRING);
+		g_value_set_string (value, thevalue);
+	}
 }
 
-/*
- * Public functions
- */
+static gboolean
+row_is_in_current_pg_res (GdaPostgresRecordset *model, gint row)
+{
+	if ((model->priv->pg_res) && (model->priv->pg_res_size > 0) &&
+            (row >= model->priv->pg_res_inf) && (row < model->priv->pg_res_inf + model->priv->pg_res_size))
+                return TRUE;
+        else
+                return FALSE;
+}
 
-GType
-gda_postgres_recordset_get_type (void)
+static GdaPRow *
+new_row_from_pg_res (GdaPostgresRecordset *imodel, gint pg_res_rownum)
 {
-	static GType type = 0;
+	GdaPRow *prow;
+	gchar *thevalue;
+	gboolean isNull;
+	gint col;
 
-	if (G_UNLIKELY (type == 0)) {
-		static const GTypeInfo info = {
-			sizeof (GdaPostgresRecordsetClass),
-			(GBaseInitFunc) NULL,
-			(GBaseFinalizeFunc) NULL,
-			(GClassInitFunc) gda_postgres_recordset_class_init,
-			NULL,
-			NULL,
-			sizeof (GdaPostgresRecordset),
-			0,
-			(GInstanceInitFunc) gda_postgres_recordset_init
-		};
-		type = g_type_register_static (PARENT_TYPE, "GdaPostgresRecordset", &info, 0);
+	prow = gda_prow_new (((GdaPModel*) imodel)->prep_stmt->ncols);
+	for (col = 0; col < ((GdaPModel*) imodel)->prep_stmt->ncols; col++) {
+		thevalue = PQgetvalue (imodel->priv->pg_res, pg_res_rownum, col);
+		isNull = thevalue && *thevalue != '\0' ? FALSE : PQgetisnull (imodel->priv->pg_res, pg_res_rownum, col);
+		set_value (imodel->priv->cnc, 
+			   gda_prow_get_value (prow, col), 
+			   ((GdaPModel*) imodel)->prep_stmt->types [col], 
+			   thevalue, isNull, 
+			   PQgetlength (imodel->priv->pg_res, pg_res_rownum, col));
 	}
-	return type;
+	return prow;
 }
 
-GdaDataModel *
-gda_postgres_recordset_new (GdaConnection *cnc, PGresult *pg_res)
+static gboolean
+fetch_next_chunk (GdaPostgresRecordset *model, gboolean *fetch_error, GError **error)
 {
-	GdaPostgresRecordset *model;
-	GdaPostgresConnectionData *cnc_priv_data;
-	gchar *cmd_tuples;
-	gchar *endptr [1];
-	gint i;
+	if (model->priv->pg_res) {
+		PQclear (model->priv->pg_res);
+		model->priv->pg_res = NULL;
+	}
+	*fetch_error = FALSE;
 
-	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-	g_return_val_if_fail (pg_res != NULL, NULL);
+	if (model->priv->pg_pos == G_MAXINT) 
+		return FALSE;
 
-	cnc_priv_data = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_POSTGRES_HANDLE);
+	gchar *str;
+	gboolean retval = TRUE;
+	int status;
+
+	str = g_strdup_printf ("FETCH FORWARD %d FROM %s;",
+			       model->priv->chunk_size, model->priv->cursor_name);
+#ifdef GDA_PG_DEBUG
+	g_print ("QUERY: %s\n", str);
+#endif
+        model->priv->pg_res = PQexec (model->priv->pconn, str);
+        g_free (str);
+        status = PQresultStatus (model->priv->pg_res);
+	model->priv->chunks_read ++;
+        if (status != PGRES_TUPLES_OK) {
+		_gda_postgres_make_error (model->priv->cnc, model->priv->pconn, model->priv->pg_res, error);
+                PQclear (model->priv->pg_res);
+                model->priv->pg_res = NULL;
+		model->priv->pg_res_size = 0;
+                retval = FALSE;
+		*fetch_error = TRUE;
+        }
+	else {
+#ifdef GDA_PG_DEBUG
+		dump_pg_res (model->priv->pg_res);
+#endif
 
-	model = g_object_new (GDA_TYPE_POSTGRES_RECORDSET, NULL);
-	model->priv->pg_res = pg_res;
-	model->priv->cnc = cnc;
-	model->priv->ncolumns = PQnfields (pg_res);
-	cmd_tuples = PQcmdTuples (pg_res);
-	if (cmd_tuples == NULL || *cmd_tuples == '\0')
-		model->priv->nrows = PQntuples (pg_res);
+                //PQntuples() returns the number of rows in the result:
+                const gint nbtuples = PQntuples (model->priv->pg_res);
+		model->priv->pg_res_size = nbtuples;
+
+                if (nbtuples > 0) {
+			/* model->priv->pg_res_inf */
+			if (model->priv->pg_pos == G_MININT)
+				model->priv->pg_res_inf = 0;
+			else
+				model->priv->pg_res_inf = model->priv->pg_pos + 1;
+
+			/* GDA_PMODEL (model)->advertized_nrows and model->priv->pg_pos */
+			if (nbtuples < model->priv->chunk_size) {
+				if (model->priv->pg_pos == G_MININT) 
+					GDA_PMODEL (model)->advertized_nrows = nbtuples;
+				else
+					GDA_PMODEL (model)->advertized_nrows = model->priv->pg_pos + nbtuples + 1;
+
+				model->priv->pg_pos = G_MAXINT;				
+			}
+			else {
+				if (model->priv->pg_pos == G_MININT)
+					model->priv->pg_pos = nbtuples - 1;
+				else
+					model->priv->pg_pos += nbtuples;
+			}
+		}
+		else {
+			if (model->priv->pg_pos == G_MININT)
+				GDA_PMODEL (model)->advertized_nrows = 0;
+			else
+				GDA_PMODEL (model)->advertized_nrows = model->priv->pg_pos + 1; /* total number of rows */
+			model->priv->pg_pos = G_MAXINT;
+			retval = FALSE;
+		}
+	}
+
+#ifdef GDA_PG_DEBUG
+	g_print ("--> SIZE = %d (inf = %d) nrows = %d, pg_pos = %d\n", model->priv->pg_res_size, model->priv->pg_res_inf,
+		 GDA_PMODEL (model)->advertized_nrows, model->priv->pg_pos);
+#endif
+
+	return retval;
+}
+
+static gboolean
+fetch_prev_chunk (GdaPostgresRecordset *model, gboolean *fetch_error, GError **error)
+{
+	if (model->priv->pg_res) {
+		PQclear (model->priv->pg_res);
+		model->priv->pg_res = NULL;
+	}
+	*fetch_error = FALSE;
+
+	if (model->priv->pg_pos == G_MININT) 
+		return FALSE;
+	else if (model->priv->pg_pos == G_MAXINT) 
+		g_assert (GDA_PMODEL (model)->advertized_nrows >= 0); /* total number of rows MUST be known at this point */
+
+	gchar *str;
+	gboolean retval = TRUE;
+	int status;
+	gint noffset;
+	
+	if (model->priv->pg_pos == G_MAXINT)
+		noffset = model->priv->chunk_size + 1;
+	else
+		noffset = model->priv->pg_res_size + model->priv->chunk_size;
+	str = g_strdup_printf ("MOVE BACKWARD %d FROM %s; FETCH FORWARD %d FROM %s;",
+			       noffset, model->priv->cursor_name,
+			       model->priv->chunk_size, model->priv->cursor_name);
+#ifdef GDA_PG_DEBUG
+	g_print ("QUERY: %s\n", str);
+#endif
+        model->priv->pg_res = PQexec (model->priv->pconn, str);
+        g_free (str);
+        status = PQresultStatus (model->priv->pg_res);
+	model->priv->chunks_read ++;
+        if (status != PGRES_TUPLES_OK) {
+		_gda_postgres_make_error (model->priv->cnc, model->priv->pconn, model->priv->pg_res, error);
+                PQclear (model->priv->pg_res);
+                model->priv->pg_res = NULL;
+		model->priv->pg_res_size = 0;
+                retval = FALSE;
+		*fetch_error = TRUE;
+        }
 	else {
-		model->priv->nrows = strtol (cmd_tuples, endptr, 10);
-		if (**endptr != '\0')
-			g_warning (_("Tuples:\"%s\""), cmd_tuples);
-		
+#ifdef GDA_PG_DEBUG
+		dump_pg_res (model->priv->pg_res);
+#endif
+
+                //PQntuples() returns the number of rows in the result:
+                const gint nbtuples = PQntuples (model->priv->pg_res);
+		model->priv->pg_res_size = nbtuples;
+
+                if (nbtuples > 0) {
+			/* model->priv->pg_res_inf */
+			if (model->priv->pg_pos == G_MAXINT)
+				model->priv->pg_res_inf = GDA_PMODEL (model)->advertized_nrows - nbtuples;
+			else
+				model->priv->pg_res_inf = 
+					MAX (model->priv->pg_res_inf - (noffset - model->priv->chunk_size), 0);
+
+			/* model->priv->pg_pos */
+			if (nbtuples < model->priv->chunk_size) {
+				model->priv->pg_pos = G_MAXINT;
+			}
+			else {
+				if (model->priv->pg_pos == G_MAXINT)
+					model->priv->pg_pos = GDA_PMODEL (model)->advertized_nrows - 1;
+				else
+					model->priv->pg_pos = MAX (model->priv->pg_pos - noffset, -1) + nbtuples;
+			}
+		}
+		else {
+			model->priv->pg_pos = G_MAXINT;
+			retval = FALSE;
+		}
 	}
-	model->priv->column_types = gda_postgres_get_column_types (pg_res, 
-								   cnc_priv_data->type_data, 
-								   cnc_priv_data->ntypes);
-	gda_data_model_hash_set_n_columns (GDA_DATA_MODEL_HASH (model),
-					   model->priv->ncolumns);
-	model->priv->table_name = gda_postgres_guess_table_name (cnc, pg_res);
-
-	/* set GdaColumn attributes */
-	for (i = 0; i < model->priv->ncolumns; i++)
-		gda_postgres_recordset_describe_column (GDA_DATA_MODEL (model), cnc, pg_res, 
-							cnc_priv_data->type_data, 
-							cnc_priv_data->ntypes,
-							model->priv->table_name, i);
 
-	return GDA_DATA_MODEL (model);
+#ifdef GDA_PG_DEBUG
+	g_print ("<-- SIZE = %d (inf = %d) nrows = %d, pg_pos = %d\n", model->priv->pg_res_size, model->priv->pg_res_inf,
+		 GDA_PMODEL (model)->advertized_nrows, model->priv->pg_pos);
+#endif
+
+	return retval;
 }
 
-PGresult *
-gda_postgres_recordset_get_pgresult (GdaPostgresRecordset *recset)
+static gboolean
+fetch_row_number_chunk (GdaPostgresRecordset *model, int row_index, gboolean *fetch_error, GError **error)
 {
-	g_return_val_if_fail (GDA_IS_POSTGRES_RECORDSET (recset), NULL);
+        if (model->priv->pg_res) {
+                PQclear (model->priv->pg_res);
+                model->priv->pg_res = NULL;
+        }
+	*fetch_error = FALSE;
+
+        gchar *str;
+        gboolean retval = TRUE;
+        int status;
+
+        /* Postgres's FETCH ABSOLUTE seems to use a 1-based index: */
+        str = g_strdup_printf ("FETCH ABSOLUTE %d FROM %s;",
+                               row_index + 1, model->priv->cursor_name);
+#ifdef GDA_PG_DEBUG
+        g_print ("QUERY: %s\n", str);
+#endif
+        model->priv->pg_res = PQexec (model->priv->pconn, str);
+        g_free (str);
+        status = PQresultStatus (model->priv->pg_res);
+        model->priv->chunks_read ++; /* Not really correct, because we are only fetching 1 row, not a whole chunk of rows. */
+        if (status != PGRES_TUPLES_OK) {
+		_gda_postgres_make_error (model->priv->cnc, model->priv->pconn, model->priv->pg_res, error);
+                PQclear (model->priv->pg_res);
+                model->priv->pg_res = NULL;
+                model->priv->pg_res_size = 0;
+                retval = FALSE;
+		*fetch_error = TRUE;
+        }
+        else {
+#ifdef GDA_PG_DEBUG
+                dump_pg_res (model->priv->pg_res);
+#endif
+
+                //PQntuples() returns the number of rows in the result:
+                const gint nbtuples = PQntuples (model->priv->pg_res);
+                model->priv->pg_res_size = nbtuples;
+
+                if (nbtuples > 0) {
+                        /* Remember the row number for the start of this chunk:
+                         * (actually a chunk of just 1 record in this case.) */
+                        model->priv->pg_res_inf = row_index;
+
+                        /* don't change model->priv->nrows because we can't know if we have reached the end */
+                        model->priv->pg_pos = row_index;
+                }
+                else {
+                        model->priv->pg_pos = G_MAXINT;
+                        retval = FALSE;
+                }
+        }
+
+#ifdef GDA_PG_DEBUG
+        g_print ("--> SIZE = %d (inf = %d) nrows = %d, pg_pos = %d\n", model->priv->pg_res_size, model->priv->pg_res_inf,
+                 model->priv->nrows, model->priv->pg_pos);
+#endif
 
-	return recset->priv->pg_res;
+        return retval;
 }

Modified: branches/V4-branch/providers/postgres/gda-postgres-recordset.h
==============================================================================
--- branches/V4-branch/providers/postgres/gda-postgres-recordset.h	(original)
+++ branches/V4-branch/providers/postgres/gda-postgres-recordset.h	Wed Feb 20 20:36:04 2008
@@ -1,11 +1,8 @@
-/* GDA DB Postgres provider
- * Copyright (C) 1998 - 2002 The GNOME Foundation
+/* GDA postgres provider
+ * Copyright (C) 1998 - 2008 The GNOME Foundation.
  *
  * AUTHORS:
- *      Michael Lausch <michael lausch at>
- *	Rodrigo Moya <rodrigo gnome-db org>
- *      Vivien Malerba <malerba gnome-db org>
- *      Gonzalo Paniagua Javier <gonzalo gnome-db org>
+ *         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
@@ -26,9 +23,9 @@
 #ifndef __GDA_POSTGRES_RECORDSET_H__
 #define __GDA_POSTGRES_RECORDSET_H__
 
-#include <libgda/gda-data-model-hash.h>
-#include <libgda/gda-value.h>
-#include <libpq-fe.h>
+#include <libgda/libgda.h>
+#include <providers-support/gda-pmodel.h>
+#include "gda-postgres-pstmt.h"
 
 G_BEGIN_DECLS
 
@@ -43,20 +40,19 @@
 typedef struct _GdaPostgresRecordsetPrivate GdaPostgresRecordsetPrivate;
 
 struct _GdaPostgresRecordset {
-	GdaDataModelHash model;
+	GdaPModel                model;
 	GdaPostgresRecordsetPrivate *priv;
 };
 
 struct _GdaPostgresRecordsetClass {
-	GdaDataModelHashClass parent_class;
+	GdaPModelClass             parent_class;
 };
 
-GType         gda_postgres_recordset_get_type (void) G_GNUC_CONST;
-GdaDataModel *gda_postgres_recordset_new (GdaConnection *cnc, PGresult *pgres);
+GType         gda_postgres_recordset_get_type   (void) G_GNUC_CONST;
+GdaDataModel *gda_postgres_recordset_new_random (GdaConnection *cnc, GdaPostgresPStmt *ps, PGresult *pg_res, GType *col_types);
+GdaDataModel *gda_postgres_recordset_new_cursor (GdaConnection *cnc, GdaPostgresPStmt *ps, gchar *cursor_name, GType *col_types);
 
-PGresult     *gda_postgres_recordset_get_pgresult (GdaPostgresRecordset *recset);
 
 G_END_DECLS
 
 #endif
-

Added: branches/V4-branch/providers/postgres/gda-postgres-util.c
==============================================================================
--- (empty file)
+++ branches/V4-branch/providers/postgres/gda-postgres-util.c	Wed Feb 20 20:36:04 2008
@@ -0,0 +1,135 @@
+/* GDA postgres provider
+ * Copyright (C) 1998 - 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *         Vivien Malerba <malerba gnome-db org>
+ *         Rodrigo Moya <rodrigo gnome-db org>
+ *         Gonzalo Paniagua Javier <gonzalo 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 "gda-postgres-util.h"
+
+static GdaConnectionEventCode
+gda_postgres_sqlsate_to_gda_code (const gchar *sqlstate)
+{
+        guint64 gda_code = g_ascii_strtoull (sqlstate, NULL, 0);
+
+        switch (gda_code) {
+                case 42501:
+                        return GDA_CONNECTION_EVENT_CODE_INSUFFICIENT_PRIVILEGES;
+                case 23505:
+                        return GDA_CONNECTION_EVENT_CODE_UNIQUE_VIOLATION;
+                case 23502:
+                        return GDA_CONNECTION_EVENT_CODE_NOT_NULL_VIOLATION;
+                default:
+                        return GDA_CONNECTION_EVENT_CODE_UNKNOWN;
+        }
+}
+
+/*
+ * Create a new #GdaConnectionEvent object and "adds" it to @cnc
+ *
+ * Returns: a new GdaConnectionEvent which must not be unrefed()
+ */
+GdaConnectionEvent *
+_gda_postgres_make_error (GdaConnection *cnc, PGconn *pconn, PGresult *pg_res, GError **error)
+{
+	GdaConnectionEvent *error_ev;
+        GdaConnectionEventCode gda_code = GDA_CONNECTION_EVENT_CODE_UNKNOWN;
+        GdaTransactionStatus *trans;
+
+        error_ev = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+        if (pconn != NULL) {
+                gchar *message;
+
+                if (pg_res != NULL) {
+                        gchar *sqlstate;
+
+                        message = g_strdup (PQresultErrorMessage (pg_res));
+                        sqlstate = PQresultErrorField (pg_res, PG_DIAG_SQLSTATE);
+                        gda_connection_event_set_sqlstate (error_ev, sqlstate);
+                        gda_code = gda_postgres_sqlsate_to_gda_code (sqlstate);
+                }
+                else {
+                        message = g_strdup (PQerrorMessage (pconn));
+                        gda_code = GDA_CONNECTION_EVENT_CODE_UNKNOWN;
+                }
+
+		
+		gchar *ptr = message;
+		if (g_str_has_prefix (message, "ERROR:"))
+			ptr += 6;
+		g_strstrip (ptr);
+
+                gda_connection_event_set_description (error_ev, ptr);
+                gda_connection_event_set_gda_code (error_ev, gda_code);
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_STATEMENT_EXEC_ERROR, ptr);
+		g_free (message);
+        }
+        else {
+                gda_connection_event_set_description (error_ev, _("No detail"));
+                gda_connection_event_set_gda_code (error_ev, gda_code);
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_STATEMENT_EXEC_ERROR,
+			     _("No detail"));
+        }
+
+        gda_connection_event_set_code (error_ev, -1);
+        gda_connection_event_set_source (error_ev, "gda-postgres");
+        gda_connection_add_event (cnc, error_ev);
+
+        /* change the transaction status if there is a problem */
+        trans = gda_connection_get_transaction_status (cnc);
+        if (trans) {
+                if ((PQtransactionStatus (pconn) == PQTRANS_INERROR) &&
+                    (trans->state != GDA_TRANSACTION_STATUS_STATE_FAILED))
+                        gda_connection_internal_change_transaction_state (cnc,
+                                                                          GDA_TRANSACTION_STATUS_STATE_FAILED);
+        }
+        return error_ev;
+}
+
+/* to be used only while initializing a connection */
+PGresult *
+_gda_postgres_PQexec_wrap (GdaConnection *cnc, PGconn *pconn, const char *query)
+{
+	GdaConnectionEvent *event;
+
+        if (cnc) {
+                event = gda_connection_event_new (GDA_CONNECTION_EVENT_COMMAND);
+                gda_connection_event_set_description (event, query);
+                gda_connection_add_event (cnc, event);
+        }
+
+        return PQexec (pconn, query);
+}
+
+GType
+_gda_postgres_type_oid_to_gda (PostgresConnectionData *cdata, Oid postgres_type)
+{
+	gint i;
+
+	for (i = 0; i < cdata->ntypes; i++)
+		if (cdata->type_data[i].oid == postgres_type) 
+			break;
+
+  	if (cdata->type_data[i].oid != postgres_type)
+		return G_TYPE_STRING;
+
+	return cdata->type_data[i].type;
+}

Added: branches/V4-branch/providers/postgres/gda-postgres-util.h
==============================================================================
--- (empty file)
+++ branches/V4-branch/providers/postgres/gda-postgres-util.h	Wed Feb 20 20:36:04 2008
@@ -0,0 +1,40 @@
+/* GDA postgres provider
+ * Copyright (C) 1998 - 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *         Vivien Malerba <malerba gnome-db org>
+ *         Rodrigo Moya <rodrigo gnome-db org>
+ *         Gonzalo Paniagua Javier <gonzalo 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; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __GDA_POSTGRES_UTIL_H__
+#define __GDA_POSTGRES_UTIL_H__
+
+#include "gda-postgres.h"
+
+G_BEGIN_DECLS
+
+GdaConnectionEvent *_gda_postgres_make_error               (GdaConnection *cnc, PGconn *pconn, PGresult *pg_res, GError **error);
+PGresult           *_gda_postgres_PQexec_wrap              (GdaConnection *cnc, PGconn *pconn, const char *query);
+
+int                 _gda_postgres_get_connection_type_list (GdaConnection *cnc, PostgresConnectionData *cdata);
+GType               _gda_postgres_type_oid_to_gda          (PostgresConnectionData *cdata, Oid postgres_type);
+
+G_END_DECLS
+
+#endif
+

Modified: branches/V4-branch/providers/postgres/gda-postgres.h
==============================================================================
--- branches/V4-branch/providers/postgres/gda-postgres.h	(original)
+++ branches/V4-branch/providers/postgres/gda-postgres.h	Wed Feb 20 20:36:04 2008
@@ -1,75 +1,68 @@
-/* GDA Postgres Provider
- * Copyright (C) 1998 - 2007 The GNOME Foundation
+/* GDA postgres provider
+ * Copyright (C) 1998 - 2008 The GNOME Foundation.
  *
  * AUTHORS:
  *         Vivien Malerba <malerba gnome-db org>
  *         Rodrigo Moya <rodrigo gnome-db org>
  *         Gonzalo Paniagua Javier <gonzalo 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 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,
+ * 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; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 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_POSTGRES_H__
 #define __GDA_POSTGRES_H__
 
-#include <glib/gmacros.h>
-#include <glib/gi18n-lib.h>
-#include <libgda/gda-server-provider.h>
-#include "gda-postgres-provider.h"
-#include "gda-postgres-recordset.h"
-#include "gda-postgres-cursor-recordset.h"
-
-#define GDA_POSTGRES_PROVIDER_ID "GDA PostgreSQL provider"
-
-G_BEGIN_DECLS
-
 /*
- * Utility functions
+ * Provider name
  */
+#define POSTGRES_PROVIDER_NAME "PostgreSQL"
 
-GdaConnectionEvent *gda_postgres_make_error (GdaConnection *cnc, PGconn *pconn, PGresult *pg_res);
-void gda_postgres_set_value (GdaConnection *cnc,
-			     GValue *value, 
-			     GType type, 
-			     const gchar *thevalue,
-			     gboolean isNull,
-			     gint length);
-
-
-GType gda_postgres_type_oid_to_gda (GdaPostgresTypeOid *type_data, 
-					   gint ntypes,
-					   Oid postgres_type);
-
-GType gda_postgres_type_name_to_gda (GHashTable *h_table,
-					    const gchar *name);
-
-const gchar *gda_data_type_to_string (GType type);
-gchar *gda_postgres_value_to_sql_string (GValue *value);
-gboolean gda_postgres_check_transaction_started (GdaConnection *cnc);
+#include <libgda/libgda.h>
+#include <libpq-fe.h>
+#include <libpq/libpq-fs.h>
 
-PGresult *gda_postgres_PQexec_wrap (GdaConnection *cnc, PGconn *conn, const char *query);
+/*
+ * Postgres type identification
+ */
+typedef struct {
+        gchar              *name;
+        Oid                 oid;
+        GType               type;
+        gchar              *comments;
+        gchar              *owner;
+} GdaPostgresTypeOid;
 
 /*
- * For recordset implementations
+ * Provider's specific connection data
  */
-void gda_postgres_recordset_describe_column (GdaDataModel *model, GdaConnection *cnc, PGresult *pg_res, 
-					     GdaPostgresTypeOid *type_data, gint ntypes, const gchar *table_name,
-					     gint col);
-gchar *gda_postgres_guess_table_name (GdaConnection *cnc, PGresult *pg_res);
-GType *gda_postgres_get_column_types (PGresult *pg_res, GdaPostgresTypeOid *type_data, gint ntypes);
-G_END_DECLS
+typedef struct {
+	GdaConnection      *cnc;
+        PGconn             *pconn;
+        gint                ntypes;
+        GdaPostgresTypeOid *type_data;
+        GHashTable         *h_table;
+
+        /* Version of the backend to which we are connected */
+        gchar              *version;
+        gfloat              version_float;
+
+        /* Internal data types not returned */
+        gchar              *avoid_types;
+        gchar              *avoid_types_oids;
+        gchar              *any_type_oid; /* oid for the 'any' data type, used to fetch aggregates and functions */
+} PostgresConnectionData;
 
 #endif
-

Modified: branches/V4-branch/providers/postgres/gen_def.c
==============================================================================
--- branches/V4-branch/providers/postgres/gen_def.c	(original)
+++ branches/V4-branch/providers/postgres/gen_def.c	Wed Feb 20 20:36:04 2008
@@ -1,5 +1,4 @@
 /* 
- *
  * Copyright (C) 2007 Vivien Malerba
  *
  * This Library is free software; you can redistribute it and/or

Modified: branches/V4-branch/providers/postgres/libmain.c
==============================================================================
--- branches/V4-branch/providers/postgres/libmain.c	(original)
+++ branches/V4-branch/providers/postgres/libmain.c	Wed Feb 20 20:36:04 2008
@@ -1,10 +1,8 @@
 /* GDA Postgres Provider
- * Copyright (C) 1998 - 2007 The GNOME Foundation
+ * Copyright (C) 2008 The GNOME Foundation
  *
  * AUTHORS:
- *         Vivien Malerba <malerba gnome-db org>
- *         Rodrigo Moya <rodrigo gnome-db org>
- *         Gonzalo Paniagua Javier <gonzalo gnome-db org>
+ *      TO_ADD: your name and email
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -22,10 +20,10 @@
  */
 
 #include <glib/gi18n-lib.h>
-#include <libgda/gda-config.h>
-#include "gda-postgres-provider.h"
 #include <libgda/gda-server-provider-extra.h>
 #include <libgda/binreloc/gda-binreloc.h>
+#include "gda-postgres.h"
+#include "gda-postgres-provider.h"
 
 static gchar      *module_path = NULL;
 const gchar       *plugin_get_name (void);
@@ -36,14 +34,14 @@
 void
 plugin_init (const gchar *real_path)
 {
-	if (real_path)
-		module_path = g_strdup (real_path);
+        if (real_path)
+                module_path = g_strdup (real_path);
 }
 
 const gchar *
 plugin_get_name (void)
 {
-	return "PostgreSQL";
+	return POSTGRES_PROVIDER_NAME;
 }
 
 const gchar *
@@ -68,7 +66,7 @@
 {
 	GdaServerProvider *prov;
 
-	prov = gda_postgres_provider_new ();
-	g_object_set_data ((GObject *) prov, "GDA_PROVIDER_DIR", module_path);
-	return prov;
+	prov = (GdaServerProvider*) g_object_new (GDA_TYPE_POSTGRES_PROVIDER, NULL);
+        g_object_set_data ((GObject *) prov, "GDA_PROVIDER_DIR", module_path);
+        return prov;
 }

Added: branches/V4-branch/providers/prepare_provider_sources.sh
==============================================================================
--- (empty file)
+++ branches/V4-branch/providers/prepare_provider_sources.sh	Wed Feb 20 20:36:04 2008
@@ -0,0 +1,55 @@
+#!/bin/sh
+
+#
+# This script prepares the sources to write a new database provider (it renames the files and
+# the objects within the files) using a new name given as the only argument of the command
+# line.
+#
+# Usage:
+# 1 - Copy the ./skel-implementation/capi or ./skel-implementation/models to another directory (for example MySQL)
+# 2 - go into the new directory (MySQL/ in this case)
+# 3 - execute this script with the name of the provider to create (mysql in this case)
+#     ../prepare_provider_sources.sh mysql
+# 
+
+if [ $# != 1 ]
+then
+  echo "Usage: `basename $0` <provider name>"
+  exit 1
+fi  
+provname=$1
+
+#
+# compute what to rename from ("capi", "models")
+#
+for file in $( ls | grep "gda-[a-z]*.h"); 
+do
+    base=$(echo $file | cut -b 5- | sed -e 's/\.h$//')
+done
+
+#
+# renaming files
+#
+for file in *
+do
+    newname=$(echo $file | sed -e "s/$base/$provname/")
+    if [ $file != $newname ]; then
+	mv $file $newname
+    fi
+done
+
+#
+# changing contents
+#
+upname=$(echo $provname | cut -b 1 | tr a-z A-Z)$(echo $provname | sed -e "s/^.//")
+allupname=$(echo $provname | tr a-z A-Z)
+bupname=$(echo $base | cut -b 1 | tr a-z A-Z)$(echo $base | sed -e "s/^.//")
+ballupname=$(echo $base | tr a-z A-Z)
+
+
+for file in *
+do
+    mv $file $file.1
+    cat $file.1 | sed -e "s/$base/$provname/g" -e "s/$bupname/$upname/g" -e "s/$ballupname/$allupname/g"> $file
+    rm -f $file.1
+done

Modified: branches/V4-branch/providers/skel-implementation/capi/gda-capi-ddl.h
==============================================================================
--- branches/V4-branch/providers/skel-implementation/capi/gda-capi-ddl.h	(original)
+++ branches/V4-branch/providers/skel-implementation/capi/gda-capi-ddl.h	Wed Feb 20 20:36:04 2008
@@ -1,5 +1,5 @@
 /* GDA Capi provider
- * Copyright (C) 2006 - 2008 The GNOME Foundation
+ * Copyright (C) 2008 The GNOME Foundation
  *
  * AUTHORS:
  *      TO_ADD: your name and email

Modified: branches/V4-branch/providers/skel-implementation/capi/gda-capi-parser.h
==============================================================================
--- branches/V4-branch/providers/skel-implementation/capi/gda-capi-parser.h	(original)
+++ branches/V4-branch/providers/skel-implementation/capi/gda-capi-parser.h	Wed Feb 20 20:36:04 2008
@@ -29,10 +29,11 @@
 
 G_BEGIN_DECLS
 
-#define GDA_TYPE_CAPI_PARSER          (gda_capi_parser_get_type())
-#define GDA_CAPI_PARSER(obj)          G_TYPE_CHECK_INSTANCE_CAST (obj, gda_capi_parser_get_type(), GdaCapiParser)
-#define GDA_CAPI_PARSER_CLASS(klass)  G_TYPE_CHECK_CLASS_CAST (klass, gda_capi_parser_get_type (), GdaCapiParserClass)
-#define GDA_IS_CAPI_PARSER(obj)       G_TYPE_CHECK_INSTANCE_TYPE (obj, gda_capi_parser_get_type ())
+#define GDA_TYPE_CAPI_PARSER            (gda_capi_parser_get_type())
+#define GDA_CAPI_PARSER(obj)            (G_TYPE_CHECK_INSTANCE_CAST (obj, GDA_TYPE_CAPI_PARSER, GdaCapiParser))
+#define GDA_CAPI_PARSER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST (klass, GDA_TYPE_CAPI_PARSER, GdaCapiParserClass))
+#define GDA_IS_CAPI_PARSER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE (obj, GDA_TYPE_CAPI_PARSER))
+#define GDA_IS_CAPI_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDA_TYPE_CAPI_PARSER))
 
 typedef struct _GdaCapiParser GdaCapiParser;
 typedef struct _GdaCapiParserClass GdaCapiParserClass;

Modified: branches/V4-branch/providers/skel-implementation/capi/gda-capi-provider.c
==============================================================================
--- branches/V4-branch/providers/skel-implementation/capi/gda-capi-provider.c	(original)
+++ branches/V4-branch/providers/skel-implementation/capi/gda-capi-provider.c	Wed Feb 20 20:36:04 2008
@@ -151,7 +151,6 @@
 	provider_class->get_data_handler = gda_capi_provider_get_data_handler;
 	provider_class->get_def_dbms_type = gda_capi_provider_get_default_dbms_type;
 
-	provider_class->create_connection = NULL;
 	provider_class->open_connection = gda_capi_provider_open_connection;
 	provider_class->close_connection = gda_capi_provider_close_connection;
 	provider_class->get_database = gda_capi_provider_get_database;
@@ -173,6 +172,10 @@
 	provider_class->statement_prepare = gda_capi_provider_statement_prepare;
 	provider_class->statement_execute = gda_capi_provider_statement_execute;
 
+	provider_class->is_busy = NULL;
+	provider_class->cancel = NULL;
+	provider_class->create_connection = NULL;
+
 	memset (&(provider_class->meta_funcs), 0, sizeof (GdaServerProviderMeta));
 	provider_class->meta_funcs.info = _gda_capi_meta_info;
 	provider_class->meta_funcs.btypes = _gda_capi_meta_btypes;
@@ -569,9 +572,8 @@
  * Commit transaction request
  */
 static gboolean
-gda_capi_provider_commit_transaction (GdaServerProvider *provider,
-					GdaConnection *cnc,
-					const gchar *name, GError **error)
+gda_capi_provider_commit_transaction (GdaServerProvider *provider, GdaConnection *cnc,
+				      const gchar *name, GError **error)
 {
 	CapiConnectionData *cdata;
 
@@ -591,9 +593,8 @@
  * Rollback transaction request
  */
 static gboolean
-gda_capi_provider_rollback_transaction (GdaServerProvider *provider,
-					  GdaConnection *cnc,
-					  const gchar *name, GError **error)
+gda_capi_provider_rollback_transaction (GdaServerProvider *provider, GdaConnection *cnc,
+					const gchar *name, GError **error)
 {
 	CapiConnectionData *cdata;
 
@@ -678,6 +679,11 @@
 static gboolean
 gda_capi_provider_supports_feature (GdaServerProvider *provider, GdaConnection *cnc, GdaConnectionFeature feature)
 {
+	if (cnc) {
+		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+		g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
+	}
+
 	switch (feature) {
 	case GDA_CONNECTION_FEATURE_SQL :
 		return TRUE;
@@ -955,7 +961,7 @@
 			break;
 		}
 
-		/* actual binding using the C API */
+		/* actual binding using the C API, for parameter at position @i */
 		const GValue *value = gda_holder_get_value (h);
 		TO_IMPLEMENT;
 	}

Modified: branches/V4-branch/providers/skel-implementation/capi/gda-capi-pstmt.h
==============================================================================
--- branches/V4-branch/providers/skel-implementation/capi/gda-capi-pstmt.h	(original)
+++ branches/V4-branch/providers/skel-implementation/capi/gda-capi-pstmt.h	Wed Feb 20 20:36:04 2008
@@ -29,10 +29,10 @@
 G_BEGIN_DECLS
 
 #define GDA_TYPE_CAPI_PSTMT            (gda_capi_pstmt_get_type())
-#define GDA_CAPI_PSTMT(obj)            (G_TYPE_CHECK_INSTANCE_CAST (obj, GDA_TYPE_PSTMT, GdaCapiPStmt))
-#define GDA_CAPI_PSTMT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST (klass, GDA_TYPE_PSTMT, GdaCapiPStmtClass))
-#define GDA_IS_CAPI_PSTMT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE(obj, GDA_TYPE_PSTMT))
-#define GDA_IS_CAPI_PSTMT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GDA_TYPE_PSTMT))
+#define GDA_CAPI_PSTMT(obj)            (G_TYPE_CHECK_INSTANCE_CAST (obj, GDA_TYPE_CAPI_PSTMT, GdaCapiPStmt))
+#define GDA_CAPI_PSTMT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST (klass, GDA_TYPE_CAPI_PSTMT, GdaCapiPStmtClass))
+#define GDA_IS_CAPI_PSTMT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE(obj, GDA_TYPE_CAPI_PSTMT))
+#define GDA_IS_CAPI_PSTMT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GDA_TYPE_CAPI_PSTMT))
 
 typedef struct _GdaCapiPStmt        GdaCapiPStmt;
 typedef struct _GdaCapiPStmtClass   GdaCapiPStmtClass;

Modified: branches/V4-branch/providers/skel-implementation/capi/gda-capi-recordset.c
==============================================================================
--- branches/V4-branch/providers/skel-implementation/capi/gda-capi-recordset.c	(original)
+++ branches/V4-branch/providers/skel-implementation/capi/gda-capi-recordset.c	Wed Feb 20 20:36:04 2008
@@ -38,10 +38,10 @@
 
 /* virtual methods */
 static gint     gda_capi_recordset_fetch_nb_rows (GdaPModel *model);
-static GdaPRow *gda_capi_recordset_fetch_random (GdaPModel *model, gint rownum, GError **error);
-static GdaPRow *gda_capi_recordset_fetch_next (GdaPModel *model, gint rownum, GError **error);
-static GdaPRow *gda_capi_recordset_fetch_prev (GdaPModel *model, gint rownum, GError **error);
-static GdaPRow *gda_capi_recordset_fetch_at (GdaPModel *model, gint rownum, GError **error);
+static gboolean gda_capi_recordset_fetch_random (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error);
+static gboolean gda_capi_recordset_fetch_next (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error);
+static gboolean gda_capi_recordset_fetch_prev (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error);
+static gboolean gda_capi_recordset_fetch_at (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error);
 
 
 struct _GdaCapiRecordsetPrivate {
@@ -148,6 +148,11 @@
 	if (!cdata)
 		return NULL;
 
+	/* make sure @ps reports the correct number of columns using the API*/
+        if (_GDA_PSTMT (ps)->ncols < 0)
+                /*_GDA_PSTMT (ps)->ncols = ...;*/
+		TO_IMPLEMENT;
+
         /* completing @ps if not yet done */
         if (!_GDA_PSTMT (ps)->types && (_GDA_PSTMT (ps)->ncols > 0)) {
 		/* create prepared statement's columns */
@@ -223,84 +228,114 @@
 }
 
 /*
- * Create a new filled #GdaPRow object for the row at position @rownum.
+ * Create a new filled #GdaPRow object for the row at position @rownum, and put it into *prow.
+ *
+ * WARNING: @prow will NOT be NULL, but *prow may or may not be NULL:
+ *  -  If *prow is NULL then a new #GdaPRow object has to be created, 
+ *  -  and otherwise *prow contains a #GdaPRow object which has already been created 
+ *     (through a call to this very function), and in this case it should not be modified
+ *     but the function may return FALSE if an error occurred.
  *
  * Memory management for that new GdaPRow object is left to the implementation, which
- * can use gda_pmodel_take_row().
+ * can use gda_pmodel_take_row(). If new row objects are "given" to the GdaPModel implemantation
+ * using that method, then this method should detect when all the data model rows have been analysed
+ * (when model->nb_stored_rows == model->advertized_nrows) and then possibly discard the API handle
+ * as it won't be used anymore to fetch rows.
  */
-static GdaPRow *
-gda_capi_recordset_fetch_random (GdaPModel *model, gint rownum, GError **error)
+static gboolean 
+gda_capi_recordset_fetch_random (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error)
 {
 	GdaCapiRecordset *imodel;
-	GdaPRow *prow = NULL;
 
 	imodel = GDA_CAPI_RECORDSET (model);
 
 	TO_IMPLEMENT;
 
-	return prow;
+	return TRUE;
+}
+
+/*
+ * Create and "give" filled #GdaPRow object for all the rows in the model
+ */
+static gboolean
+gda_capi_recordset_store_all (GdaPModel *model, GError **error)
+{
+	GdaCapiRecordset *imodel;
+
+	imodel = GDA_CAPI_RECORDSET (model);
+
+	/* default implementation */
+	for (i = 0; i < model->advertized_nrows; i++) {
+		GdaPRow *prow;
+		if (! gda_capi_recordset_fetch_random (model, &prow, i, error))
+			return FALSE;
+	}
+	return TRUE;
 }
 
 /*
- * Create a new filled #GdaPRow object for the next cursor row
+ * Create a new filled #GdaPRow object for the next cursor row, and put it into *prow.
+ *
+ * WARNING: @prow will NOT be NULL, but *prow may or may not be NULL:
+ *  -  If *prow is NULL then a new #GdaPRow object has to be created, 
+ *  -  and otherwise *prow contains a #GdaPRow object which has already been created 
+ *     (through a call to this very function), and in this case it should not be modified
+ *     but the function may return FALSE if an error occurred.
  *
  * Memory management for that new GdaPRow object is left to the implementation, which
  * can use gda_pmodel_take_row().
  */
-static GdaPRow *
-gda_capi_recordset_fetch_next (GdaPModel *model, gint rownum, GError **error)
+static gboolean 
+gda_capi_recordset_fetch_next (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error)
 {
-	GdaPRow *prow;
 	GdaCapiRecordset *imodel = (GdaCapiRecordset*) model;
 
-	prow = gda_pmodel_get_stored_row (model, rownum);
-	if (prow)
-		return prow;
-	
 	TO_IMPLEMENT;
 
-	return prow;
+	return TRUE;
 }
 
 /*
- * Create a new filled #GdaPRow object for the previous cursor row
+ * Create a new filled #GdaPRow object for the previous cursor row, and put it into *prow.
+ *
+ * WARNING: @prow will NOT be NULL, but *prow may or may not be NULL:
+ *  -  If *prow is NULL then a new #GdaPRow object has to be created, 
+ *  -  and otherwise *prow contains a #GdaPRow object which has already been created 
+ *     (through a call to this very function), and in this case it should not be modified
+ *     but the function may return FALSE if an error occurred.
  *
  * Memory management for that new GdaPRow object is left to the implementation, which
  * can use gda_pmodel_take_row().
  */
-static GdaPRow *
-gda_capi_recordset_fetch_prev (GdaPModel *model, gint rownum, GError **error)
+static gboolean 
+gda_capi_recordset_fetch_prev (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error)
 {
-	GdaPRow *prow;
 	GdaCapiRecordset *imodel = (GdaCapiRecordset*) model;
 
-	prow = gda_pmodel_get_stored_row (model, rownum);
-	if (prow)
-		return prow;
-	
 	TO_IMPLEMENT;
 
-	return prow;
+	return TRUE;
 }
 
 /*
- * Create a new filled #GdaPRow object for the cursor row at position @rownum
+ * Create a new filled #GdaPRow object for the cursor row at position @rownum, and put it into *prow.
+ *
+ * WARNING: @prow will NOT be NULL, but *prow may or may not be NULL:
+ *  -  If *prow is NULL then a new #GdaPRow object has to be created, 
+ *  -  and otherwise *prow contains a #GdaPRow object which has already been created 
+ *     (through a call to this very function), and in this case it should not be modified
+ *     but the function may return FALSE if an error occurred.
  *
  * Memory management for that new GdaPRow object is left to the implementation, which
  * can use gda_pmodel_take_row().
  */
-static GdaPRow *
-gda_capi_recordset_fetch_at (GdaPModel *model, gint rownum, GError **error)
+static gboolean 
+gda_capi_recordset_fetch_at (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error)
 {
-	GdaPRow *prow;
 	GdaCapiRecordset *imodel = (GdaCapiRecordset*) model;
-
-	prow = gda_pmodel_get_stored_row (model, rownum);
-	if (prow)
-		return prow;
 	
 	TO_IMPLEMENT;
 
-	return prow;
+	return TRUE;
 }
 

Modified: branches/V4-branch/providers/skel-implementation/capi/gda-capi-recordset.h
==============================================================================
--- branches/V4-branch/providers/skel-implementation/capi/gda-capi-recordset.h	(original)
+++ branches/V4-branch/providers/skel-implementation/capi/gda-capi-recordset.h	Wed Feb 20 20:36:04 2008
@@ -1,5 +1,5 @@
 /* GDA Capi provider
- * Copyright (C) 1998 - 2006 The GNOME Foundation.
+ * Copyright (C) 2008 The GNOME Foundation.
  *
  * AUTHORS:
  *      TO_ADD: your name and email

Modified: branches/V4-branch/providers/skel-implementation/capi/libgda-capi-4.0.pc.in
==============================================================================
--- branches/V4-branch/providers/skel-implementation/capi/libgda-capi-4.0.pc.in	(original)
+++ branches/V4-branch/providers/skel-implementation/capi/libgda-capi-4.0.pc.in	Wed Feb 20 20:36:04 2008
@@ -4,6 +4,6 @@
 includedir= includedir@
 
 Name: libgda-postgres- GDA_ABI_MAJOR_VERSION@  GDA_ABI_MINOR_VERSION@
-Description: GDA (GNOME Data Access) CApi provider
+Description: GDA (GNOME Data Access) Capi provider
 Requires: libgda- GDA_ABI_MAJOR_VERSION@  GDA_ABI_MINOR_VERSION@
 Version: @VERSION@

Modified: branches/V4-branch/tools/gda-sql.c
==============================================================================
--- branches/V4-branch/tools/gda-sql.c	(original)
+++ branches/V4-branch/tools/gda-sql.c	Wed Feb 20 20:36:04 2008
@@ -1028,10 +1028,19 @@
 	FILE *to_stream;
 	gboolean append_nl = FALSE;
 	gint length;
+	static gint force_no_pager = -1;
 	
 	if (!str)
 		return;
 
+	if (force_no_pager < 0) {
+		/* still unset... */
+		if (getenv ("GDA_NO_PAGER"))
+			force_no_pager = 1;
+		else
+			force_no_pager = 0;	
+	}
+
 	length = strlen (str);
 	if (str[length] != '\n')
 		append_nl = TRUE;
@@ -1041,7 +1050,7 @@
 	else
 		to_stream = stdout;
 
-	if (isatty (fileno (to_stream))) {
+	if (!force_no_pager && isatty (fileno (to_stream))) {
 		/* use pager */
 		FILE *pipe;
 		const char *pager;



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