[libgda] More work on the Oracle provider



commit 3f92a4cd0c7e2eb596d2c1f74e60fa59fd1ff9f1
Author: Vivien Malerba <malerba gnome-db org>
Date:   Wed May 6 22:01:01 2009 +0200

    More work on the Oracle provider
    
    	* providers/oracle:
    	  - use the callback API to fetch results for variable length data types
    	  - implemented more meta data retreival
    	  - booleans (which is not an Oracle data type) are interpreted as 0 an !0
    	  - better handling of OCI types
    	* libgda/gda-data-meta-wrapper.c: bug fixes
    	* libgda/gda-meta-store.c: bug fixes
    	* providers/postgres/gda-postgres-meta.c: bug fixes
---
 ChangeLog                               |   11 +
 libgda/gda-data-meta-wrapper.c          |   64 +++-
 libgda/gda-meta-store.c                 |    2 +-
 providers/oracle/gda-oracle-meta.c      |  545 ++++++++++++++++++++++++++++++-
 providers/oracle/gda-oracle-provider.c  |  312 +++++++++++++++++-
 providers/oracle/gda-oracle-recordset.c |  394 ++++++++++++----------
 providers/oracle/gda-oracle-util.c      |  361 ++++++++++++++------
 providers/oracle/gda-oracle-util.h      |   52 +++-
 providers/oracle/gda-oracle.h           |    4 +
 providers/postgres/gda-postgres-meta.c  |   10 +-
 10 files changed, 1417 insertions(+), 338 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 7fcfd31..5788eee 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2009-05-06  Vivien Malerba <malerba gnome-db org>
+
+	* providers/oracle:
+	  - use the callback API to fetch results for variable length data types
+	  - implemented more meta data retreival
+	  - booleans (which is not an Oracle data type) are interpreted as 0 an !0
+	  - better handling of OCI types
+	* libgda/gda-data-meta-wrapper.c: bug fixes
+	* libgda/gda-meta-store.c: bug fixes
+	* providers/postgres/gda-postgres-meta.c: bug fixes
+
 2009-05-05  Vivien Malerba <malerba gnome-db org>
 
 	* libgda/gda-sql-builder.c:
diff --git a/libgda/gda-data-meta-wrapper.c b/libgda/gda-data-meta-wrapper.c
index 17bf87e..288a6f4 100644
--- a/libgda/gda-data-meta-wrapper.c
+++ b/libgda/gda-data-meta-wrapper.c
@@ -406,7 +406,7 @@ identifier_needs_quotes (const gchar *str, GdaSqlIdentifierStyle mode)
 {
 	const gchar *ptr;
 	for (ptr = str; *ptr; ptr++) {
-		if ((*ptr == ' ') || (*ptr == '"') ||
+		if ((*ptr == ' ') ||
 		    ((mode == GDA_SQL_IDENTIFIERS_LOWER_CASE) && (*ptr != g_ascii_tolower (*ptr))) ||
 		    ((mode == GDA_SQL_IDENTIFIERS_UPPER_CASE) && (*ptr != g_ascii_toupper (*ptr))))
 			return TRUE;
@@ -414,6 +414,26 @@ identifier_needs_quotes (const gchar *str, GdaSqlIdentifierStyle mode)
 	return FALSE;
 }
 
+static gboolean
+identifier_is_all_lower (const gchar *str)
+{
+	const gchar *ptr;
+	for (ptr = str; *ptr; ptr++) {
+		if (*ptr != g_ascii_tolower (*ptr))
+			return FALSE;
+	}
+	return TRUE;
+}
+
+static gchar *
+to_lower (gchar *str)
+{
+	gchar *ptr;
+	for (ptr = str; *ptr; ptr++)
+		*ptr = g_ascii_tolower (*ptr);
+	return str;
+}
+
 /*
  * Returns:
  *  - NULL if no changes are necessary from the current value
@@ -432,29 +452,41 @@ compute_value (const GValue *value, GdaSqlIdentifierStyle mode)
 		return NULL;
 	if ((*str == '"') && (str[strlen(str) - 1] == '"'))
 		return NULL; /* already quoted */
-	if (identifier_needs_quotes (str, mode)) {
-		gchar **sa = g_strsplit (str, ".", 0);
-		if (sa[1]) {
-			gint i;
-			for (i = 0; sa[i]; i++) {
-				if (identifier_needs_quotes (sa[i], mode)) {
-					gchar *tmp = gda_sql_identifier_add_quotes (sa[i]);
-					g_free (sa[i]);
-					sa[i] = tmp;
-				}
+	gchar **sa = g_strsplit (str, ".", 0);
+	if (sa[1]) {
+		gint i;
+		gboolean onechanged = FALSE;
+		for (i = 0; sa[i]; i++) {
+			if (identifier_needs_quotes (sa[i], mode)) {
+				gchar *tmp = gda_sql_identifier_add_quotes (sa[i]);
+				g_free (sa[i]);
+				sa[i] = tmp;
+				onechanged = TRUE;
+			}
+			else if (! identifier_is_all_lower (sa[i])) {
+				to_lower (sa[i]);
+				onechanged = TRUE;
 			}
+		}
+		if (onechanged) {
 			retval = gda_value_new (G_TYPE_STRING);
 			g_value_take_string (retval, g_strjoinv (".", sa));
 		}
-		else {
+	}
+	else {
+		if (identifier_needs_quotes (str, mode)) {
 			retval = gda_value_new (G_TYPE_STRING);
 			g_value_take_string (retval, gda_sql_identifier_add_quotes (str));
 		}
-		g_strfreev (sa);
-		return retval;
+		else if (! identifier_is_all_lower (str)) {
+			gchar *tmp;
+			tmp = to_lower (g_strdup (str));
+			retval = gda_value_new (G_TYPE_STRING);
+			g_value_take_string (retval, tmp);
+		}
 	}
-	else
-		return NULL;
+	g_strfreev (sa);
+	return retval;
 }
 
 /*
diff --git a/libgda/gda-meta-store.c b/libgda/gda-meta-store.c
index 2e89aa7..498300c 100644
--- a/libgda/gda-meta-store.c
+++ b/libgda/gda-meta-store.c
@@ -2502,7 +2502,7 @@ gda_meta_store_modify_v (GdaMetaStore *store, const gchar *table_name,
 					context.column_values = g_new (GValue *, context.size);
 					
 					for (k = 0; k < tfk->cols_nb; k++) {
-						context.column_values [k] = (GValue*) gda_data_model_get_value_at (wrapped_data, 
+						context.column_values [k] = (GValue*) gda_data_model_get_value_at (new_data, 
 									    tfk->ref_pk_cols_array[k], i, error);
 						if (!context.column_values [k]) {
 							g_free (context.column_values);
diff --git a/providers/oracle/gda-oracle-meta.c b/providers/oracle/gda-oracle-meta.c
index 3791e70..06e5fc1 100644
--- a/providers/oracle/gda-oracle-meta.c
+++ b/providers/oracle/gda-oracle-meta.c
@@ -32,6 +32,7 @@
 #include <libgda/gda-data-model-array.h>
 #include <libgda/gda-set.h>
 #include <libgda/gda-holder.h>
+#include "gda-oracle-util.h"
 
 /*
  * predefined statements' IDs
@@ -39,7 +40,16 @@
 typedef enum {
         I_STMT_CATALOG,
         I_STMT_SCHEMAS_ALL,
-	I_STMT_SCHEMA_NAMED
+	I_STMT_SCHEMA_NAMED,
+	I_STMT_TABLES_ALL,
+	I_STMT_TABLES_ALL_RAW,
+	I_STMT_TABLES,
+	I_STMT_TABLE_NAMED,
+	I_STMT_VIEWS_ALL,
+	I_STMT_VIEWS,
+	I_STMT_VIEW_NAMED,
+	I_STMT_COLUMNS_OF_TABLE,
+        I_STMT_COLUMNS_ALL,
 } InternalStatementItem;
 
 
@@ -51,10 +61,37 @@ static gchar *internal_sql[] = {
 	"select ora_database_name from dual",
 
 	/* I_STMT_SCHEMAS_ALL */
-	"SELECT ora_database_name, username, username, CASE WHEN username = user THEN 1 ELSE 0 END FROM all_users",
+	"SELECT ora_database_name, username, username, CASE WHEN username IN ('SYS', 'SYSTEM', 'DBSNMP', 'OUTLN', 'MDSYS', 'ORDSYS', 'ORDPLUGINS', 'CTXSYS', 'DSSYS', 'PERFSTAT', 'WKPROXY', 'WKSYS', 'WMSYS', 'XDB', 'ANONYMOUS', 'ODM', 'ODM_MTR', 'OLAPSYS', 'TRACESVR', 'REPADMIN') THEN 1 ELSE 0 END FROM all_users",
 
 	/* I_STMT_SCHEMA_NAMED */
-	"SELECT ora_database_name, username, username, CASE WHEN username = user THEN 1 ELSE 0 END FROM all_users WHERE username = ##name::string",
+	"SELECT ora_database_name, username, username, CASE WHEN username IN ('SYS', 'SYSTEM', 'DBSNMP', 'OUTLN', 'MDSYS', 'ORDSYS', 'ORDPLUGINS', 'CTXSYS', 'DSSYS', 'PERFSTAT', 'WKPROXY', 'WKSYS', 'WMSYS', 'XDB', 'ANONYMOUS', 'ODM', 'ODM_MTR', 'OLAPSYS', 'TRACESVR', 'REPADMIN') THEN 1 ELSE 0 END FROM all_users WHERE username = ##name::string",
+
+	/* I_STMT_TABLES_ALL */
+	"SELECT ora_database_name, a.owner, a.table_name, 'BASE TABLE', 1, c.comments, CASE WHEN a.owner = user THEN a.table_name ELSE a.owner || '.' || a.table_name END, a.owner || '.' || a.table_name, a.owner FROM all_tables a LEFT JOIN ALL_TAB_COMMENTS c ON (a.table_name=c.table_name) UNION SELECT ora_database_name, v.owner, v.view_name, 'VIEW', 0, c.comments, CASE WHEN v.owner = user THEN v.view_name ELSE v.owner || '.' || v.view_name END, v.owner || '.' || v.view_name, v.owner FROM all_views v LEFT JOIN ALL_TAB_COMMENTS c ON (v.view_name=c.table_name)",
+
+	/* I_STMT_TABLES_ALL_RAW */
+	"SELECT ora_database_name, a.owner, a.table_name FROM all_tables a UNION SELECT ora_database_name, v.owner, v.view_name FROM all_views v",
+
+	/* I_STMT_TABLES */
+	"SELECT ora_database_name, a.owner, a.table_name, 'BASE TABLE', 1, c.comments, CASE WHEN a.owner = user THEN a.table_name ELSE a.owner || '.' || a.table_name END, a.owner || '.' || a.table_name, a.owner FROM all_tables a LEFT JOIN ALL_TAB_COMMENTS c ON (a.table_name=c.table_name) WHERE a.owner = ##schema::string UNION SELECT ora_database_name, v.owner, v.view_name, 'VIEW', 0, c.comments, CASE WHEN v.owner = user THEN v.view_name ELSE v.owner || '.' || v.view_name END, v.owner || '.' || v.view_name, v.owner FROM all_views v LEFT JOIN ALL_TAB_COMMENTS c ON (v.view_name=c.table_name) WHERE v.owner = ##schema::string",
+
+	/* I_STMT_TABLE_NAMED */
+	"SELECT ora_database_name, a.owner, a.table_name, 'BASE TABLE', 1, c.comments, CASE WHEN a.owner = user THEN a.table_name ELSE a.owner || '.' || a.table_name END, a.owner || '.' || a.table_name, a.owner FROM all_tables a LEFT JOIN ALL_TAB_COMMENTS c ON (a.table_name=c.table_name) WHERE a.owner = ##schema::string AND a.table_name = ##name::string UNION SELECT ora_database_name, v.owner, v.view_name, 'VIEW', 0, c.comments, CASE WHEN v.owner = user THEN v.view_name ELSE v.owner || '.' || v.view_name END, v.owner || '.' || v.view_name, v.owner FROM all_views v LEFT JOIN ALL_TAB_COMMENTS c ON (v.view_name=c.table_name) WHERE v.owner = ##schema::string AND v.view_name = ##name::string",
+
+	/* I_STMT_VIEWS_ALL */
+	"SELECT ora_database_name, v.owner, v.view_name, v.text, NULL, 0 FROM all_views v",
+
+	/* I_STMT_VIEWS */
+	"SELECT ora_database_name, v.owner, v.view_name, v.text, NULL, 0 FROM all_views v WHERE v.owner = ##schema::string",
+
+	/* I_STMT_VIEW_NAMED */
+	"SELECT ora_database_name, v.owner, v.view_name, v.text, NULL, 0 FROM all_views v WHERE v.owner = ##schema::string AND v.view_name = ##name::string",
+
+	/* I_STMT_COLUMNS_OF_TABLE */
+	"SELECT ora_database_name, tc.owner, tc.table_name, tc.column_name, tc.column_id, tc.data_default, decode(tc.nullable,'N',0,'Y',1), tc.data_type, NULL, 'gchararray', CASE WHEN tc.char_used = 'C' THEN tc.char_length ELSE NULL END as clen, CASE WHEN tc.char_used = 'B' THEN tc.char_length ELSE NULL END as olen, tc.data_precision, tc.data_scale, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, c.comments  FROM ALL_TAB_COLUMNS tc LEFT JOIN ALL_COL_COMMENTS c ON (tc.owner = c.owner AND tc.table_name=c.table_name AND tc.column_name = c.column_name) WHERE tc.table_name = ##name::string ORDER BY tc.column_id",
+
+        /* I_STMT_COLUMNS_ALL */
+	"SELECT ora_database_name, tc.owner, tc.table_name, tc.column_name, tc.column_id, tc.data_default, decode(tc.nullable,'N',0,'Y',1), tc.data_type, NULL, 'gchararray', CASE WHEN tc.char_used = 'C' THEN tc.char_length ELSE NULL END as clen, CASE WHEN tc.char_used = 'B' THEN tc.char_length ELSE NULL END as olen, tc.data_precision, tc.data_scale, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, c.comments  FROM ALL_TAB_COLUMNS tc LEFT JOIN ALL_COL_COMMENTS c ON (tc.owner = c.owner AND tc.table_name=c.table_name AND tc.column_name = c.column_name) ORDER BY tc.table_name, tc.column_id"
 };
 
 /*
@@ -106,6 +143,7 @@ _gda_oracle_meta__info (GdaServerProvider *prov, GdaConnection *cnc,
 							 error);
 	if (!model)
 		return FALSE;
+	gda_meta_store_set_identifiers_style (store, GDA_SQL_IDENTIFIERS_UPPER_CASE);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 		
@@ -148,6 +186,7 @@ _gda_oracle_meta_udt (GdaServerProvider *prov, GdaConnection *cnc,
 	 */
 	if (!model)
 		return FALSE;
+	gda_meta_store_set_identifiers_style (store, GDA_SQL_IDENTIFIERS_UPPER_CASE);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 
@@ -290,6 +329,7 @@ _gda_oracle_meta__schemata (GdaServerProvider *prov, GdaConnection *cnc,
                                                               GDA_STATEMENT_MODEL_RANDOM_ACCESS, col_types, error);
 	if (!model)
 		return FALSE;
+	gda_meta_store_set_identifiers_style (store, GDA_SQL_IDENTIFIERS_UPPER_CASE);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 		
@@ -312,6 +352,7 @@ _gda_oracle_meta_schemata (GdaServerProvider *prov, GdaConnection *cnc,
 								      GDA_STATEMENT_MODEL_RANDOM_ACCESS, col_types, error);
                 if (!model)
                         return FALSE;
+		gda_meta_store_set_identifiers_style (store, GDA_SQL_IDENTIFIERS_UPPER_CASE);
                 retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
         }
         else {
@@ -322,6 +363,7 @@ _gda_oracle_meta_schemata (GdaServerProvider *prov, GdaConnection *cnc,
                 if (!model)
                         return FALSE;
 
+		gda_meta_store_set_identifiers_style (store, GDA_SQL_IDENTIFIERS_UPPER_CASE);
                 retval = gda_meta_store_modify (store, context->table_name, model, "schema_name = ##name::string", error,
                                                 "name", schema_name_n, NULL);
         }
@@ -330,12 +372,51 @@ _gda_oracle_meta_schemata (GdaServerProvider *prov, GdaConnection *cnc,
         return retval;
 }
 
+static GType col_types_tables[] = {G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_NONE};
+static GType col_types_views[] = {G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_NONE};
+
+
 gboolean
 _gda_oracle_meta__tables_views (GdaServerProvider *prov, GdaConnection *cnc, 
-			      GdaMetaStore *store, GdaMetaContext *context, GError **error)
+				GdaMetaStore *store, GdaMetaContext *context, GError **error)
 {
-	TO_IMPLEMENT;
-	return TRUE;
+	GdaDataModel *tables_model, *views_model;
+        gboolean retval = TRUE;
+
+        OracleConnectionData *cdata;
+        cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data (cnc);
+        if (!cdata)
+                return FALSE;
+
+        tables_model = gda_connection_statement_execute_select_full (cnc, internal_stmt[I_STMT_TABLES_ALL], NULL, 
+								     GDA_STATEMENT_MODEL_RANDOM_ACCESS, col_types_tables,
+								     error);
+        if (!tables_model)
+                return FALSE;
+        views_model = gda_connection_statement_execute_select_full (cnc, internal_stmt[I_STMT_VIEWS_ALL], NULL,
+								    GDA_STATEMENT_MODEL_RANDOM_ACCESS, col_types_views,
+								    error);
+        if (!views_model) {
+                g_object_unref (tables_model);
+                return FALSE;
+        }
+
+	gda_meta_store_set_identifiers_style (store, GDA_SQL_IDENTIFIERS_UPPER_CASE);
+
+	GdaMetaContext c2;
+        c2 = *context; /* copy contents, just because we need to modify @context->table_name */
+        if (retval) {
+                c2.table_name = "_tables";
+                retval = gda_meta_store_modify_with_context (store, &c2, tables_model, error);
+        }
+        if (retval) {
+                c2.table_name = "_views";
+                retval = gda_meta_store_modify_with_context (store, &c2, views_model, error);
+        }
+        g_object_unref (tables_model);
+        g_object_unref (views_model);
+
+        return retval;
 }
 
 gboolean
@@ -344,23 +425,459 @@ _gda_oracle_meta_tables_views (GdaServerProvider *prov, GdaConnection *cnc,
 			     const GValue *table_catalog, const GValue *table_schema, 
 			     const GValue *table_name_n)
 {
-	TO_IMPLEMENT;
-	return TRUE;
+	GdaDataModel *tables_model, *views_model;
+        gboolean retval = TRUE;
+
+        OracleConnectionData *cdata;
+        cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data (cnc);
+        if (!cdata)
+                return FALSE;
+
+	if (! gda_holder_set_value (gda_set_get_holder (i_set, "schema"), table_schema, error))
+                return FALSE;
+
+	if (!table_name_n) {
+		tables_model = gda_connection_statement_execute_select_full (cnc, internal_stmt[I_STMT_TABLES], i_set, 
+									     GDA_STATEMENT_MODEL_RANDOM_ACCESS, col_types_tables,
+									     error);
+		if (!tables_model)
+			return FALSE;
+		views_model = gda_connection_statement_execute_select_full (cnc, internal_stmt[I_STMT_VIEWS], i_set,
+									    GDA_STATEMENT_MODEL_RANDOM_ACCESS, col_types_views,
+									    error);
+		if (!views_model) {
+			g_object_unref (tables_model);
+			return FALSE;
+		}
+	}
+	else {
+		if (! gda_holder_set_value (gda_set_get_holder (i_set, "name"), table_name_n, error))
+                        return FALSE;
+		tables_model = gda_connection_statement_execute_select_full (cnc, internal_stmt[I_STMT_TABLE_NAMED], i_set, 
+									     GDA_STATEMENT_MODEL_RANDOM_ACCESS, col_types_tables,
+									     error);
+		if (!tables_model)
+			return FALSE;
+		views_model = gda_connection_statement_execute_select_full (cnc, internal_stmt[I_STMT_VIEW_NAMED], i_set,
+									    GDA_STATEMENT_MODEL_RANDOM_ACCESS, col_types_views,
+									    error);
+		if (!views_model) {
+			g_object_unref (tables_model);
+			return FALSE;
+		}
+	}
+
+	gda_meta_store_set_identifiers_style (store, GDA_SQL_IDENTIFIERS_UPPER_CASE);
+
+	GdaMetaContext c2;
+        c2 = *context; /* copy contents, just because we need to modify @context->table_name */
+        if (retval) {
+                c2.table_name = "_tables";
+                retval = gda_meta_store_modify_with_context (store, &c2, tables_model, error);
+        }
+        if (retval) {
+                c2.table_name = "_views";
+                retval = gda_meta_store_modify_with_context (store, &c2, views_model, error);
+        }
+        g_object_unref (tables_model);
+        g_object_unref (views_model);
+
+        return retval;
+}
+
+/*
+ * Returns: a new G_TYPE_STRING GValue
+ */
+static GValue *
+oracle_identifier_to_value (const gchar *sqlid)
+{
+	GValue *v;
+	g_return_val_if_fail (sqlid, NULL);
+
+	v = gda_value_new (G_TYPE_STRING);
+	if (g_ascii_isalnum (*sqlid)) {
+		const gchar *ptr;
+		for (ptr = sqlid; *ptr; ptr++) {
+			if ((*ptr == ' ') || (*ptr != g_ascii_toupper (*ptr))) {
+				/* add quotes */
+				g_value_take_string (v, gda_sql_identifier_add_quotes (sqlid));
+				return v;
+			}
+		}
+
+		g_value_set_string (v, sqlid);
+	}
+	else
+		g_value_take_string (v, gda_sql_identifier_add_quotes (sqlid));
+	return v;
 }
 
 gboolean
 _gda_oracle_meta__columns (GdaServerProvider *prov, GdaConnection *cnc, 
-			 GdaMetaStore *store, GdaMetaContext *context, GError **error)
+			   GdaMetaStore *store, GdaMetaContext *context, GError **error)
 {
-	TO_IMPLEMENT;
-	return TRUE;
+	GdaDataModel *model, *tables;
+	gboolean retval = FALSE;
+	gint i, nrows;
+	OracleConnectionData *cdata;
+
+	cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata)
+		return FALSE;
+
+	/* use a prepared statement for the "base" model */
+	tables = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_TABLES_ALL_RAW], NULL, error);
+	if (!tables)
+		return FALSE;
+
+	model = gda_data_model_array_new_with_g_types (24, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, 
+						       G_TYPE_INT, G_TYPE_STRING, G_TYPE_BOOLEAN,
+						       G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+						       G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, 
+						       G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+						       G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+						       G_TYPE_BOOLEAN, G_TYPE_STRING);
+
+	/* fill in @model */
+	const GValue *cv0 = NULL;
+	GList *values = NULL;
+	nrows = gda_data_model_get_n_rows (tables);
+	for (i = 0; i < nrows; i++) {
+		const GValue *cv1, *cv2;
+		values = NULL;
+
+		if (!cv0) {
+			cv0 = gda_data_model_get_value_at (tables, 0, i, error);
+			if (!cv0)
+				goto out;
+		}
+		if (!(cv1 = gda_data_model_get_value_at (tables, 1, i, error)) ||
+		    !(cv2 = gda_data_model_get_value_at (tables, 2, i, error)))
+			goto out;
+
+		/* Allocate the Describe handle */
+		int result;
+		OCIDescribe *dschp = (OCIDescribe *) 0;
+		GdaConnectionEvent *event;
+
+		result = OCIHandleAlloc ((dvoid *) cdata->henv,
+					 (dvoid **) &dschp,
+					 (ub4) OCI_HTYPE_DESCRIBE,
+					 (size_t) 0,
+					 (dvoid **) 0);
+		if ((event = gda_oracle_check_result ((result), (cnc), (cdata), OCI_HTYPE_ERROR,
+						      _("Could not fetch next row")))) {
+			g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_DATA_ERROR,
+				     "%s", gda_connection_event_get_description (event));
+			goto out;
+		}
+
+		/* Describe the table */
+		gchar *fq_tblname;
+		const gchar *schema_name, *table_name;
+		GValue *v1, *v2;
+		v1 = oracle_identifier_to_value (g_value_get_string (cv1));
+		schema_name = g_value_get_string (v1);
+		v2 = oracle_identifier_to_value (g_value_get_string (cv2));
+		table_name = g_value_get_string (v2);
+		fq_tblname = g_strdup_printf ("%s.%s", schema_name, table_name);
+		gda_value_free (v1);
+		gda_value_free (v2);
+
+		result = OCIDescribeAny (cdata->hservice,
+					 cdata->herr,
+					 (text *) fq_tblname,
+					 strlen (fq_tblname),
+					 OCI_OTYPE_NAME,
+					 0,
+					 OCI_PTYPE_UNK,
+					 (OCIDescribe *) dschp);
+		g_free (fq_tblname);
+		if ((event = gda_oracle_check_result ((result), (cnc), (cdata), OCI_HTYPE_ERROR,
+						      _("Could not get a description handle")))) {
+			g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_DATA_ERROR,
+				     "%s", gda_connection_event_get_description (event));
+			OCIHandleFree ((dvoid *) dschp, OCI_HTYPE_DESCRIBE);
+			goto out;
+		}
+
+
+		/* Get the parameter handle */
+		OCIParam *parmh;
+		result = OCIAttrGet ((dvoid *) dschp,
+				     (ub4) OCI_HTYPE_DESCRIBE,
+				     (dvoid **) &parmh,
+				     (ub4 *) 0,
+				     (ub4) OCI_ATTR_PARAM,
+				     (OCIError *) cdata->herr);
+		if ((event = gda_oracle_check_result ((result), (cnc), (cdata), OCI_HTYPE_ERROR,
+						      _("Could not get parameter handle")))) {
+			g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_DATA_ERROR,
+				     "%s", gda_connection_event_get_description (event));
+			OCIHandleFree ((dvoid *) dschp, OCI_HTYPE_DESCRIBE);
+			goto out;
+		}
+
+		/* Get the number of columns */
+		ub2 numcols;
+		OCIParam *collsthd;
+		result = OCIAttrGet ((dvoid *) parmh,
+				     (ub4) OCI_DTYPE_PARAM,
+				     (dvoid *) &numcols,
+				     (ub4 *) 0,
+				     (ub4) OCI_ATTR_NUM_COLS,
+				     (OCIError *) cdata->herr);
+		if ((event = gda_oracle_check_result ((result), (cnc), (cdata), OCI_HTYPE_ERROR,
+						      _("Could not get attribute")))) {
+			g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_DATA_ERROR,
+				     "%s", gda_connection_event_get_description (event));
+			OCIHandleFree ((dvoid *) dschp, OCI_HTYPE_DESCRIBE);
+			goto out;
+		}
+
+		result = OCIAttrGet ((dvoid *) parmh,
+				     (ub4) OCI_DTYPE_PARAM,
+				     (dvoid *) &collsthd,
+				     (ub4 *) 0,
+				     (ub4) OCI_ATTR_LIST_COLUMNS,
+				     (OCIError *) cdata->herr);
+		if ((event = gda_oracle_check_result ((result), (cnc), (cdata), OCI_HTYPE_ERROR,
+						      _("Could not get attribute")))) {
+			g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_DATA_ERROR,
+				     "%s", gda_connection_event_get_description (event));
+			OCIHandleFree ((dvoid *) dschp, OCI_HTYPE_DESCRIBE);
+			goto out;
+		}
+		
+		/* fetch information for each column, loop starts at 1! */
+		gint col;
+		for (col = 1; col <= numcols; col++) {
+			/* column's catalog, schema, table */
+			GValue *v;
+			values = g_list_prepend (NULL, (gpointer) cv0);
+			v = oracle_identifier_to_value (g_value_get_string (cv1));
+			values = g_list_prepend (values, v);
+			v = oracle_identifier_to_value (g_value_get_string (cv2));
+			values = g_list_prepend (values, v);
+
+			/* Get the column handle */
+			OCIParam *colhd;
+			result = OCIParamGet ((dvoid *) collsthd,
+					      (ub4) OCI_DTYPE_PARAM,
+					      (OCIError *) cdata->herr,
+					      (dvoid **) &colhd,
+					      (ub2) col);
+			if ((event = gda_oracle_check_result ((result), (cnc), (cdata), OCI_HTYPE_ERROR,
+							      _("Could not get attribute")))) {
+				g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_DATA_ERROR,
+					     "%s", gda_connection_event_get_description (event));
+				OCIHandleFree ((dvoid *) dschp, OCI_HTYPE_DESCRIBE);
+				goto out;
+			}
+
+			/* Field name */
+			text *strp;
+			ub4 sizep;
+			result = OCIAttrGet ((dvoid *) colhd,
+					     (ub4) OCI_DTYPE_PARAM,
+					     (dvoid *) &strp,
+					     (ub4 *) &sizep,
+					     (ub4) OCI_ATTR_NAME,
+					     (OCIError *) cdata->herr);
+			if ((event = gda_oracle_check_result ((result), (cnc), (cdata), OCI_HTYPE_ERROR,
+							      _("Could not get attribute")))) {
+				g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_DATA_ERROR,
+					     "%s", gda_connection_event_get_description (event));
+				OCIDescriptorFree ((dvoid *) colhd, OCI_DTYPE_PARAM);
+				OCIHandleFree ((dvoid *) dschp, OCI_HTYPE_DESCRIBE);
+				goto out;
+			}
+			gchar *tmpname;
+			tmpname = (gchar*) g_malloc (sizep + 1);
+			strncpy (tmpname, strp, sizep);
+			tmpname[sizep] = 0;
+			v = oracle_identifier_to_value (tmpname);
+			g_free (tmpname);
+			values = g_list_prepend (values, v);
+			
+			/* ordinal position */
+			g_value_set_int ((v = gda_value_new (G_TYPE_INT)), col);
+			values = g_list_prepend (values, v);
+
+			/* default */
+			values = g_list_prepend (values, gda_value_new_null ());
+
+			/* Not null? */
+			ub1 nullable;
+			result = OCIAttrGet ((dvoid *)colhd,
+					     (ub4) OCI_DTYPE_PARAM,
+					     (dvoid *) &nullable,
+					     (ub4 *) 0,
+					     (ub4) OCI_ATTR_IS_NULL,
+					     (OCIError *) cdata->herr);
+			if ((event = gda_oracle_check_result ((result), (cnc), (cdata), OCI_HTYPE_ERROR,
+							      _("Could not get attribute")))) {
+				g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_DATA_ERROR,
+					     "%s", gda_connection_event_get_description (event));
+				OCIDescriptorFree ((dvoid *) colhd, OCI_DTYPE_PARAM);
+				OCIHandleFree ((dvoid *) dschp, OCI_HTYPE_DESCRIBE);
+				goto out;
+			}
+			g_value_set_boolean ((v = gda_value_new (G_TYPE_BOOLEAN)), ! (nullable > 0));
+			values = g_list_prepend (values, v);
+
+			/* Data type */
+			ub2 type;
+			ub1 precision;
+			sb1 scale;
+			result = OCIAttrGet ((dvoid *)colhd,
+					     (ub4) OCI_DTYPE_PARAM,
+					     (dvoid *) &type,
+					     (ub4 *) 0,
+					     (ub4) OCI_ATTR_DATA_TYPE,
+					     (OCIError *) cdata->herr);
+			if ((event = gda_oracle_check_result ((result), (cnc), (cdata), OCI_HTYPE_ERROR,
+							      _("Could not get attribute")))) {
+				g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_DATA_ERROR,
+					     "%s", gda_connection_event_get_description (event));
+				OCIDescriptorFree ((dvoid *) colhd, OCI_DTYPE_PARAM);
+				OCIHandleFree ((dvoid *) dschp, OCI_HTYPE_DESCRIBE);
+				goto out;
+			}
+			
+			result = OCIAttrGet ((dvoid *)colhd,
+					     (ub4) OCI_DTYPE_PARAM,
+					     (dvoid *) &precision,
+					     (ub4 *) 0,
+					     (ub4) OCI_ATTR_PRECISION,
+					     (OCIError *) cdata->herr);
+			if ((event = gda_oracle_check_result ((result), (cnc), (cdata), OCI_HTYPE_ERROR,
+							      _("Could not get attribute")))) {
+				g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_DATA_ERROR,
+					     "%s", gda_connection_event_get_description (event));
+				OCIDescriptorFree ((dvoid *) colhd, OCI_DTYPE_PARAM);
+				OCIHandleFree ((dvoid *) dschp, OCI_HTYPE_DESCRIBE);
+				goto out;
+			}
+
+			result = OCIAttrGet ((dvoid *)colhd,
+					     (ub4) OCI_DTYPE_PARAM,
+					     (dvoid *) &scale,
+					     (ub4 *) 0,
+					     (ub4) OCI_ATTR_SCALE,
+					     (OCIError *) cdata->herr);
+			if ((event = gda_oracle_check_result ((result), (cnc), (cdata), OCI_HTYPE_ERROR,
+							      _("Could not get attribute")))) {
+				g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_DATA_ERROR,
+					     "%s", gda_connection_event_get_description (event));
+				OCIDescriptorFree ((dvoid *) colhd, OCI_DTYPE_PARAM);
+				OCIHandleFree ((dvoid *) dschp, OCI_HTYPE_DESCRIBE);
+				goto out;
+			}
+
+			g_value_set_string ((v = gda_value_new (G_TYPE_STRING)), _oracle_sqltype_to_string (type));
+			values = g_list_prepend (values, v);
+
+			/* array spec */
+			values = g_list_prepend (values, gda_value_new_null ());
+			
+			/* GType */
+			const gchar *ctmp;
+			ctmp = g_type_name (_oracle_sqltype_to_g_type (type, precision, scale));
+			g_value_set_string ((v = gda_value_new (G_TYPE_STRING)),
+					    ctmp ? ctmp : "GdaBinary");
+			values = g_list_prepend (values, v);
+
+			/* character_maximum_length */
+			values = g_list_prepend (values, gda_value_new_null ());
+
+			/* character_octet_length */
+			values = g_list_prepend (values, gda_value_new_null ());
+
+			/* numeric_precision */
+			g_value_set_int ((v = gda_value_new (G_TYPE_INT)), precision);
+			values = g_list_prepend (values, v);
+
+			/* numeric_scale */
+			g_value_set_int ((v = gda_value_new (G_TYPE_INT)), scale);
+			values = g_list_prepend (values, v);
+
+			/* datetime_precision */
+			values = g_list_prepend (values, gda_value_new_null ());
+
+			/* character_set_catalog */
+			values = g_list_prepend (values, gda_value_new_null ());
+
+			/* character_set_schema */
+			values = g_list_prepend (values, gda_value_new_null ());
+			
+			/* character_set_name */
+			values = g_list_prepend (values, gda_value_new_null ());
+
+			/* collation_catalog */
+			values = g_list_prepend (values, gda_value_new_null ());
+
+			/* collation_schema */
+			values = g_list_prepend (values, gda_value_new_null ());
+			
+			/* collation_name */
+			values = g_list_prepend (values, gda_value_new_null ());
+
+			/* extra */
+			values = g_list_prepend (values, gda_value_new_null ());
+
+			/* is_updatable */
+			values = g_list_prepend (values, gda_value_new_null ());
+
+			/* column_comments */
+			values = g_list_prepend (values, gda_value_new_null ());
+
+			/* add to @model */
+			gint newrow;
+			values = g_list_reverse (values);
+			newrow = gda_data_model_append_values (model, values, error);
+			
+			/* free values */
+			g_list_foreach (values->next, (GFunc) gda_value_free, NULL);
+			g_list_free (values);
+			values = NULL;
+			if (newrow == -1)
+				goto out;
+		}
+
+		OCIHandleFree ((dvoid *) dschp, OCI_HTYPE_DESCRIBE);		
+	}
+	retval = TRUE;
+
+ out:
+	if (values) {
+		/* in case of error */
+		values = g_list_reverse (values);
+		g_list_foreach (values->next, (GFunc) gda_value_free, NULL);
+		g_list_free (values);
+	}
+
+	/* modify meta store with @model */
+	if (retval) {
+		FILE *out;
+		out = fopen ("_columns", "w");
+		gda_data_model_dump (model, out);
+		fclose (out);
+
+		gda_meta_store_set_identifiers_style (store, GDA_SQL_IDENTIFIERS_UPPER_CASE);
+		retval = gda_meta_store_modify_with_context (store, context, model, error);
+	}
+	g_object_unref (tables);
+	g_object_unref (model);
+
+	return retval;
 }
 
 gboolean
 _gda_oracle_meta_columns (GdaServerProvider *prov, GdaConnection *cnc, 
-			GdaMetaStore *store, GdaMetaContext *context, GError **error,
-			const GValue *table_catalog, const GValue *table_schema, 
-			const GValue *table_name)
+			  GdaMetaStore *store, GdaMetaContext *context, GError **error,
+			  const GValue *table_catalog, const GValue *table_schema, 
+			  const GValue *table_name)
 {
 	TO_IMPLEMENT;
 	return TRUE;
diff --git a/providers/oracle/gda-oracle-provider.c b/providers/oracle/gda-oracle-provider.c
index 42253f8..7bdf4c6 100644
--- a/providers/oracle/gda-oracle-provider.c
+++ b/providers/oracle/gda-oracle-provider.c
@@ -252,6 +252,29 @@ gda_oracle_provider_class_init (GdaOracleProviderClass *klass)
 
 	/* thread safe */
 	provider_class->limiting_thread = NULL;
+
+	/* static types */
+	static_types = g_new (GType, GDA_STYPE_NULL + 1);
+	static_types[GDA_STYPE_INT] = G_TYPE_INT;
+	static_types[GDA_STYPE_STRING] = G_TYPE_STRING;
+	static_types[GDA_STYPE_BOOLEAN] = G_TYPE_BOOLEAN;
+	static_types[GDA_STYPE_DATE] = G_TYPE_DATE;
+	static_types[GDA_STYPE_TIME] = GDA_STYPE_TIME;
+	static_types[GDA_STYPE_TIMESTAMP] = GDA_STYPE_TIMESTAMP;
+	static_types[GDA_STYPE_INT64] = G_TYPE_INT64;
+	static_types[GDA_STYPE_UINT] = G_TYPE_UINT;
+	static_types[GDA_STYPE_FLOAT] = G_TYPE_FLOAT;
+	static_types[GDA_STYPE_DOUBLE] = G_TYPE_DOUBLE;
+	static_types[GDA_STYPE_LONG] = G_TYPE_LONG;
+	static_types[GDA_STYPE_ULONG] = G_TYPE_ULONG;
+	static_types[GDA_STYPE_NUMERIC] = GDA_STYPE_NUMERIC;
+	static_types[GDA_STYPE_BINARY] = GDA_STYPE_BINARY;
+	static_types[GDA_STYPE_BLOB] = GDA_STYPE_BLOB;
+	static_types[GDA_STYPE_CHAR] = G_TYPE_CHAR;
+	static_types[GDA_STYPE_SHORT] = GDA_STYPE_SHORT;
+	static_types[GDA_STYPE_GTYPE] = G_TYPE_GTYPE;
+	static_types[GDA_STYPE_GEOMETRIC_POINT] = GDA_STYPE_GEOMETRIC_POINT;
+	static_types[GDA_STYPE_NULL] = GDA_TYPE_NULL;
 }
 
 static void
@@ -613,6 +636,35 @@ gda_oracle_provider_open_connection (GdaServerProvider *provider, GdaConnection
 	cdata->schema = g_ascii_strup (username, -1);
 	gda_connection_internal_set_provider_data (cnc, cdata, (GDestroyNotify) gda_oracle_free_cnc_data);
 
+	/* get version */
+	gchar version [512];
+	cdata->version = NULL;
+	cdata->major_version = 8;
+	cdata->minor_version = 0;
+	result = OCIServerVersion (cdata->hservice, cdata->herr, version, 511, OCI_HTYPE_SVCCTX);
+	if ((result == OCI_SUCCESS) || (result = OCI_SUCCESS_WITH_INFO)) {
+		cdata->version = g_strdup (version);
+		gchar *tmp, *ptr;
+		tmp = g_ascii_strdown (version, -1);
+		ptr = strstr (tmp, "release");
+		if (ptr) {
+			for (ptr += 7; *ptr; ptr++) {
+				if (! g_ascii_isspace (*ptr))
+					break;
+			}
+			if (g_ascii_isdigit (*ptr)) {
+				cdata->major_version = *ptr - '0';
+				ptr++;
+				if (*ptr) {
+					ptr++;
+					if (g_ascii_isdigit (*ptr))
+						cdata->minor_version = *ptr - '0';
+				}
+			}
+		}
+		g_free (tmp);
+	}
+
 	/* Optionnally set some attributes for the newly opened connection (encoding to UTF-8 for example )*/
 	if (! execute_raw_command (cnc, "ALTER SESSION SET NLS_DATE_FORMAT = 'MM/DD/YYYY'") ||
 	    ! execute_raw_command (cnc, "ALTER SESSION SET NLS_NUMERIC_CHARACTERS = \". \"")) {
@@ -674,6 +726,7 @@ static const gchar *
 gda_oracle_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc)
 {
 	OracleConnectionData *cdata;
+	static guchar version[512];
 
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
@@ -681,8 +734,8 @@ gda_oracle_provider_get_server_version (GdaServerProvider *provider, GdaConnecti
 	cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data (cnc);
 	if (!cdata) 
 		return FALSE;
-	TO_IMPLEMENT;
-	return NULL;
+
+	return cdata->version;
 }
 
 /*
@@ -1154,7 +1207,11 @@ gda_oracle_provider_create_parser (GdaServerProvider *provider, GdaConnection *c
  * 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 *oracle_render_select (GdaSqlStatementSelect *stmt, GdaSqlRenderingContext *context, GError **error);
 static gchar *oracle_render_select_target (GdaSqlSelectTarget *target, GdaSqlRenderingContext *context, GError **error);
+static gchar *oracle_render_expr (GdaSqlExpr *expr, GdaSqlRenderingContext *context,
+                                  gboolean *is_default, gboolean *is_null,
+                                  GError **error);
 
 static gchar *
 gda_oracle_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection *cnc,
@@ -1173,7 +1230,9 @@ gda_oracle_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection
 	memset (&context, 0, sizeof (context));
 	context.params = params;
 	context.flags = flags;
+	context.render_select = (GdaSqlRenderingFunc) oracle_render_select;
 	context.render_select_target = (GdaSqlRenderingFunc) oracle_render_select_target;
+	context.render_expr = oracle_render_expr; /* render "FALSE" as 0 and TRUE as !0 */
 
 	str = gda_statement_to_sql_real (stmt, &context, error);
 
@@ -1224,6 +1283,214 @@ oracle_render_select_target (GdaSqlSelectTarget *target, GdaSqlRenderingContext
         return NULL;
 }
 
+static gchar *
+oracle_render_select (GdaSqlStatementSelect *stmt, GdaSqlRenderingContext *context, GError **error)
+{
+	GString *string;
+	gchar *str;
+	GSList *list;
+
+	g_return_val_if_fail (stmt, NULL);
+	g_return_val_if_fail (GDA_SQL_ANY_PART (stmt)->type == GDA_SQL_ANY_STMT_SELECT, NULL);
+
+	string = g_string_new ("SELECT ");
+	/* distinct */
+	if (stmt->distinct) {
+		g_string_append (string, "DISTINCT ");
+		if (stmt->distinct_expr) {
+			str = context->render_expr (stmt->distinct_expr, context, NULL, NULL, error);
+			if (!str) goto err;
+			g_string_append (string, "ON ");
+			g_string_append (string, str);
+			g_string_append_c (string, ' ');
+			g_free (str);
+		}
+	}
+	
+	/* selected expressions */
+	for (list = stmt->expr_list; list; list = list->next) {
+		str = context->render_select_field (GDA_SQL_ANY_PART (list->data), context, error);
+		if (!str) goto err;
+		if (list != stmt->expr_list)
+			g_string_append (string, ", ");
+		g_string_append (string, str);
+		g_free (str);
+	}
+
+	/* FROM */
+	if (stmt->from) {
+		str = context->render_select_from (GDA_SQL_ANY_PART (stmt->from), context, error);
+		if (!str) goto err;
+		g_string_append_c (string, ' ');
+		g_string_append (string, str);
+		g_free (str);
+	}
+	else {
+		g_string_append (string, " FROM DUAL");
+	}
+
+	/* WHERE */
+	if (stmt->where_cond) {
+		g_string_append (string, " WHERE ");
+		str = context->render_expr (stmt->where_cond, context, NULL, NULL, error);
+		if (!str) goto err;
+		g_string_append (string, str);
+		g_free (str);
+	}
+
+	/* LIMIT */
+	if (stmt->limit_count) {
+		if (stmt->where_cond)
+			g_string_append (string, " AND");
+		else
+			g_string_append (string, " WHERE");
+		
+		if (stmt->limit_offset) {
+			g_set_error (error, GDA_STATEMENT_ERROR, GDA_STATEMENT_SYNTAX_ERROR,
+				     _("Oracle does not support the offset with a limit"));
+			goto err;
+		}
+		else {
+			g_string_append (string, " ROWNUM <= (");
+			str = context->render_expr (stmt->limit_count, context, NULL, NULL, error);
+			if (!str) goto err;
+			g_string_append (string, str);
+			g_free (str);
+			g_string_append_c (string, ')');
+		}
+	}
+
+	/* GROUP BY */
+	for (list = stmt->group_by; list; list = list->next) {
+		str = context->render_expr (list->data, context, NULL, NULL, error);
+		if (!str) goto err;
+		if (list != stmt->group_by)
+			g_string_append (string, ", ");
+		else
+			g_string_append (string, " GROUP BY ");
+		g_string_append (string, str);
+		g_free (str);
+	}
+
+	/* HAVING */
+	if (stmt->having_cond) {
+		g_string_append (string, " HAVING ");
+		str = context->render_expr (stmt->having_cond, context, NULL, NULL, error);
+		if (!str) goto err;
+		g_string_append (string, str);
+		g_free (str);
+	}
+
+	/* ORDER BY */
+	for (list = stmt->order_by; list; list = list->next) {
+		str = context->render_select_order (GDA_SQL_ANY_PART (list->data), context, error);
+		if (!str) goto err;
+		if (list != stmt->order_by)
+			g_string_append (string, ", ");
+		else
+			g_string_append (string, " ORDER BY ");
+		g_string_append (string, str);
+		g_free (str);
+	}
+
+	str = string->str;
+	g_string_free (string, FALSE);
+	return str;
+
+ err:
+	g_string_free (string, TRUE);
+	return NULL;
+}
+
+static gchar *
+oracle_render_expr (GdaSqlExpr *expr, GdaSqlRenderingContext *context, 
+		    gboolean *is_default, gboolean *is_null,
+		    GError **error)
+{
+	GString *string;
+	gchar *str = NULL;
+
+	g_return_val_if_fail (expr, NULL);
+	g_return_val_if_fail (GDA_SQL_ANY_PART (expr)->type == GDA_SQL_ANY_EXPR, NULL);
+
+	if (is_default)
+		*is_default = FALSE;
+	if (is_null)
+		*is_null = FALSE;
+
+	/* can't have: 
+	 *  - expr->cast_as && expr->param_spec 
+	 */
+	if (!gda_sql_any_part_check_structure (GDA_SQL_ANY_PART (expr), error)) return NULL;
+
+	string = g_string_new ("");
+	if (expr->param_spec) {
+		str = context->render_param_spec (expr->param_spec, expr, context, is_default, is_null, error);
+		if (!str) goto err;
+	}
+	else if (expr->value) {
+		str = gda_value_stringify (expr->value);
+		if (!str) goto err;
+		if (is_null && gda_value_is_null (expr->value))
+			*is_null = TRUE;
+		else if (is_default && (G_VALUE_TYPE (expr->value) == G_TYPE_STRING) && 
+			 !g_ascii_strcasecmp (g_value_get_string (expr->value), "default"))
+			*is_default = TRUE;
+		else if (!g_ascii_strcasecmp (str, "FALSE")) {
+			g_free (str);
+			str = g_strdup ("0");
+		}
+		else if (!g_ascii_strcasecmp (str, "TRUE")) {
+			g_free (str);
+			str = g_strdup ("1");
+		}
+	}
+	else if (expr->func) {
+		str = context->render_function (GDA_SQL_ANY_PART (expr->func), context, error);
+		if (!str) goto err;
+	}
+	else if (expr->cond) {
+		str = context->render_operation (GDA_SQL_ANY_PART (expr->cond), context, error);
+		if (!str) goto err;
+	}
+	else if (expr->select) {
+		gchar *str1;
+		str1 = context->render_select (GDA_SQL_ANY_PART (expr->select), context, error);
+		if (!str1) goto err;
+		str = g_strdup_printf ("(%s)", str1);
+		g_free (str1);
+	}
+	else if (expr->case_s) {
+		str = context->render_case (GDA_SQL_ANY_PART (expr->case_s), context, error);
+		if (!str) goto err;
+	}
+	else {
+		if (is_null)
+			*is_null = TRUE;
+		str = g_strdup ("NULL");
+	}
+
+	if (!str) {
+		/* TO REMOVE */
+		str = g_strdup ("[...]");
+	}
+
+	if (expr->cast_as) 
+		g_string_append_printf (string, "CAST (%s AS %s)", str, expr->cast_as);
+	else
+		g_string_append (string, str);
+	g_free (str);
+
+	str = string->str;
+	g_string_free (string, FALSE);
+	return str;
+
+ err:
+	g_string_free (string, TRUE);
+	return NULL;
+}
+
+
 /*
  * Statement prepare request
  *
@@ -1392,7 +1659,13 @@ gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 	/* get/create new prepared statement */
 	ps = (GdaOraclePStmt *) gda_connection_get_prepared_statement (cnc, stmt);
 	if (!ps) {
-		if (!gda_oracle_provider_statement_prepare (provider, cnc, stmt, NULL)) {
+		GError *lerror = NULL;
+		if (!gda_oracle_provider_statement_prepare (provider, cnc, stmt, &lerror)) {
+			if (lerror && (lerror->domain == GDA_STATEMENT_ERROR) &&
+			    (lerror->code == GDA_STATEMENT_SYNTAX_ERROR)) {
+				g_propagate_error (error, lerror);
+				return 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,
@@ -1401,6 +1674,7 @@ gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 			 * Don't call gda_connection_add_prepared_statement() with this new prepared statement
 			 * as it will be destroyed once used.
 			 */
+			
 			TO_IMPLEMENT;
 			return NULL;
 		}
@@ -1421,7 +1695,8 @@ gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 		const gchar *pname = (gchar *) list->data;
 		gchar *real_pname = NULL;
 		GdaHolder *h;
-		
+		GdaOracleValue *ora_value = NULL;
+
 		/* find requested parameter */
 		if (!params) {
 			event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
@@ -1457,13 +1732,13 @@ gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 			else {
                                 /* bind param to NULL */
 				/* Hint: Indicator Variables, see p. 118 */
-                                TO_IMPLEMENT;
+				ora_value = g_new0 (GdaOracleValue, 1);
+				ora_value->indicator = -1;
                                 empty_rs = TRUE;
-                                continue;
                         }
 
 		}
-		if (!gda_holder_is_valid (h)) {
+		else if (!gda_holder_is_valid (h)) {
 			if (! allow_noparam) {
 				gchar *str;
 				str = g_strdup_printf (_("Parameter '%s' is invalid"), pname);
@@ -1476,15 +1751,17 @@ gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 			}
 			else {
                                 /* bind param to NULL */
-				TO_IMPLEMENT;
+				ora_value = g_new0 (GdaOracleValue, 1);
+				ora_value->indicator = -1;
                                 empty_rs = TRUE;
-                                continue;
                         }
 		}
 
 		/* actual binding using the C API, for parameter at position @i */
-		const GValue *value = gda_holder_get_value (h);
-		GdaOracleValue *ora_value = _gda_value_to_oracle_value (value);
+		if (!ora_value) {
+			const GValue *value = gda_holder_get_value (h);
+			ora_value = _gda_value_to_oracle_value (value);
+		}
 		OCIBind *bindpp = (OCIBind *) 0;
 		int result;
 		result = OCIBindByName ((dvoid *) ps->hstmt,
@@ -1566,8 +1843,9 @@ gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 					 (ub4) 0,
 					 (CONST OCISnapshot *) NULL,
 					 (OCISnapshot *) NULL,
-					 OCI_STMT_SCROLLABLE_READONLY); /* not OCI_COMMIT_ON_SUCCESS because transactions are
-									   handled separately */
+					 OCI_DEFAULT);
+		/* or OCI_STMT_SCROLLABLE_READONLY, not OCI_COMMIT_ON_SUCCESS because transactions are
+		   handled separately */
 		
 		event = gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
 						 _("Could not execute the Oracle statement"));
@@ -1652,7 +1930,8 @@ gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
                 }
 
                 data_model = gda_oracle_recordset_new (cnc, ps, params, flags, col_types);
-		gda_connection_internal_statement_executed (cnc, stmt, params, NULL); /* required: help @cnc keep some stats */
+		if (data_model)
+			gda_connection_internal_statement_executed (cnc, stmt, params, NULL); /* required: help @cnc keep some stats */
 		g_object_unref (ps);
 		return (GObject*) data_model;
         }
@@ -1846,8 +2125,9 @@ gda_oracle_free_cnc_data (OracleConnectionData *cdata)
                 OCIHandleFree ((dvoid *) cdata->herr, OCI_HTYPE_ERROR);
         if (cdata->henv)
                 OCIHandleFree ((dvoid *) cdata->henv, OCI_HTYPE_ENV);
-        if (cdata->schema)
-                g_free(cdata->schema);
+
+	g_free (cdata->schema);
+	g_free (cdata->version);
 
 	g_free (cdata);
 }
diff --git a/providers/oracle/gda-oracle-recordset.c b/providers/oracle/gda-oracle-recordset.c
index fe978cc..4b91804 100644
--- a/providers/oracle/gda-oracle-recordset.c
+++ b/providers/oracle/gda-oracle-recordset.c
@@ -31,6 +31,7 @@
 #include "gda-oracle-util.h"
 
 #define _GDA_PSTMT(x) ((GdaPStmt*)(x))
+#define BUFFER_SIZE 4095 /* size of the buffer to fecth data from the server using the callback API (OCIDefineDynamic) */
 
 static void gda_oracle_recordset_class_init (GdaOracleRecordsetClass *klass);
 static void gda_oracle_recordset_init       (GdaOracleRecordset *recset,
@@ -48,10 +49,14 @@ static GdaRow  *new_row (GdaDataSelect *imodel, GdaConnection *cnc, GdaOraclePSt
 
 struct _GdaOracleRecordsetPrivate {
 	gint     next_row_num;
-	gboolean is_scrollable; /* if FALSE => in RANDOM access mode we need to perform some caching like for SQLite */
 };
 static GObjectClass *parent_class = NULL;
 
+#ifdef GDA_DEBUG
+#define TS_DIFF(a,b) (((b).tv_sec * 1000000 + (b).tv_usec) - ((a).tv_sec * 1000000 + (a).tv_usec))
+#include <sys/time.h>
+#endif
+
 /*
  * Object init and finalize
  */
@@ -61,7 +66,6 @@ gda_oracle_recordset_init (GdaOracleRecordset *recset,
 {
 	g_return_if_fail (GDA_IS_ORACLE_RECORDSET (recset));
 	recset->priv = g_new0 (GdaOracleRecordsetPrivate, 1);
-	recset->priv->is_scrollable = FALSE;
 	recset->priv->next_row_num = 0;
 }
 
@@ -129,6 +133,44 @@ gda_oracle_recordset_get_type (void)
 	return type;
 }
 
+static sb4
+ora_def_callback (GdaOracleValue *ora_value,
+		  OCIDefine *def,
+		  ub4 iter,
+		  dvoid **bufpp,
+		  ub4 **alenpp,
+		  ub1 *piecep,
+		  dvoid **indpp,
+		  ub2 **rcodep)
+{
+	if (!ora_value->value) {
+		/* 1st chunk */
+		ora_value->defined_size = 0;
+		ora_value->value = g_new0 (guchar, BUFFER_SIZE + 1);
+		*bufpp = ora_value->value;
+	}
+	else {
+		/* other chunks */
+		ora_value->defined_size += ora_value->xlen; /* previous's chunk's real size */
+#ifdef GDA_DEBUG_NO
+		gint i;
+		g_print ("XLEN= %d\n", ora_value->xlen);
+		for (i = 0 ; i < ora_value->defined_size; i++)
+			g_print ("SO FAR[%d]=[%d]%c\n", i, ((gchar*) ora_value->value)[i],
+				 g_unichar_isgraph (((gchar*) ora_value->value)[i]) ? ((gchar*) ora_value->value)[i] : '-');
+#endif
+		ora_value->value = g_renew (guchar, ora_value->value, ora_value->defined_size + BUFFER_SIZE);
+		*bufpp = ora_value->value + ora_value->defined_size;
+	}
+
+	ora_value->xlen = BUFFER_SIZE;
+	*alenpp = &(ora_value->xlen);
+	*indpp = (dvoid *) &(ora_value->indicator);
+	*rcodep = (ub2 *) &(ora_value->rcode);
+
+	return OCI_CONTINUE;
+}
+
 /*
  * the @ps struct is modified and transfered to the new data model created in
  * this function
@@ -141,10 +183,8 @@ gda_oracle_recordset_new (GdaConnection *cnc, GdaOraclePStmt *ps, GdaSet *exec_p
         OracleConnectionData *cdata;
         gint i;
 	GdaDataModelAccessFlags rflags;
-	int result;
 
 	gint nb_rows = -1;
-	gboolean is_scrollable = FALSE;
 
         g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
         g_return_val_if_fail (ps != NULL, NULL);
@@ -206,6 +246,7 @@ gda_oracle_recordset_new (GdaConnection *cnc, GdaOraclePStmt *ps, GdaSet *exec_p
 			GdaColumn *column;
 			int result;
 			GdaOracleValue *ora_value;
+			gboolean use_callback = FALSE;
 
 			ora_value = g_new0 (GdaOracleValue, 1);
 			ora_values = g_list_prepend (ora_values, ora_value);
@@ -227,13 +268,14 @@ gda_oracle_recordset_new (GdaConnection *cnc, GdaOraclePStmt *ps, GdaSet *exec_p
 					     OCI_DTYPE_PARAM,
 					     &(ora_value->defined_size),
 					     0,
-					     OCI_ATTR_DATA_SIZE,
+					     (ub4) OCI_ATTR_DATA_SIZE,
 					     cdata->herr);
 			if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
 						     _("Could not get the parameter defined size"))) {
 				g_list_foreach (ora_values, (GFunc) _gda_oracle_value_free, NULL);
 				return NULL;
 			}
+			ora_value->defined_size++;
 			
 			/* data type */
 			result = OCIAttrGet ((dvoid *) (ora_value->pard),
@@ -248,6 +290,37 @@ gda_oracle_recordset_new (GdaConnection *cnc, GdaOraclePStmt *ps, GdaSet *exec_p
 				return NULL;
 			}
 
+			result = OCIAttrGet ((dvoid *) (ora_value->pard),
+					     OCI_DTYPE_PARAM,
+					     &(ora_value->precision),
+					     0,
+					     OCI_ATTR_PRECISION,
+					     cdata->herr);
+			if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+						     _("Could not get the type's precision"))) {
+				g_list_foreach (ora_values, (GFunc) _gda_oracle_value_free, NULL);
+				return NULL;
+			}
+
+			result = OCIAttrGet ((dvoid *) (ora_value->pard),
+					     OCI_DTYPE_PARAM,
+					     &(ora_value->scale),
+					     0,
+					     OCI_ATTR_SCALE,
+					     cdata->herr);
+			if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+						     _("Could not get the type's scale"))) {
+				g_list_foreach (ora_values, (GFunc) _gda_oracle_value_free, NULL);
+				return NULL;
+			}
+
+#ifdef GDA_DEBUG_NO
+			g_print ("--COL type is %d, GType is %s, ORA defined size is %d\n",
+				 ora_value->sql_type,
+				 g_type_name (ora_value->g_type),
+				 ora_value->defined_size - 1);
+#endif
+
 			/* column's name */
 			text *name;
 			ub4 name_len;
@@ -274,30 +347,58 @@ gda_oracle_recordset_new (GdaConnection *cnc, GdaOraclePStmt *ps, GdaSet *exec_p
 			g_free (name_buffer);
 
 			/* for data fetching  */
-			ub2 fake_type;
-			fake_type = ora_value->sql_type;
+			if (_GDA_PSTMT (ps)->types [i] != GDA_TYPE_NULL)
+				ora_value->sql_type = _g_type_to_oracle_sqltype (_GDA_PSTMT (ps)->types [i]);
+
 			switch (ora_value->sql_type) {
-			case SQLT_NUM: /* Numerics are coerced to string */
-				fake_type = SQLT_CHR;
+			case SQLT_CHR: /* for G_TYPE_STRING => request SQLT_CHR */
+			case SQLT_STR:
+			case SQLT_VCS:
+			case SQLT_RID:
+			case SQLT_AVC:
+			case SQLT_AFC:
+				ora_value->sql_type = SQLT_CHR;
+				if (ora_value->defined_size == 1)
+					use_callback = TRUE;
+				break;
+
+			case SQLT_INT:
+				ora_value->defined_size = sizeof (gint);
 				break;
-			case SQLT_DAT: /* Convert SQLT_DAT to OCIDate */
-				fake_type = SQLT_ODT;
+
+			case SQLT_FLT:
+			case SQLT_BFLOAT:
+				ora_value->defined_size = sizeof (gfloat);
+				break;
+
+			case SQLT_BDOUBLE:
+				ora_value->defined_size = sizeof (gdouble);
+				break;
+								
+			case SQLT_DAT: /* request OCIDate */
+				ora_value->sql_type = SQLT_ODT;
+				break;
+
+			case SQLT_NUM: /* for GDA_TYPE_NUMERIC => request SQLT_CHR */
+			case SQLT_VNU:
+				ora_value->sql_type = SQLT_CHR;
+				break;
+				
+			case SQLT_LBI:
+			case SQLT_LVB:
+			case SQLT_LVC:
+			case SQLT_LNG:
+			case SQLT_VBI:
+			case SQLT_BIN:
+				use_callback = TRUE;
 				break;
 			}
 			
 			if (_GDA_PSTMT (ps)->types [i] != GDA_TYPE_NULL)
 				ora_value->g_type = _GDA_PSTMT (ps)->types [i];
 			else
-				ora_value->g_type = _oracle_sqltype_to_g_type (ora_value->sql_type);
-			/*
-			if (col_size_array && (i < col_size_array->len)) {
-				ub2 size;
-				
-				size = g_array_index (col_size_array, ub2, i);
-				if (size > 0)
-					ora_value->defined_size = size;
-			}
-			*/
+				ora_value->g_type = _oracle_sqltype_to_g_type (ora_value->sql_type, ora_value->precision, 
+									       ora_value->scale);
 			if (ora_value->g_type == GDA_TYPE_BLOB) {
 				/* allocate a Lob locator */
 				OCILobLocator *lob;
@@ -313,13 +414,22 @@ gda_oracle_recordset_new (GdaConnection *cnc, GdaOraclePStmt *ps, GdaSet *exec_p
 				ora_value->value = lob;
 				ora_value->defined_size = 0;
 			}
-			else if (ora_value->defined_size == 0)
+			else if (use_callback) {
 				ora_value->value = NULL;
-			else {
-				ora_value->defined_size++;
-				ora_value->value = g_malloc0 (ora_value->defined_size);
+				ora_value->defined_size = 33554432; /* 32M */
 			}
+			else
+				ora_value->value = g_malloc0 (ora_value->defined_size);
 			
+			ora_value->s_type = gda_g_type_to_static_type (ora_value->g_type);
+#ifdef GDA_DEBUG_NO
+			g_print ("**COL type is %d, GType is %s, ORA defined size is %d%s\n",
+				 ora_value->sql_type,
+				 g_type_name (ora_value->g_type),
+				 ora_value->defined_size - 1,
+				 use_callback ? " using callback": "");
+#endif
+
 			ora_value->hdef = (OCIDefine *) 0;
 			ora_value->indicator = 0;
 			result = OCIDefineByPos ((OCIStmt *) ps->hstmt,
@@ -328,71 +438,51 @@ gda_oracle_recordset_new (GdaConnection *cnc, GdaOraclePStmt *ps, GdaSet *exec_p
 						 (ub4) i + 1,
 						 ora_value->value,
 						 ora_value->defined_size,
-						 (ub2) fake_type,
+						 ora_value->sql_type,
 						 (dvoid *) &(ora_value->indicator),
-						 (ub2 *) 0,
-						 (ub2 *) 0,
-						 (ub4) OCI_DEFAULT);
+						 &(ora_value->rlen),
+						 &(ora_value->rcode),
+						 (ub4) (use_callback ? OCI_DYNAMIC_FETCH : OCI_DEFAULT));
 			if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
 						     _("Could not define by position"))) {
 				OCIDescriptorFree ((dvoid *) ora_value->pard, OCI_DTYPE_PARAM);
 				g_list_foreach (ora_values, (GFunc) _gda_oracle_value_free, NULL);
 				return NULL;
 			}
+
+			if (use_callback) {
+				result = OCIDefineDynamic ((OCIDefine *) (ora_value->hdef),
+							   (OCIError *) (cdata->herr),
+							   (dvoid*) (ora_value),
+							   (OCICallbackDefine) ora_def_callback);
+				if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+							     _("Could not define by position"))) {
+					OCIDescriptorFree ((dvoid *) ora_value->pard, OCI_DTYPE_PARAM);
+					g_list_foreach (ora_values, (GFunc) _gda_oracle_value_free, NULL);
+					return NULL;
+				}
+			}
+
+			ora_value->use_callback = use_callback;
 		}
 
 		ps->ora_values = g_list_reverse (ora_values);
         }
 
-	/* determine if cursor is scrollable or not as "Remote mapped queries cannot be used with scrollable cursors"
-	 * or so says dthe doc.
-	 * Also set the prefetch rows number */
-	result = OCIStmtFetch2 (ps->hstmt,
-                                cdata->herr,
-                                (ub4) 1,
-                                (ub2) OCI_FETCH_LAST,
-                                (sb4) 0,
-                                (ub4) OCI_DEFAULT);
-	if (result == OCI_NO_DATA)
-                nb_rows = 0;
-	else if (result != OCI_ERROR) {
-		is_scrollable = TRUE;
-	
-		/* get number of rows */
-		ub4 pos;
-                result = OCIAttrGet (ps->hstmt, OCI_HTYPE_STMT,
-                                     (dvoid *) &pos, NULL,
-                                     OCI_ATTR_CURRENT_POSITION, cdata->herr);
-                if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
-					     _("Could not get the current position"))) 
-                        return NULL;
-		nb_rows = pos;
-
-		/* go back to 1st row */
-		result = OCIStmtFetch2 (ps->hstmt,
-					cdata->herr,
-					(ub4) 1,
-					(ub2) OCI_FETCH_FIRST,
-					(sb4) 0,
-					(ub4) OCI_DEFAULT);
-		if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
-                                             _("Could not move to position")))
-			return NULL;
-
-		/* set prefetch size */
-		ub4 prefetch;
-		prefetch = (ub4) ((gfloat) nb_rows * 0.2);
-		if (prefetch > 1)
-			OCIAttrSet (ps->hstmt, OCI_HTYPE_STMT,
-				    &prefetch, 0,
-				    OCI_ATTR_PREFETCH_ROWS, cdata->herr);
-	}
-
-	/* determine access mode: RANDOM or CURSOR FORWARD are the only supported */
-	if (flags & GDA_DATA_MODEL_ACCESS_RANDOM)
-		rflags = GDA_DATA_MODEL_ACCESS_RANDOM;
-	else
-		rflags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD;
+	/* determine access mode: RANDOM or CURSOR FORWARD are the only supported; if CURSOR BACKWARD
+         * is requested, then we need RANDOM mode */
+        if (flags & GDA_DATA_MODEL_ACCESS_RANDOM)
+                rflags = GDA_DATA_MODEL_ACCESS_RANDOM;
+        else if (flags & GDA_DATA_MODEL_ACCESS_CURSOR_BACKWARD)
+                rflags = GDA_DATA_MODEL_ACCESS_RANDOM;
+        else
+                rflags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD;
+
+	ub4 prefetch;
+	prefetch = (ub4) (100);
+	OCIAttrSet (ps->hstmt, OCI_HTYPE_STMT,
+		    &prefetch, 0,
+		    OCI_ATTR_PREFETCH_ROWS, cdata->herr);
 
 	/* create data model */
         model = g_object_new (GDA_TYPE_ORACLE_RECORDSET, 
@@ -401,9 +491,6 @@ gda_oracle_recordset_new (GdaConnection *cnc, GdaOraclePStmt *ps, GdaSet *exec_p
 			      "model-usage", rflags, 
 			      "exec-params", exec_params, NULL);
 	GDA_DATA_SELECT (model)->advertized_nrows = nb_rows;
-	GDA_ORACLE_RECORDSET (model)->priv->is_scrollable = is_scrollable;
-
-	g_print ("DETECTED %d rows, %s\n", nb_rows, is_scrollable ? "SCROLLABLE" : "NON SCROLLABLE");
 	
         return GDA_DATA_MODEL (model);
 }
@@ -420,30 +507,41 @@ fetch_next_oracle_row (GdaOracleRecordset *model, gboolean do_store, GError **er
 	cnc = gda_data_select_get_connection ((GdaDataSelect*) model);
 	cdata = (OracleConnectionData*)	gda_connection_internal_get_provider_data (cnc);
 	if (!cdata)
-		return FALSE;
+		return NULL;
 
 	/* fetch row */
-	result = OCIStmtFetch2 (ps->hstmt,
-				cdata->herr,
-				(ub4) 1,
-				(ub2) OCI_FETCH_NEXT,
-				(sb4) 1,
-				(ub4) OCI_DEFAULT);
+	if (cdata->major_version > 9)
+		result = OCIStmtFetch2 (ps->hstmt,
+					cdata->herr,
+					(ub4) 1,
+					(ub2) OCI_FETCH_NEXT,
+					(sb4) 1,
+					(ub4) OCI_DEFAULT);
+	else
+		result = OCIStmtFetch (ps->hstmt,
+				       cdata->herr,
+				       (ub4) 1,
+				       (ub2) OCI_FETCH_NEXT,
+				       (ub4) OCI_DEFAULT);
 	if (result == OCI_NO_DATA) {
 		GDA_DATA_SELECT (model)->advertized_nrows = model->priv->next_row_num;
 		return NULL;
 	}
-	else if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
-					  _("Could not fetch requested row"))) {
-		/* set @error */
-		TO_IMPLEMENT;
-		return FALSE;
+	else {
+		GdaConnectionEvent *event;
+		if ((event = gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+						      _("Could not fetch next row")))) {
+			/* set @error */
+			g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_DATA_ERROR,
+				     "%s", gda_connection_event_get_description (event));
+
+			return NULL;
+		}
 	}
-	
+
 	prow = new_row ((GdaDataSelect*) model, cnc, ps);
-	gda_data_select_take_row (model, prow, model->priv->next_row_num);
+	gda_data_select_take_row ((GdaDataSelect*) model, prow, model->priv->next_row_num);
 	model->priv->next_row_num ++;
-	g_print ("Next row: %d\n", model->priv->next_row_num);
 
 	return prow;
 }
@@ -462,9 +560,17 @@ gda_oracle_recordset_fetch_nb_rows (GdaDataSelect *model)
         if (model->advertized_nrows >= 0)
                 return model->advertized_nrows;
 
+	struct timeval stm1, stm2;
+
+	gettimeofday (&stm1, NULL);
+
         for (prow = fetch_next_oracle_row (imodel, TRUE, NULL);
              prow;
              prow = fetch_next_oracle_row (imodel, TRUE, NULL));
+
+	gettimeofday (&stm2, NULL);
+	/*g_print ("TOTAL time to get nb rows: %0.2f ms\n", (float) (TS_DIFF(stm1,stm2) / 1000.));*/
+
         return model->advertized_nrows;
 }
 
@@ -486,42 +592,31 @@ gda_oracle_recordset_fetch_nb_rows (GdaDataSelect *model)
 static gboolean 
 gda_oracle_recordset_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
 {
-	int result;
-	GdaOraclePStmt *ps = GDA_ORACLE_PSTMT (model->prep_stmt);
+	GdaOracleRecordset *imodel;
 	OracleConnectionData *cdata;
 	GdaConnection *cnc;
 
 	if (*prow)
                 return TRUE;
 
+	imodel = GDA_ORACLE_RECORDSET (model);
 	cnc = gda_data_select_get_connection (model);
 	cdata = (OracleConnectionData*)	gda_connection_internal_get_provider_data (cnc);
 	if (!cdata)
 		return FALSE;
 
-	if (GDA_ORACLE_RECORDSET (model)->priv->is_scrollable) {
-		/* fetch row */
-		result = OCIStmtFetch2 (ps->hstmt,
-					cdata->herr,
-					(ub4) 1,
-					(ub2) OCI_FETCH_ABSOLUTE,
-					(sb4) rownum + 1,
-					(ub4) OCI_DEFAULT);
-		if (result == OCI_NO_DATA) {
-			model->advertized_nrows = rownum - 1;
-		}
-		else if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
-						  _("Could not fetch requested row"))) {
-			/* set @error */
-			TO_IMPLEMENT;
+	for (; imodel->priv->next_row_num <= rownum; ) {
+		*prow = fetch_next_oracle_row (imodel, TRUE, error);
+		if (!*prow) {
+			/*if (GDA_DATA_SELECT (model)->advertized_nrows >= 0), it's not an error */
+			if ((GDA_DATA_SELECT (model)->advertized_nrows >= 0) &&
+			    (imodel->priv->next_row_num < rownum)) {
+				g_set_error (error, 0,
+					     GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR,
+					     _("Row %d not found"), rownum);
+			}
 			return FALSE;
 		}
-		
-		*prow = new_row (model, cnc, ps);
-		gda_data_select_take_row (model, *prow, rownum);
-	}
-	else {
-		TO_IMPLEMENT;
 	}
 	return TRUE;
 }
@@ -561,39 +656,11 @@ gda_oracle_recordset_store_all (GdaDataSelect *model, GError **error)
 static gboolean 
 gda_oracle_recordset_fetch_next (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
 {
-	int result;
-	GdaOraclePStmt *ps = GDA_ORACLE_PSTMT (model->prep_stmt);
-	OracleConnectionData *cdata;
-	GdaConnection *cnc;
-
 	if (*prow)
                 return TRUE;
 
-	cnc = gda_data_select_get_connection (model);
-	cdata = (OracleConnectionData*)	gda_connection_internal_get_provider_data (cnc);
-	if (!cdata)
-		return FALSE;
-
-	/* fetch row */
-	result = OCIStmtFetch2 (ps->hstmt,
-				cdata->herr,
-				(ub4) 1,
-				(ub2) OCI_FETCH_NEXT,
-				(sb4) 1,
-				(ub4) OCI_DEFAULT);
-	if (result == OCI_NO_DATA) {
-		model->advertized_nrows = rownum - 1;
-	}
-	else if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
-					  _("Could not fetch requested row"))) {
-		/* set @error */
-		TO_IMPLEMENT;
-		return FALSE;
-	}
-	
-	*prow = new_row (model, cnc, ps);
-	gda_data_select_take_row (model, *prow, rownum);
-	return TRUE;
+	*prow = fetch_next_oracle_row ((GdaOracleRecordset*) model, TRUE, error);
+	return *prow ? TRUE : FALSE;
 }
 
 /*
@@ -611,8 +678,6 @@ gda_oracle_recordset_fetch_next (GdaDataSelect *model, GdaRow **prow, gint rownu
 static gboolean 
 gda_oracle_recordset_fetch_prev (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
 {
-	int result;
-	GdaOraclePStmt *ps = GDA_ORACLE_PSTMT (model->prep_stmt);
 	OracleConnectionData *cdata;
 	GdaConnection *cnc;
 
@@ -624,31 +689,8 @@ gda_oracle_recordset_fetch_prev (GdaDataSelect *model, GdaRow **prow, gint rownu
 	if (!cdata)
 		return FALSE;
 
-	if (GDA_ORACLE_RECORDSET (model)->priv->is_scrollable) {
-		/* fetch row */
-		result = OCIStmtFetch2 (ps->hstmt,
-					cdata->herr,
-					(ub4) 1,
-					(ub2) OCI_FETCH_PRIOR,
-					(sb4) 1,
-					(ub4) OCI_DEFAULT);
-		if (result == OCI_NO_DATA) {
-			model->advertized_nrows = rownum - 1;
-		}
-		else if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
-						  _("Could not fetch requested row"))) {
-			/* set @error */
-			TO_IMPLEMENT;
-			return FALSE;
-		}
-		
-		*prow = new_row (model, cnc, ps);
-		gda_data_select_take_row (model, *prow, rownum);
-	}
-	else {
-		TO_IMPLEMENT;
-	}
-	return TRUE;
+	g_warning ("Internal implementation error: non scrollable cursor requested to go backward!\n");
+	return FALSE;
 }
 
 /*
diff --git a/providers/oracle/gda-oracle-util.c b/providers/oracle/gda-oracle-util.c
index caed135..2930efc 100644
--- a/providers/oracle/gda-oracle-util.c
+++ b/providers/oracle/gda-oracle-util.c
@@ -48,13 +48,11 @@
 GdaConnectionEvent *
 _gda_oracle_make_error (dvoid *hndlp, ub4 type, const gchar *file, gint line)
 {
-	GdaConnectionEvent *error;
+	GdaConnectionEvent *error = NULL;
 	gchar errbuf[512];
 	ub4 errcode;
 	gchar *source;
 
-	error = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
-
 	if (hndlp != NULL) {
 		OCIErrorGet ((dvoid *) hndlp,
 			     (ub4) 1, 
@@ -64,16 +62,25 @@ _gda_oracle_make_error (dvoid *hndlp, ub4 type, const gchar *file, gint line)
 			     (ub4) sizeof (errbuf), 
 			     (ub4) type);
 	
-		gda_connection_event_set_description (error, errbuf);
-		/*g_warning ("Oracle error:%s", errbuf);*/
+		if (errcode != 1405) {
+			error = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+			gda_connection_event_set_description (error, errbuf);
+			/*g_warning ("Oracle error:%s", errbuf);*/
+			if (errcode == 600)
+				g_warning ("Maybe an Oracle bug...");
+		}
 	} 
-	else 
+	else {
+		error = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
 		gda_connection_event_set_description (error, _("NO DESCRIPTION"));
+	}
 	
-	gda_connection_event_set_code (error, errcode);
-	source = g_strdup_printf ("gda-oracle:%s:%d", file, line);
-	gda_connection_event_set_source (error, source);
-	g_free(source);
+	if (error) {
+		gda_connection_event_set_code (error, errcode);
+		source = g_strdup_printf ("gda-oracle:%s:%d", file, line);
+		gda_connection_event_set_source (error, source);
+		g_free(source);
+	}
 	
 	return error;
 }
@@ -114,10 +121,12 @@ _gda_oracle_handle_error (gint result, GdaConnection *cnc,
 			break;
 		case OCI_HTYPE_ENV:
 			error = _gda_oracle_make_error (cdata->henv, type, file, line);
-			gda_connection_add_event (cnc, error);
+			if (error)
+				gda_connection_add_event (cnc, error);
 			break;
 		default:
-			error = gda_connection_add_event_string (cnc, msg);
+			if (error)
+				error = gda_connection_add_event_string (cnc, msg);
 			gda_connection_add_event (cnc, error);
 			break;
 		}
@@ -131,13 +140,15 @@ _gda_oracle_handle_error (gint result, GdaConnection *cnc,
 		error = gda_connection_add_event_string (cnc, msg);
 	}
 
+#ifdef GDA_DEBUG
 	if (error)
 		g_print ("HANDLED error: %s\n", gda_connection_event_get_description (error));
+#endif
 	return error;
 }
 
 GType 
-_oracle_sqltype_to_g_type (const ub2 sqltype)
+_oracle_sqltype_to_g_type (const ub2 sqltype, sb2 precision, sb1 scale)
 {
 	/* an incomplete list of all the oracle types */
 	switch (sqltype) {
@@ -145,28 +156,40 @@ _oracle_sqltype_to_g_type (const ub2 sqltype)
 	case SQLT_STR:
 	case SQLT_VCS:
 	case SQLT_RID:
-	case SQLT_LNG:
-	case SQLT_LVC:
-	case SQLT_AFC:
 	case SQLT_AVC:
-	case SQLT_LAB:
-	case SQLT_VST:
+	case SQLT_AFC:
 		return G_TYPE_STRING;
 	case SQLT_NUM:
-		return GDA_TYPE_NUMERIC;
+	case SQLT_VNU:
+		if (scale == 0)
+			return G_TYPE_INT;
+		else if ((precision != 0) && (scale == -127))
+			return G_TYPE_FLOAT;
+		else return GDA_TYPE_NUMERIC;
 	case SQLT_INT:
 		return G_TYPE_INT;
 	case SQLT_UIN:
 		return G_TYPE_UINT;
+	case SQLT_BFLOAT:
 	case SQLT_FLT:
 		return G_TYPE_FLOAT;
+	case SQLT_BDOUBLE:
+		return G_TYPE_DOUBLE;
+		
+	case SQLT_LVC:
+	case SQLT_LVB:
 	case SQLT_VBI:
 	case SQLT_BIN:
+	case SQLT_LNG:
 	case SQLT_LBI:
-	case SQLT_LVB:
+	case SQLT_RDD:
+	case SQLT_NTY:
+	case SQLT_REF:
+		return GDA_TYPE_BINARY;
 	case SQLT_BLOB:
-	case SQLT_BFILEE:
-	case SQLT_CFILEE:
+	case SQLT_FILE:
+	//case SQLT_BFILEE:
+	//case SQLT_CFILEE:
 	case SQLT_CLOB:
 		return GDA_TYPE_BLOB;
 	case SQLT_DAT:
@@ -180,24 +203,69 @@ _oracle_sqltype_to_g_type (const ub2 sqltype)
 	case SQLT_TIMESTAMP_TZ:
 	case SQLT_TIMESTAMP_LTZ:
 		return GDA_TYPE_TIMESTAMP;
-	case SQLT_SLS:
-	case SQLT_CUR:
-	case SQLT_RDD:
-	case SQLT_OSL:
-	case SQLT_NTY:
-	case SQLT_REF:
-	case SQLT_RSET:
-	case SQLT_NCO:
-	case SQLT_INTERVAL_YM:
-	case SQLT_INTERVAL_DS:
-	case SQLT_VNU:
-	case SQLT_PDN:
-	case SQLT_NON:
+	//case SQLT_VST:
+	//case SQLT_SLS:
+	//case SQLT_CUR:
+	//case SQLT_OSL:
+
+	//case SQLT_RSET:
+	//case SQLT_NCO:
+	//case SQLT_INTERVAL_YM:
+	//case SQLT_INTERVAL_DS:
+	//case SQLT_PDN:
+	//case SQLT_NON:
 	default:
 		return G_TYPE_INVALID;
 	}
 }
 
+ub2
+_g_type_to_oracle_sqltype (GType type)
+{
+	if (type == G_TYPE_BOOLEAN)
+		return SQLT_INT;
+	else if (type == G_TYPE_STRING) 
+		return SQLT_CHR;
+	else if (type == G_TYPE_INT)
+		return SQLT_INT;
+	else if (type == G_TYPE_DATE)
+		return SQLT_ODT;
+	else if (type == GDA_TYPE_TIME)
+		return SQLT_TIME;
+	else if (type == G_TYPE_INT64)
+		return SQLT_CHR;
+	else if (type == G_TYPE_UINT)
+		return SQLT_UIN;
+	else if (type == G_TYPE_ULONG)
+		return SQLT_INT;
+	else if (type == G_TYPE_LONG)
+		return SQLT_INT;
+	else if (type == GDA_TYPE_SHORT)
+		return SQLT_INT;
+	else if (type == G_TYPE_FLOAT)
+		return SQLT_BFLOAT;
+	else if (type == G_TYPE_DOUBLE)
+		return SQLT_BDOUBLE;
+	else if (type == GDA_TYPE_NUMERIC)
+		return SQLT_CHR;
+	else if (type == GDA_TYPE_GEOMETRIC_POINT)
+		return SQLT_CHR;
+	else if (type == GDA_TYPE_TIMESTAMP)
+		return SQLT_TIMESTAMP;
+	else if (type == GDA_TYPE_BINARY)
+		return SQLT_LNG;
+	else if (type == GDA_TYPE_BLOB)
+		return SQLT_BLOB;
+	else if (type == G_TYPE_GTYPE)
+		return SQLT_CHR;
+	else if (type == G_TYPE_CHAR)
+		return SQLT_INT;
+	else {
+		g_warning ("Internal implementation missing: type %s not handled", g_type_name (type));
+		return SQLT_LNG;
+	}
+}
+
 gchar * 
 _oracle_sqltype_to_string (const ub2 sqltype)
 {
@@ -210,18 +278,20 @@ _oracle_sqltype_to_string (const ub2 sqltype)
 	case SQLT_INT:
 		return "INTEGER";
 	case SQLT_FLT:
+	case SQLT_BFLOAT:
+	case SQLT_BDOUBLE:
 		return "FLOAT";
 	case SQLT_STR:
 		return "STRING";
 	case SQLT_VNU:
 		return "VARNUM";
-	case SQLT_PDN:
+	//case SQLT_PDN:
 		return "";
 	case SQLT_LNG:
 		return "LONG";
 	case SQLT_VCS:
 		return "VARCHAR";
-	case SQLT_NON:
+	//case SQLT_NON:
 		return "";
 	case SQLT_RID:
 		return "ROWID";
@@ -235,7 +305,7 @@ _oracle_sqltype_to_string (const ub2 sqltype)
 		return "LONG RAW";
 	case SQLT_UIN:
 		return "UNSIGNED INT";
-	case SQLT_SLS:
+	//case SQLT_SLS:
 		return "";
 	case SQLT_LVC:
 		return "LONG VARCHAR";
@@ -245,18 +315,18 @@ _oracle_sqltype_to_string (const ub2 sqltype)
 		return "CHAR";
 	case SQLT_AVC:
 		return "CHARZ";
-	case SQLT_CUR:
+	//case SQLT_CUR:
 		return "CURSOR";
 	case SQLT_RDD:
 		return "ROWID";
-	case SQLT_LAB:
+	//case SQLT_LAB:
 		return "LABEL";
-	case SQLT_OSL:
+	//case SQLT_OSL:
 		return "OSLABEL";
 	case SQLT_NTY:
-		return "";
+		return "NAMED DATA TYPE";
 	case SQLT_REF:
-		return "";
+		return "REF";
 	case SQLT_CLOB:
 		return "CLOB";
 	case SQLT_BLOB:
@@ -265,11 +335,11 @@ _oracle_sqltype_to_string (const ub2 sqltype)
 		return "BFILE";
 	case SQLT_CFILEE:
 		return "CFILE";
-	case SQLT_RSET:
+	//case SQLT_RSET:
 		return "RESULT SET";
-	case SQLT_NCO:
+	//case SQLT_NCO:
 		return "";
-	case SQLT_VST:
+	//case SQLT_VST:
 		return "";
 	case SQLT_ODT:
 		return "OCI DATE";
@@ -283,14 +353,14 @@ _oracle_sqltype_to_string (const ub2 sqltype)
 		return "TIMESTAMP";
 	case SQLT_TIMESTAMP_TZ:
 		return "TIMESTAMP WITH TIME ZONE";
-	case SQLT_INTERVAL_YM:
+	//case SQLT_INTERVAL_YM:
 		return "INTERVAL YEAR TO MONTH";
-	case SQLT_INTERVAL_DS:
+	//case SQLT_INTERVAL_DS:
 		return "INTERVAL DAY TO SECOND";
 	case SQLT_TIMESTAMP_LTZ:
 		return "TIMESTAMP WITH LOCAL TIME ZONE";
 	default:
-		return "UNKNOWN";
+		return "UNDEFINED";
 	}
 }
 
@@ -400,6 +470,21 @@ _gda_value_to_oracle_value (const GValue *value)
 			ora_value->defined_size = 0;
 		}
 	}
+	else if (type == GDA_TYPE_BINARY) {
+		GdaBinary *bin;
+
+		bin = (GdaBinary *) gda_value_get_binary ((GValue *) value);
+		if (bin) {
+			ora_value->sql_type = SQLT_LNG;
+			ora_value->value = bin->data;
+			ora_value->defined_size = bin->binary_length;
+		}
+		else {
+			ora_value->sql_type = SQLT_CHR;
+			ora_value->value = g_strdup ("");
+			ora_value->defined_size = 0;
+		}
+	}
 	else {
 		gchar *val_str;
 		val_str = gda_value_stringify ((GValue *) value);
@@ -421,59 +506,42 @@ _gda_oracle_set_value (GValue *value,
 {
 	GdaTime gtime;
 	GdaTimestamp timestamp;
-	GdaNumeric numeric;
 	sb2 year;
 	ub1 month;
 	ub1 day;
 	ub1 hour;
 	ub1 min;
 	ub1 sec;
-	GType type;
-	gchar *string_buffer, *tmp;
 
-	if (-1 == (ora_value->indicator)) {
+	if (ora_value->indicator == -1) {
 		gda_value_set_null (value);
 		return;
 	}
 
-	type = ora_value->g_type;
-	gda_value_reset_with_type (value, type);
-	if (type == G_TYPE_BOOLEAN) 
-		g_value_set_boolean (value, (atoi (ora_value->value)) ? TRUE: FALSE);
-	else if (type == G_TYPE_STRING) {
-		string_buffer = g_malloc0 (ora_value->defined_size+1);
-		memcpy (string_buffer, ora_value->value, ora_value->defined_size);
-		string_buffer[ora_value->defined_size] = '\0';
-		g_strchomp(string_buffer);
-		tmp = g_locale_to_utf8 (string_buffer, -1, NULL, NULL, NULL);
-		g_value_set_string (value, tmp);
-		g_free (tmp);
-		g_free (string_buffer);
-	}
-	else if (type == G_TYPE_INT64)
-		g_value_set_int64 (value, atoll (ora_value->value));
-	else if (type == G_TYPE_INT)
-		g_value_set_int (value, atol (ora_value->value));
-	else if (type == G_TYPE_UINT)
-		g_value_set_uint (value, atol (ora_value->value));
-	else if (type == GDA_TYPE_SHORT)
-		gda_value_set_short (value, atoi (ora_value->value));
-	else if (type == G_TYPE_FLOAT)
-		g_value_set_float (value, atof (ora_value->value));
-	else if (type == G_TYPE_DOUBLE)
-		g_value_set_double (value, atof (ora_value->value));
-	else if (type == GDA_TYPE_NUMERIC) {
-		string_buffer = g_malloc0 (ora_value->defined_size+1);
-		memcpy (string_buffer, ora_value->value, ora_value->defined_size);
-		string_buffer [ora_value->defined_size] = '\0';
+	gda_value_reset_with_type (value, ora_value->g_type);
+	switch (ora_value->s_type) {
+	case GDA_STYPE_INT:
+		g_value_set_int (value, *((gint *) ora_value->value));
+		break;
+	case GDA_STYPE_STRING: {
+		gchar *string_buffer, *tmp;
+		
+		string_buffer = (gchar *) ora_value->value;
+		string_buffer [ora_value->rlen] = '\0';
 		g_strchomp (string_buffer);
-		numeric.number = string_buffer;
-		numeric.precision = 0; /* FIXME */
-		numeric.width = 0; /* FIXME */
-		gda_value_set_numeric (value, &numeric);
-		g_free (string_buffer);
+		//tmp = g_locale_to_utf8 (string_buffer, -1, NULL, NULL, NULL);
+		//g_value_take_string (value, tmp);
+		g_value_set_string (value, string_buffer);
+		if (ora_value->use_callback) {
+			g_free (string_buffer);
+			ora_value->value = NULL;
+		}
+		break;
 	}
-	else if (type == G_TYPE_DATE) {
+	case GDA_STYPE_BOOLEAN:
+		g_value_set_boolean (value, (*((gint *) ora_value->value)) ? TRUE: FALSE);
+		break;
+	case GDA_STYPE_DATE: {
 		GDate *date;
 		OCIDateGetDate ((CONST OCIDate *) ora_value->value,
 				(sb2 *) &year,
@@ -481,11 +549,20 @@ _gda_oracle_set_value (GValue *value,
 				(ub1 *) &day);
 		date = g_date_new_dmy (day, month, year);
 		g_value_take_boxed (value, date);
+		break;
 	}
-	else if (type == GDA_TYPE_GEOMETRIC_POINT) {}
-	else if (type == GDA_TYPE_NULL)
-		gda_value_set_null (value);
-	else if (type == GDA_TYPE_TIMESTAMP) {
+	case GDA_STYPE_TIME: {
+		OCIDateGetTime ((CONST OCIDate *) ora_value->value,
+				(ub1 *) &hour,
+				(ub1 *) &min,
+				(ub1 *) &sec);
+		gtime.hour = hour;
+		gtime.minute = min;
+		gtime.second = sec;
+		gda_value_set_time (value, &gtime);
+		break;
+	}
+	case GDA_STYPE_TIMESTAMP: {
 		OCIDateGetDate ((CONST OCIDate *) ora_value->value,
 				(sb2 *) &year,
 				(ub1 *) &month,
@@ -503,21 +580,57 @@ _gda_oracle_set_value (GValue *value,
 		timestamp.fraction = 0;
 		timestamp.timezone = 0;
 		gda_value_set_timestamp(value, &timestamp);
+		break;
 	}
-	else if (type == GDA_TYPE_TIME) {
-		OCIDateGetTime ((CONST OCIDate *) ora_value->value,
-				(ub1 *) &hour,
-				(ub1 *) &min,
-				(ub1 *) &sec);
-		gtime.hour = hour;
-		gtime.minute = min;
-		gtime.second = sec;
-		gda_value_set_time (value, &gtime);
+	case GDA_STYPE_INT64:
+		g_value_set_int64 (value, atoll (ora_value->value));
+		break;
+	case GDA_STYPE_UINT:
+		g_value_set_uint (value, *((guint*) ora_value->value));
+		break;
+	case GDA_STYPE_FLOAT:
+		g_value_set_float (value, *((gfloat*) ora_value->value));
+		break;
+	case GDA_STYPE_DOUBLE:
+		g_value_set_double (value, *((gdouble*) ora_value->value));
+		break;
+	case GDA_STYPE_LONG:
+		TO_IMPLEMENT;
+		break;
+	case GDA_STYPE_ULONG:
+		TO_IMPLEMENT;
+		break;
+	case GDA_STYPE_NUMERIC: {
+		GdaNumeric *numeric;
+		g_assert (!ora_value->use_callback);
+		
+		numeric = g_new0 (GdaNumeric, 1);
+		numeric->number = g_malloc0 (ora_value->defined_size);
+		memcpy (numeric->number, ora_value->value, ora_value->defined_size);
+		numeric->number [ora_value->rlen] = '\0';
+		g_strchomp (numeric->number);
+		numeric->precision = ora_value->precision;
+		numeric->width = ora_value->scale;
+		g_value_take_boxed (value, numeric);
+		break;
 	}
-	else if (type == GDA_TYPE_BINARY) {
-		g_warning ("GdaBinary type is not supported by Oracle");
+	case GDA_STYPE_BINARY: {
+		GdaBinary *bin;
+
+		bin = g_new0 (GdaBinary, 1);
+		if (ora_value->use_callback) {		
+			bin->data = ora_value->value;
+			ora_value->value = NULL;
+		}
+		else {
+			bin->data = g_new (guchar, ora_value->rlen);
+			memcpy (bin->data, ora_value->value, ora_value->rlen);
+		}
+		bin->binary_length = ora_value->rlen;
+		gda_value_take_binary (value, bin);
+		break;
 	}
-	else if (type == GDA_TYPE_BLOB) {
+	case GDA_STYPE_BLOB: {
 		GdaBlob *blob;
 		GdaBlobOp *op;
 		OCILobLocator *lobloc;
@@ -553,9 +666,30 @@ _gda_oracle_set_value (GValue *value,
 		g_object_unref (op);
 
 		gda_value_take_blob (value, blob);
+		break;
+	}
+	case GDA_STYPE_CHAR: {
+		TO_IMPLEMENT; /* test that value fits in */
+		g_value_set_char (value, *((gchar*) ora_value->value));
+		break;
+	}
+	case GDA_STYPE_SHORT: {
+		TO_IMPLEMENT; /* test that value fits in */
+		gda_value_set_short (value, *((gint*) ora_value->value));
+		break;
+	}
+	case GDA_STYPE_GTYPE:
+		TO_IMPLEMENT;
+		break;
+	case GDA_STYPE_GEOMETRIC_POINT:
+		TO_IMPLEMENT;
+		break;
+	case GDA_STYPE_NULL:
+		gda_value_set_null (value);
+		break;
+	default:
+		g_assert_not_reached ();
 	}
-	else
-		g_value_set_string (value, ora_value->value);
 }
 
 void
@@ -568,3 +702,16 @@ _gda_oracle_value_free (GdaOracleValue *ora_value)
         OCIDescriptorFree ((dvoid *) ora_value->pard, OCI_DTYPE_PARAM);
         g_free (ora_value);
 }
+
+GType *static_types = NULL;
+GdaStaticType
+gda_g_type_to_static_type (GType type)
+{
+	GdaStaticType st;
+	for (st = 0; st < GDA_STYPE_NULL; st++) {
+		if (static_types [st] == type)
+			return st;
+	}
+	g_error ("Missing type '%s' in GDA static types", g_type_name (type));
+	return 0;
+}
diff --git a/providers/oracle/gda-oracle-util.h b/providers/oracle/gda-oracle-util.h
index 55c4892..e381553 100644
--- a/providers/oracle/gda-oracle-util.h
+++ b/providers/oracle/gda-oracle-util.h
@@ -36,15 +36,60 @@ G_BEGIN_DECLS
 #define gda_oracle_blob_type(sqltype) \
         ((((sqltype) == SQLT_BFILEE) || ((sqltype) == SQLT_CFILEE)) ? OCI_DTYPE_FILE : OCI_DTYPE_LOB)
 
+/*
+ * Static types
+ */
+typedef enum {
+	GDA_STYPE_INT,
+	GDA_STYPE_STRING,
+	GDA_STYPE_BOOLEAN,
+	GDA_STYPE_DATE,
+	GDA_STYPE_TIME,
+	GDA_STYPE_TIMESTAMP,
+	GDA_STYPE_INT64,
+	GDA_STYPE_UINT,
+	GDA_STYPE_FLOAT,
+	GDA_STYPE_DOUBLE,
+	GDA_STYPE_LONG,
+	GDA_STYPE_ULONG,
+	GDA_STYPE_NUMERIC,
+	GDA_STYPE_BINARY,
+	GDA_STYPE_BLOB,
+	GDA_STYPE_CHAR,
+	GDA_STYPE_SHORT,
+	GDA_STYPE_GTYPE,
+	GDA_STYPE_GEOMETRIC_POINT,
+
+	GDA_STYPE_NULL /* MUST be last */
+} GdaStaticType;
+extern GType *static_types;
+GdaStaticType gda_g_type_to_static_type (GType type);
 
+/* 
+   @indicator
+   -2  item length > variable size so data truncated
+   -1  value is NULL
+   0  value is in host variable
+   >0  item length > variable, indicator is length before truncation
+*/
 typedef struct {
 	OCIDefine *hdef;
         OCIParam *pard;
+	gboolean use_callback;
+
         sb2 indicator;
-        ub2 sql_type;
-        ub2 defined_size;
+	ub2 rlen; /* length of data returned after fetch */
+	ub2 rcode; /* column level return codes */
+	ub4 xlen;
+
+        ub2 sql_type; /* Oracle type */
+        ub4 defined_size;
+	sb2 precision;
+	sb1 scale;
+
         gpointer value;
         GType g_type;
+	GdaStaticType s_type;
 } GdaOracleValue;
 
 GdaConnectionEvent *_gda_oracle_make_error (dvoid *hndlp, ub4 type, const gchar *file, gint line);
@@ -52,7 +97,8 @@ GdaConnectionEvent *_gda_oracle_handle_error (gint result, GdaConnection *cnc,
 					      OracleConnectionData *cdata,
 					      ub4 type, const gchar *msg,
 					      const gchar *file, gint line);
-GType               _oracle_sqltype_to_g_type (const ub2 sqltype);
+GType               _oracle_sqltype_to_g_type (const ub2 sqltype, sb2 precision, sb1 scale);
+ub2                 _g_type_to_oracle_sqltype (GType type);
 gchar *             _oracle_sqltype_to_string (const ub2 sqltype);
 gchar *             _gda_oracle_value_to_sql_string (GValue *value);
 GdaOracleValue     *_gda_value_to_oracle_value (const GValue *value);
diff --git a/providers/oracle/gda-oracle.h b/providers/oracle/gda-oracle.h
index 1afd601..f5e485c 100644
--- a/providers/oracle/gda-oracle.h
+++ b/providers/oracle/gda-oracle.h
@@ -42,6 +42,10 @@ typedef struct {
         OCISvcCtx *hservice;
         OCISession *hsession;
         gchar *schema; /* the same as the username which opened the connection */
+
+	gchar *version;
+	guint8 major_version;
+	guint8 minor_version;
 } OracleConnectionData;
 
 #endif
diff --git a/providers/postgres/gda-postgres-meta.c b/providers/postgres/gda-postgres-meta.c
index 299b323..0a971e6 100644
--- a/providers/postgres/gda-postgres-meta.c
+++ b/providers/postgres/gda-postgres-meta.c
@@ -314,7 +314,7 @@ _gda_postgres_meta__btypes (GdaServerProvider *prov, GdaConnection *cnc,
 
 	/* use a proxy to customize @model */
 	proxy = (GdaDataModel*) gda_data_proxy_new (model);
-	gda_data_proxy_set_sample_size ((GdaDataProxy*) proxy, 0);
+	g_object_set (G_OBJECT (proxy), "defer-sync", FALSE, "sample-size", 0, NULL);
 	nrows = gda_data_model_get_n_rows (model);
 	for (i = 0; i < nrows; i++) {
 		const GValue *value;
@@ -809,7 +809,7 @@ gboolean _gda_postgres_meta__columns (GdaServerProvider *prov, GdaConnection *cn
 
 	/* use a proxy to customize @model */
 	proxy = (GdaDataModel*) gda_data_proxy_new (model);
-	gda_data_proxy_set_sample_size ((GdaDataProxy*) proxy, 0);
+	g_object_set (G_OBJECT (proxy), "defer-sync", FALSE, "sample-size", 0, NULL);
 	nrows = gda_data_model_get_n_rows (model);
 	for (i = 0; i < nrows; i++) {
 		const GValue *value;
@@ -913,7 +913,7 @@ _gda_postgres_meta_columns (GdaServerProvider *prov, GdaConnection *cnc,
 
 	/* use a proxy to customize @model */
 	proxy = (GdaDataModel*) gda_data_proxy_new (model);
-	gda_data_proxy_set_sample_size ((GdaDataProxy*) proxy, 0);
+	g_object_set (G_OBJECT (proxy), "defer-sync", FALSE, "sample-size", 0, NULL);
 	nrows = gda_data_model_get_n_rows (model);
 	for (i = 0; i < nrows; i++) {
 		const GValue *value;
@@ -1410,7 +1410,7 @@ _gda_postgres_meta__routine_col (GdaServerProvider *prov, GdaConnection *cnc,
 
 	/* use a proxy to customize @model */
 	proxy = (GdaDataModel*) gda_data_proxy_new (model);
-	gda_data_proxy_set_sample_size ((GdaDataProxy*) proxy, 0);
+	g_object_set (G_OBJECT (proxy), "defer-sync", FALSE, "sample-size", 0, NULL);
 	nrows = gda_data_model_get_n_rows (model);
 	for (i = 0; i < nrows; i++) {
 		const GValue *cvalue;
@@ -1477,7 +1477,7 @@ GdaDataModel *model, *proxy;
 
 	/* use a proxy to customize @model */
 	proxy = (GdaDataModel*) gda_data_proxy_new (model);
-	gda_data_proxy_set_sample_size ((GdaDataProxy*) proxy, 0);
+	g_object_set (G_OBJECT (proxy), "defer-sync", FALSE, "sample-size", 0, NULL);
 	nrows = gda_data_model_get_n_rows (model);
 	for (i = 0; i < nrows; i++) {
 		const GValue *cvalue;



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