[libgda] Improved Oracle provider



commit 29ee39d5a8301593b40c5db493e31de7c74791db
Author: Vivien Malerba <malerba gnome-db org>
Date:   Thu Apr 23 20:51:11 2009 +0200

    Improved Oracle provider
    
    	* configure.in:
    	* providers/oracle: improved Oracle provider
---
 ChangeLog                               |    5 +
 configure.in                            |    2 +-
 providers/oracle/Makefile.am            |    2 +
 providers/oracle/gda-oracle-blob-op.c   |    6 +-
 providers/oracle/gda-oracle-blob-op.h   |    8 +-
 providers/oracle/gda-oracle-ddl.c       |    2 +-
 providers/oracle/gda-oracle-ddl.h       |    2 +-
 providers/oracle/gda-oracle-meta.c      |   69 +++-
 providers/oracle/gda-oracle-meta.h      |    2 +-
 providers/oracle/gda-oracle-parser.c    |    2 +-
 providers/oracle/gda-oracle-parser.h    |    2 +-
 providers/oracle/gda-oracle-provider.c  |  651 +++++++++++++++++++++++++++----
 providers/oracle/gda-oracle-provider.h  |    4 +-
 providers/oracle/gda-oracle-pstmt.c     |   26 +-
 providers/oracle/gda-oracle-pstmt.h     |   14 +-
 providers/oracle/gda-oracle-recordset.c |  430 ++++++++++++++++++---
 providers/oracle/gda-oracle-recordset.h |    6 +-
 providers/oracle/gda-oracle-util.c      |  570 +++++++++++++++++++++++++++
 providers/oracle/gda-oracle-util.h      |   69 ++++
 providers/oracle/gda-oracle.h           |   18 +-
 providers/oracle/libmain.c              |    6 +-
 21 files changed, 1730 insertions(+), 166 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 9e77d11..1fda8b4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2009-04-23  Vivien Malerba <malerba gnome-db org>
+
+	* configure.in:
+	* providers/oracle: improved Oracle provider
+
 2009-04-22  Vivien Malerba <malerba gnome-db org>
 
 	* libgda/gda-statement.h: added the GDA_STATEMENT_SQL_PARAMS_AS_VALUES constant
diff --git a/configure.in b/configure.in
index 8e38710..fb46e5a 100644
--- a/configure.in
+++ b/configure.in
@@ -895,7 +895,7 @@ then
 		AC_MSG_WARN(ORACLE backend not used)
 	else
 		AC_DEFINE(HAVE_ORACLE, 1, [Have ORACLE])
-		ORACLE_CFLAGS=" -I$oracledir/include/oracle/client -I$oracledir/rdbms/demo -I${ORACLE_HOME}/rdbms/public -I${ORACLE_HOME}/plsql/public -I$oracledir/network/public"
+		ORACLE_CFLAGS=" -I$oracledir/include -I$oracledir/include/oracle/client -I$oracledir/rdbms/demo -I${ORACLE_HOME}/rdbms/public -I${ORACLE_HOME}/plsql/public -I$oracledir/network/public"
 		ORACLE_LIBS="-L$oracledir/$oraclelibdir -lm -ldl -lclntsh"
 	fi
 fi
diff --git a/providers/oracle/Makefile.am b/providers/oracle/Makefile.am
index f419a9e..d73a8ac 100644
--- a/providers/oracle/Makefile.am
+++ b/providers/oracle/Makefile.am
@@ -38,6 +38,8 @@ libgda_oracle_la_SOURCES = \
 	gda-oracle-meta.h \
 	gda-oracle-recordset.c \
 	gda-oracle-recordset.h \
+	gda-oracle-util.c \
+	gda-oracle-util.h \
 	gda-oracle.h \
 	libmain.c \
 	parser.h \
diff --git a/providers/oracle/gda-oracle-blob-op.c b/providers/oracle/gda-oracle-blob-op.c
index 04dc562..d7b02b6 100644
--- a/providers/oracle/gda-oracle-blob-op.c
+++ b/providers/oracle/gda-oracle-blob-op.c
@@ -1,8 +1,8 @@
 /* GDA Oracle provider
- * Copyright (C) 2008 The GNOME Foundation
+ * Copyright (C) 2009 The GNOME Foundation
  *
  * AUTHORS:
- *      TO_ADD: your name and email
+ *      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
@@ -114,7 +114,7 @@ gda_oracle_blob_op_finalize (GObject * object)
 }
 
 GdaBlobOp *
-gda_oracle_blob_op_new (GdaConnection *cnc)
+gda_oracle_blob_op_new (GdaConnection *cnc, OCILobLocator *lobloc)
 {
 	GdaOracleBlobOp *bop;
 
diff --git a/providers/oracle/gda-oracle-blob-op.h b/providers/oracle/gda-oracle-blob-op.h
index a118316..5a7cbf7 100644
--- a/providers/oracle/gda-oracle-blob-op.h
+++ b/providers/oracle/gda-oracle-blob-op.h
@@ -1,8 +1,8 @@
 /* GDA Oracle provider
- * Copyright (C) 2008 The GNOME Foundation
+ * Copyright (C) 2009 The GNOME Foundation
  *
  * AUTHORS:
- *      TO_ADD: your name and email
+ *      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
@@ -47,9 +47,7 @@ struct _GdaOracleBlobOpClass {
 };
 
 GType         gda_oracle_blob_op_get_type     (void) G_GNUC_CONST;
-GdaBlobOp    *gda_oracle_blob_op_new          (GdaConnection *cnc);
-
-/* TO_ADD: more convenient API to create a GdaBlobOp with some specific information as argument */
+GdaBlobOp    *gda_oracle_blob_op_new          (GdaConnection *cnc, OCILobLocator *lobloc);
 
 G_END_DECLS
 
diff --git a/providers/oracle/gda-oracle-ddl.c b/providers/oracle/gda-oracle-ddl.c
index 28d559f..0149e4f 100644
--- a/providers/oracle/gda-oracle-ddl.c
+++ b/providers/oracle/gda-oracle-ddl.c
@@ -2,7 +2,7 @@
  * Copyright (C) 2008 The GNOME Foundation
  *
  * AUTHORS:
- *      TO_ADD: your name and email
+ *      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
diff --git a/providers/oracle/gda-oracle-ddl.h b/providers/oracle/gda-oracle-ddl.h
index 0f14318..c1576e9 100644
--- a/providers/oracle/gda-oracle-ddl.h
+++ b/providers/oracle/gda-oracle-ddl.h
@@ -2,7 +2,7 @@
  * Copyright (C) 2008 The GNOME Foundation
  *
  * AUTHORS:
- *      TO_ADD: your name and email
+ *      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
diff --git a/providers/oracle/gda-oracle-meta.c b/providers/oracle/gda-oracle-meta.c
index 128cca6..3791e70 100644
--- a/providers/oracle/gda-oracle-meta.c
+++ b/providers/oracle/gda-oracle-meta.c
@@ -1,8 +1,8 @@
 /* GDA oracle provider
- * Copyright (C) 2008 The GNOME Foundation.
+ * Copyright (C) 2009 The GNOME Foundation.
  *
  * AUTHORS:
- *      TO_ADD: your name and email
+ *      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
@@ -37,7 +37,9 @@
  * predefined statements' IDs
  */
 typedef enum {
-        I_STMT_1,
+        I_STMT_CATALOG,
+        I_STMT_SCHEMAS_ALL,
+	I_STMT_SCHEMA_NAMED
 } InternalStatementItem;
 
 
@@ -45,7 +47,14 @@ typedef enum {
  * predefined statements' SQL
  */
 static gchar *internal_sql[] = {
-	"SQL for I_STMT_1"
+	/* I_STMT_CATALOG */
+	"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",
+
+	/* 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",
 };
 
 /*
@@ -71,7 +80,7 @@ _gda_oracle_provider_meta_init (GdaServerProvider *provider)
 
         internal_parser = gda_server_provider_internal_get_parser (provider);
         internal_stmt = g_new0 (GdaStatement *, sizeof (internal_sql) / sizeof (gchar*));
-        for (i = I_STMT_1; i < sizeof (internal_sql) / sizeof (gchar*); i++) {
+        for (i = I_STMT_CATALOG; i < sizeof (internal_sql) / sizeof (gchar*); i++) {
                 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]);
@@ -93,11 +102,8 @@ _gda_oracle_meta__info (GdaServerProvider *prov, GdaConnection *cnc,
 	GdaDataModel *model;
 	gboolean retval;
 
-	TO_IMPLEMENT;
-	/* fill in @model, with something like:
-	 * model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_1], NULL, 
-	 *                                                  error);
-	 */
+	model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_CATALOG], NULL, 
+							 error);
 	if (!model)
 		return FALSE;
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
@@ -276,8 +282,18 @@ gboolean
 _gda_oracle_meta__schemata (GdaServerProvider *prov, GdaConnection *cnc, 
 			  GdaMetaStore *store, GdaMetaContext *context, GError **error)
 {
-	TO_IMPLEMENT;
-	return TRUE;
+	GdaDataModel *model;
+	gboolean retval;
+	GType col_types[] = {G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_NONE};
+
+	model = gda_connection_statement_execute_select_full (cnc, internal_stmt[I_STMT_SCHEMAS_ALL], NULL, 
+                                                              GDA_STATEMENT_MODEL_RANDOM_ACCESS, col_types, error);
+	if (!model)
+		return FALSE;
+	retval = gda_meta_store_modify_with_context (store, context, model, error);
+	g_object_unref (model);
+		
+	return retval;
 }
 
 gboolean
@@ -285,8 +301,33 @@ _gda_oracle_meta_schemata (GdaServerProvider *prov, GdaConnection *cnc,
 			 GdaMetaStore *store, GdaMetaContext *context, GError **error, 
 			 const GValue *catalog_name, const GValue *schema_name_n)
 {
-	TO_IMPLEMENT;
-	return TRUE;
+	GdaDataModel *model;
+        gboolean retval;
+	GType col_types[] = {G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_NONE};
+
+        if (! gda_holder_set_value (gda_set_get_holder (i_set, "cat"), catalog_name, error))
+                return FALSE;
+        if (!schema_name_n) {
+		model = gda_connection_statement_execute_select_full (cnc, internal_stmt[I_STMT_SCHEMAS_ALL], NULL, 
+								      GDA_STATEMENT_MODEL_RANDOM_ACCESS, col_types, error);
+                if (!model)
+                        return FALSE;
+                retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
+        }
+        else {
+                if (! gda_holder_set_value (gda_set_get_holder (i_set, "name"), schema_name_n, error))
+                        return FALSE;
+		model = gda_connection_statement_execute_select_full (cnc, internal_stmt[I_STMT_SCHEMA_NAMED], i_set, 
+								      GDA_STATEMENT_MODEL_RANDOM_ACCESS, col_types, error);
+                if (!model)
+                        return FALSE;
+
+                retval = gda_meta_store_modify (store, context->table_name, model, "schema_name = ##name::string", error,
+                                                "name", schema_name_n, NULL);
+        }
+        g_object_unref (model);
+
+        return retval;
 }
 
 gboolean
diff --git a/providers/oracle/gda-oracle-meta.h b/providers/oracle/gda-oracle-meta.h
index 0850505..5e03cb2 100644
--- a/providers/oracle/gda-oracle-meta.h
+++ b/providers/oracle/gda-oracle-meta.h
@@ -2,7 +2,7 @@
  * Copyright (C) 2008 The GNOME Foundation.
  *
  * AUTHORS:
- *      TO_ADD: your name and email
+ *      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
diff --git a/providers/oracle/gda-oracle-parser.c b/providers/oracle/gda-oracle-parser.c
index 0568732..812e308 100644
--- a/providers/oracle/gda-oracle-parser.c
+++ b/providers/oracle/gda-oracle-parser.c
@@ -3,7 +3,7 @@
  * Copyright (C) 2008 The GNOME Foundation
  *
  * AUTHORS:
- *      TO_ADD: your name and email
+ *      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
diff --git a/providers/oracle/gda-oracle-parser.h b/providers/oracle/gda-oracle-parser.h
index 088bc49..337527c 100644
--- a/providers/oracle/gda-oracle-parser.h
+++ b/providers/oracle/gda-oracle-parser.h
@@ -3,7 +3,7 @@
  * Copyright (C) 2008 The GNOME Foundation
  *
  * AUTHORS:
- *      TO_ADD: your name and email
+ *      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
diff --git a/providers/oracle/gda-oracle-provider.c b/providers/oracle/gda-oracle-provider.c
index 296dc1a..42253f8 100644
--- a/providers/oracle/gda-oracle-provider.c
+++ b/providers/oracle/gda-oracle-provider.c
@@ -1,8 +1,11 @@
 /* GDA Oracle provider
- * Copyright (C) 2008 The GNOME Foundation.
+ * Copyright (C) 2009 The GNOME Foundation.
  *
  * AUTHORS:
- *      TO_ADD: your name and email
+ *      Rodrigo Moya <rodrigo gnome-db org>
+ *      Tim Coleman <tim timcoleman com>
+ *      Vivien Malerba <malerba 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
@@ -37,6 +40,7 @@
 #include "gda-oracle-recordset.h"
 #include "gda-oracle-ddl.h"
 #include "gda-oracle-meta.h"
+#include "gda-oracle-util.h"
 #define _GDA_PSTMT(x) ((GdaPStmt*)(x))
 
 /*
@@ -245,6 +249,9 @@ gda_oracle_provider_class_init (GdaOracleProviderClass *klass)
 	provider_class->xa_funcs->xa_commit = gda_oracle_provider_xa_commit;
 	provider_class->xa_funcs->xa_rollback = gda_oracle_provider_xa_rollback;
 	provider_class->xa_funcs->xa_recover = gda_oracle_provider_xa_recover;
+
+	/* thread safe */
+	provider_class->limiting_thread = NULL;
 }
 
 static void
@@ -263,8 +270,6 @@ gda_oracle_provider_init (GdaOracleProvider *oracle_prv, GdaOracleProviderClass
 
 	/* meta data init */
 	_gda_oracle_provider_meta_init ((GdaServerProvider*) oracle_prv);
-
-	/* TO_ADD: any other provider's init should be added here */
 }
 
 GType
@@ -312,6 +317,76 @@ gda_oracle_provider_get_version (GdaServerProvider *provider)
 	return PACKAGE_VERSION;
 }
 
+/*
+ * NOT FOR SELECT statements!
+ */
+static gboolean
+execute_raw_command (GdaConnection *cnc, const gchar *sql)
+{
+	OracleConnectionData *cdata;
+	OCIStmt *hstmt = NULL;
+	int result;
+
+	cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
+	
+	result = OCIHandleAlloc ((dvoid *) cdata->henv,
+                                 (dvoid **) &hstmt,
+                                 (ub4) OCI_HTYPE_STMT,
+                                 (size_t) 0,
+                                 (dvoid **) 0);
+        if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ENV,
+                                     _("Could not allocate the Oracle statement handle")))
+		return FALSE;
+
+	result = OCIStmtPrepare ((dvoid *) hstmt,
+                                 (dvoid *) cdata->herr,
+                                 (text *) sql,
+                                 (ub4) strlen(sql),
+                                 (ub4) OCI_NTV_SYNTAX,
+                                 (ub4) OCI_DEFAULT);
+        if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+                                     _("Could not prepare the Oracle statement"))) {
+                OCIHandleFree ((dvoid *) hstmt, OCI_HTYPE_STMT);
+                return FALSE;
+        }
+	
+#ifdef GDA_DEBUG
+	ub2 stmt_type;
+	result = OCIAttrGet (hstmt, OCI_HTYPE_STMT,
+                             (dvoid *) &stmt_type, NULL,
+                             OCI_ATTR_STMT_TYPE, cdata->herr);
+	if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+                                     _("Could not get the Oracle statement type"))) {
+                OCIHandleFree ((dvoid *) hstmt, OCI_HTYPE_STMT);
+                return FALSE;
+        }
+	if (stmt_type == OCI_STMT_SELECT) {
+		g_warning ("Internal implementation error: the %s() function can't be used to execute SELECT commands\n",
+			   __FUNCTION__);
+		OCIHandleFree ((dvoid *) hstmt, OCI_HTYPE_STMT);
+                return FALSE;
+	}
+#endif
+	result = OCIStmtExecute (cdata->hservice,
+				 hstmt,
+				 cdata->herr,
+				 (ub4) 1,
+				 (ub4) 0,
+				 (CONST OCISnapshot *) NULL,
+				 (OCISnapshot *) NULL,
+				 OCI_DEFAULT);
+	if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+				     _("Could not execute the Oracle statement"))) {
+                OCIHandleFree ((dvoid *) hstmt, OCI_HTYPE_STMT);
+                return FALSE;
+        }
+
+	OCIHandleFree ((dvoid *) hstmt, OCI_HTYPE_STMT);
+	return TRUE;
+}
+
 /* 
  * Open connection request
  *
@@ -325,9 +400,10 @@ gda_oracle_provider_get_version (GdaServerProvider *provider)
  */
 static gboolean
 gda_oracle_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
-				   GdaQuarkList *params, GdaQuarkList *auth,
-				   guint *task_id, GdaServerProviderAsyncCallback async_cb, gpointer cb_data)
+				     GdaQuarkList *params, GdaQuarkList *auth,
+				     guint *task_id, GdaServerProviderAsyncCallback async_cb, gpointer cb_data)
 {
+	OracleConnectionData *cdata;
 	g_return_val_if_fail (GDA_IS_ORACLE_PROVIDER (provider), FALSE);
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
 
@@ -338,33 +414,217 @@ gda_oracle_provider_open_connection (GdaServerProvider *provider, GdaConnection
 	}
 
 	/* Check for connection parameters */
-	/* TO_ADD: your own connection parameters */
-	const gchar *db_name;
-	db_name = gda_quark_list_find (params, "DB_NAME");
-	if (!db_name) {
+	const gchar *tnsname, *username, *password;
+ 	tnsname = gda_quark_list_find (params, "TNSNAME");
+	if (!tnsname) {
 		gda_connection_add_event_string (cnc,
-						 _("The connection string must contain the DB_NAME values"));
+						 _("The connection string must contain the TNSNAME value"));
 		return FALSE;
 	}
+	username = gda_quark_list_find (auth, "USERNAME");
+	password = gda_quark_list_find (auth, "PASSWORD");
 	
 	/* open the real connection to the database */
-	/* TO_ADD: C API specific function calls;
-	 * if it fails, add a connection event and return FALSE */
-	TO_IMPLEMENT;
+	gint result;
+	result = OCIInitialize ((ub4) OCI_THREADED,
+                                (dvoid *) 0,
+                                (dvoid * (*)(dvoid *, size_t)) 0,
+                                (dvoid * (*)(dvoid *, dvoid *, size_t)) 0,
+                                (void (*)(dvoid *, dvoid *)) 0);
+
+        if (result != OCI_SUCCESS) {
+                gda_connection_add_event_string (cnc,
+                                                 _("Could not initialize Oracle"));
+                return FALSE;
+        }
+
+        /* initialize the Oracle environment */
+	cdata = g_new0 (OracleConnectionData, 1);
+        result = OCIEnvInit ((OCIEnv **) & cdata->henv,
+                             (ub4) OCI_DEFAULT,
+                             (size_t) 0,
+                             (dvoid **) 0);
+        if (result != OCI_SUCCESS) {
+                gda_connection_add_event_string (cnc,
+                                                 _("Could not initialize the Oracle environment"));
+		gda_oracle_free_cnc_data (cdata);
+                return FALSE;
+        }
+
+        /* create the service context */
+        result = OCIHandleAlloc ((dvoid *) cdata->henv,
+                                 (dvoid **) &cdata->hservice,
+                                 (ub4) OCI_HTYPE_SVCCTX,
+                                 (size_t) 0,
+                                 (dvoid **) 0);
+	if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ENV,
+                                     _("Could not allocate the Oracle service handle"))) {
+		gda_oracle_free_cnc_data (cdata);
+                return FALSE;
+	}
+
+	/* create the error handle */
+        result = OCIHandleAlloc ((dvoid *) cdata->henv,
+                                 (dvoid **) &(cdata->herr),
+                                 (ub4) OCI_HTYPE_ERROR,
+                                 (size_t) 0,
+                                 (dvoid **) 0);
+        if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ENV,
+                                     _("Could not allocate the Oracle error handle"))) {
+                OCIHandleFree ((dvoid *) cdata->hservice, OCI_HTYPE_SVCCTX);
+		gda_oracle_free_cnc_data (cdata);
+                return FALSE;
+        }
+
+        /* we use the Multiple Sessions/Connections OCI paradigm for this server */
+        result = OCIHandleAlloc ((dvoid *) cdata->henv,
+                                 (dvoid **) & cdata->hserver,
+                                 (ub4) OCI_HTYPE_SERVER,
+                                 (size_t) 0,
+                                 (dvoid **) 0);
+        if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ENV,
+                                     _("Could not allocate the Oracle server handle"))) {
+                OCIHandleFree ((dvoid *) cdata->herr, OCI_HTYPE_ERROR);
+                OCIHandleFree ((dvoid *) cdata->hservice, OCI_HTYPE_SVCCTX);
+		gda_oracle_free_cnc_data (cdata);
+                return FALSE;
+        }
+
+        /* create the session handle */
+        result = OCIHandleAlloc ((dvoid *) cdata->henv,
+                                 (dvoid **) &cdata->hsession,
+                                 (ub4) OCI_HTYPE_SESSION,
+                                 (size_t) 0,
+                                 (dvoid **) 0);
+        if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ENV,
+                                     _("Could not allocate the Oracle session handle"))) {
+                OCIHandleFree ((dvoid *) cdata->hserver, OCI_HTYPE_SERVER);
+                OCIHandleFree ((dvoid *) cdata->herr, OCI_HTYPE_ERROR);
+                OCIHandleFree ((dvoid *) cdata->hservice, OCI_HTYPE_SVCCTX);
+		gda_oracle_free_cnc_data (cdata);
+                return FALSE;
+        }
+
+	/* attach to Oracle server */
+        result = OCIServerAttach (cdata->hserver,
+                                  cdata->herr,
+                                  (text *) tnsname,
+                                  (ub4) strlen (tnsname),
+                                  OCI_DEFAULT);
+        if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+                                     _("Could not attach to the Oracle server"))) {
+                OCIHandleFree ((dvoid *) cdata->hsession, OCI_HTYPE_SESSION);
+                OCIHandleFree ((dvoid *) cdata->hserver, OCI_HTYPE_SERVER);
+                OCIHandleFree ((dvoid *) cdata->herr, OCI_HTYPE_ERROR);
+                OCIHandleFree ((dvoid *) cdata->hservice, OCI_HTYPE_SVCCTX);
+		gda_oracle_free_cnc_data (cdata);
+                return FALSE;
+        }
+
+        /* set the server attribute in the service context */
+        result = OCIAttrSet ((dvoid *) cdata->hservice,
+                             (ub4) OCI_HTYPE_SVCCTX,
+                             (dvoid *) cdata->hserver,
+                             (ub4) 0,
+                             (ub4) OCI_ATTR_SERVER,
+                             cdata->herr);
+        if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+                                     _("Could not set the Oracle server attribute in the service context"))) {
+                OCIHandleFree ((dvoid *) cdata->hsession, OCI_HTYPE_SESSION);
+                OCIHandleFree ((dvoid *) cdata->hserver, OCI_HTYPE_SERVER);
+                OCIHandleFree ((dvoid *) cdata->herr, OCI_HTYPE_ERROR);
+                OCIHandleFree ((dvoid *) cdata->hservice, OCI_HTYPE_SVCCTX);
+		gda_oracle_free_cnc_data (cdata);
+                return FALSE;
+        }
+
+	/* set the username attribute */
+        result = OCIAttrSet ((dvoid *) cdata->hsession,
+                             (ub4) OCI_HTYPE_SESSION,
+                             (dvoid *) username,
+                             (ub4) strlen (username),
+                             (ub4) OCI_ATTR_USERNAME,
+                             cdata->herr);
+        if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+                                     _("Could not set the Oracle username attribute"))) {
+                OCIHandleFree ((dvoid *) cdata->hsession, OCI_HTYPE_SESSION);
+                OCIHandleFree ((dvoid *) cdata->hserver, OCI_HTYPE_SERVER);
+                OCIHandleFree ((dvoid *) cdata->herr, OCI_HTYPE_ERROR);
+                OCIHandleFree ((dvoid *) cdata->hservice, OCI_HTYPE_SVCCTX);
+		gda_oracle_free_cnc_data (cdata);
+                return FALSE;
+        }
+
+        /* set the password attribute */
+        result = OCIAttrSet ((dvoid *) cdata->hsession,
+                             (ub4) OCI_HTYPE_SESSION,
+                             (dvoid *) password,
+                             (ub4) strlen (password),
+                             (ub4) OCI_ATTR_PASSWORD,
+                             cdata->herr);
+        if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+                                     _("Could not set the Oracle password attribute"))) {
+                OCIHandleFree ((dvoid *) cdata->hsession, OCI_HTYPE_SESSION);
+                OCIHandleFree ((dvoid *) cdata->hserver, OCI_HTYPE_SERVER);
+                OCIHandleFree ((dvoid *) cdata->herr, OCI_HTYPE_ERROR);
+                OCIHandleFree ((dvoid *) cdata->hservice, OCI_HTYPE_SVCCTX);
+		gda_oracle_free_cnc_data (cdata);
+                return FALSE;
+        }
+
+	/* begin the session */
+        result = OCISessionBegin (cdata->hservice,
+                                  cdata->herr,
+                                  cdata->hsession,
+                                  (ub4) OCI_CRED_RDBMS,
+                                  (ub4) OCI_STMT_CACHE);
+        if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+                                     _("Could not begin the Oracle session"))) {
+                OCIServerDetach (cdata->hserver, cdata->herr, OCI_DEFAULT);
+                OCIHandleFree ((dvoid *) cdata->hsession, OCI_HTYPE_SESSION);
+                OCIHandleFree ((dvoid *) cdata->hserver, OCI_HTYPE_SERVER);
+                OCIHandleFree ((dvoid *) cdata->herr, OCI_HTYPE_ERROR);
+                OCIHandleFree ((dvoid *) cdata->hservice, OCI_HTYPE_SVCCTX);
+		gda_oracle_free_cnc_data (cdata);
+                cdata->hsession = NULL;
+                return FALSE;
+        }
+
+        /* set the session attribute in the service context */
+        result = OCIAttrSet ((dvoid *) cdata->hservice,
+                             (ub4) OCI_HTYPE_SVCCTX,
+                             (dvoid *) cdata->hsession,
+                             (ub4) 0,
+                             (ub4) OCI_ATTR_SESSION,
+                             cdata->herr);
+        if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+                                     _("Could not set the Oracle session attribute in the service context"))) {
+                OCIServerDetach (cdata->hserver, cdata->herr, OCI_DEFAULT);
+                OCIHandleFree ((dvoid *) cdata->hsession, OCI_HTYPE_SESSION);
+                OCIHandleFree ((dvoid *) cdata->hserver, OCI_HTYPE_SERVER);
+                OCIHandleFree ((dvoid *) cdata->herr, OCI_HTYPE_ERROR);
+                OCIHandleFree ((dvoid *) cdata->hservice, OCI_HTYPE_SVCCTX);
+		gda_oracle_free_cnc_data (cdata);
+                return FALSE;
+        }
 
 	/* Create a new instance of the provider specific data associated to a connection (OracleConnectionData),
 	 * and set its contents */
-	OracleConnectionData *cdata;
-	cdata = g_new0 (OracleConnectionData, 1);
+	cdata->schema = g_ascii_strup (username, -1);
 	gda_connection_internal_set_provider_data (cnc, cdata, (GDestroyNotify) gda_oracle_free_cnc_data);
-	TO_IMPLEMENT; /* cdata->... = ... */
 
 	/* Optionnally set some attributes for the newly opened connection (encoding to UTF-8 for example )*/
-	TO_IMPLEMENT;
+	if (! execute_raw_command (cnc, "ALTER SESSION SET NLS_DATE_FORMAT = 'MM/DD/YYYY'") ||
+	    ! execute_raw_command (cnc, "ALTER SESSION SET NLS_NUMERIC_CHARACTERS = \". \"")) {
+		gda_connection_internal_set_provider_data (cnc, NULL, NULL);
+		gda_oracle_free_cnc_data (cdata);
+		return FALSE;
+	}
 
 	return TRUE;
 }
 
+
 /* 
  * Close connection request
  *
@@ -372,7 +632,7 @@ gda_oracle_provider_open_connection (GdaServerProvider *provider, GdaConnection
  *   - Actually close the connection to the database using @cnc's associated OracleConnectionData structure
  *   - Free the OracleConnectionData structure and its contents
  *
- * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR gonnection event must be added to @cnc)
+ * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR connection event must be added to @cnc)
  */
 static gboolean
 gda_oracle_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc)
@@ -386,7 +646,17 @@ gda_oracle_provider_close_connection (GdaServerProvider *provider, GdaConnection
 	cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data (cnc);
 	if (!cdata) 
 		return FALSE;
-	TO_IMPLEMENT;
+
+	/* end the session */
+	int result;
+        if ((result = OCISessionEnd (cdata->hservice,
+				     cdata->herr,
+				     cdata->hsession,
+				     OCI_DEFAULT))) {
+                gda_connection_add_event (cnc,
+                                          _gda_oracle_make_error (cdata->herr, OCI_HTYPE_ERROR, __FILE__, __LINE__));
+                return FALSE;
+        }
 
 	/* Free the OracleConnectionData structure and its contents*/
 	gda_oracle_free_cnc_data (cdata);
@@ -485,7 +755,7 @@ gda_oracle_provider_supports_operation (GdaServerProvider *provider, GdaConnecti
  */
 static GdaServerOperation *
 gda_oracle_provider_create_operation (GdaServerProvider *provider, GdaConnection *cnc,
-				    GdaServerOperationType type, GdaSet *options, GError **error)
+				      GdaServerOperationType type, GdaSet *options, GError **error)
 {
         gchar *file;
         GdaServerOperation *op;
@@ -523,7 +793,7 @@ gda_oracle_provider_create_operation (GdaServerProvider *provider, GdaConnection
  */
 static gchar *
 gda_oracle_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc,
-				    GdaServerOperation *op, GError **error)
+				      GdaServerOperation *op, GError **error)
 {
         gchar *sql = NULL;
         gchar *file;
@@ -585,8 +855,8 @@ gda_oracle_provider_render_operation (GdaServerProvider *provider, GdaConnection
  */
 static gboolean
 gda_oracle_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
-				     GdaServerOperation *op, guint *task_id, 
-				     GdaServerProviderAsyncCallback async_cb, gpointer cb_data, GError **error)
+				       GdaServerOperation *op, guint *task_id, 
+				       GdaServerProviderAsyncCallback async_cb, gpointer cb_data, GError **error)
 {
         GdaServerOperationType optype;
 
@@ -827,14 +1097,14 @@ gda_oracle_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConne
 	    (type == G_TYPE_ULONG) ||
 	    (type == G_TYPE_UINT) ||
 	    (type == G_TYPE_UINT64))
-		return "integer";
+		return "NUMBER";
 
 	if ((type == GDA_TYPE_BINARY) ||
 	    (type == GDA_TYPE_BLOB))
-		return "blob";
+		return "BLOB";
 
 	if (type == G_TYPE_BOOLEAN)
-		return "boolean";
+		return "BOOLEAN";
 	
 	if ((type == G_TYPE_DATE) || 
 	    (type == GDA_TYPE_GEOMETRIC_POINT) ||
@@ -845,21 +1115,21 @@ gda_oracle_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConne
 	    (type == GDA_TYPE_TIMESTAMP) ||
 	    (type == G_TYPE_INVALID) ||
 	    (type == G_TYPE_GTYPE))
-		return "string";
+		return "VARCHAR2";
 
 	if ((type == G_TYPE_DOUBLE) ||
 	    (type == GDA_TYPE_NUMERIC) ||
 	    (type == G_TYPE_FLOAT))
-		return "real";
+		return "FLOAT";
 	
 	if (type == GDA_TYPE_TIME)
-		return "time";
+		return "TIME";
 	if (type == GDA_TYPE_TIMESTAMP)
-		return "timestamp";
+		return "TIMESTAMP";
 	if (type == G_TYPE_DATE)
-		return "date";
+		return "DATE";
 
-	return "text";
+	return "VARCHAR2";
 }
 
 /*
@@ -884,18 +1154,74 @@ 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_target (GdaSqlSelectTarget *target, GdaSqlRenderingContext *context, GError **error);
+
 static gchar *
 gda_oracle_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection *cnc,
-				    GdaStatement *stmt, GdaSet *params, GdaStatementSqlFlag flags,
-				    GSList **params_used, GError **error)
+				      GdaStatement *stmt, GdaSet *params, GdaStatementSqlFlag flags,
+				      GSList **params_used, GError **error)
 {
+	gchar *str;
+	GdaSqlRenderingContext context;
+
 	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 (cnc) == provider, NULL);
 	}
 
-	return gda_statement_to_sql_extended (stmt, cnc, params, flags, params_used, error);
+	memset (&context, 0, sizeof (context));
+	context.params = params;
+	context.flags = flags;
+	context.render_select_target = (GdaSqlRenderingFunc) oracle_render_select_target;
+
+	str = gda_statement_to_sql_real (stmt, &context, error);
+
+	if (str) {
+		if (params_used)
+			*params_used = context.params_used;
+		else
+			g_slist_free (context.params_used);
+	}
+	else {
+		if (params_used)
+			*params_used = NULL;
+		g_slist_free (context.params_used);
+	}
+	return str;
+}
+
+/* the difference from the common implementation is to avoid rendering the "AS" in target alias */
+static gchar *
+oracle_render_select_target (GdaSqlSelectTarget *target, GdaSqlRenderingContext *context, GError **error)
+{
+        GString *string;
+        gchar *str;
+
+        g_return_val_if_fail (target, NULL);
+        g_return_val_if_fail (GDA_SQL_ANY_PART (target)->type == GDA_SQL_ANY_SQL_SELECT_TARGET, NULL);
+
+        /* can't have: target->expr == NULL */
+        if (!gda_sql_any_part_check_structure (GDA_SQL_ANY_PART (target), error)) return NULL;
+
+        string = g_string_new ("");
+        str = context->render_expr (target->expr, context, NULL, NULL, error);
+        if (!str) goto err;
+        g_string_append (string, str);
+        g_free (str);
+
+        if (target->as) {
+		g_string_append_c (string, ' ');
+                g_string_append (string, target->as);
+	}
+
+        str = string->str;
+        g_string_free (string, FALSE);
+        return str;
+
+ err:
+        g_string_free (string, TRUE);
+        return NULL;
 }
 
 /*
@@ -907,10 +1233,12 @@ gda_oracle_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection
  */
 static gboolean
 gda_oracle_provider_statement_prepare (GdaServerProvider *provider, GdaConnection *cnc,
-				     GdaStatement *stmt, GError **error)
+				       GdaStatement *stmt, GError **error)
 {
 	GdaOraclePStmt *ps;
 	gboolean retval = FALSE;
+	OracleConnectionData *cdata;
+	GdaConnectionEvent *event;
 
 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
@@ -927,13 +1255,50 @@ gda_oracle_provider_statement_prepare (GdaServerProvider *provider, GdaConnectio
 	GSList *used_params = NULL;
 	if (! gda_statement_get_parameters (stmt, &params, error))
                 return FALSE;
-        sql = gda_oracle_provider_statement_to_sql (provider, cnc, stmt, params, GDA_STATEMENT_SQL_PARAMS_AS_UQMARK,
-						  &used_params, error);
+        sql = gda_oracle_provider_statement_to_sql (provider, cnc, stmt, params, GDA_STATEMENT_SQL_PARAMS_AS_COLON,
+						    &used_params, error);
         if (!sql) 
 		goto out;
 
 	/* prepare @stmt using the C API, creates @ps */
-	TO_IMPLEMENT;
+	OCIStmt *hstmt;
+	int result;
+
+	cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
+
+	result = OCIHandleAlloc ((dvoid *) cdata->henv,
+                                 (dvoid **) &hstmt,
+                                 (ub4) OCI_HTYPE_STMT,
+                                 (size_t) 0,
+                                 (dvoid **) NULL);
+        if ((event = gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ENV,
+					      _("Could not allocate the Oracle statement handle")))) {
+		g_free (sql);
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_PREPARE_STMT_ERROR,
+			     "%s", gda_connection_event_get_description (event));
+                return FALSE;
+	}
+	
+	/*g_print ("Really PREPARED: %s\n", sql);*/
+	result = OCIStmtPrepare2 (cdata->hservice,
+				  &hstmt,
+				  (dvoid *) cdata->herr,
+				  (text *) sql,
+				  (ub4) strlen (sql),
+				  (text *) sql,
+				  (ub4) strlen (sql),
+				  (ub4) OCI_NTV_SYNTAX,
+				  (ub4) OCI_DEFAULT);
+        if ((event = gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+					      _("Could not prepare the Oracle statement")))) {
+		OCIStmtRelease ((dvoid *) hstmt, cdata->herr, NULL, 0, result ? OCI_STRLS_CACHE_DELETE : OCI_DEFAULT);
+		g_free (sql);
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_PREPARE_STMT_ERROR,
+			     "%s", gda_connection_event_get_description (event));
+                return FALSE;
+        }
 
 	/* make a list of the parameter names used in the statement */
 	GSList *param_ids = NULL;
@@ -957,7 +1322,7 @@ gda_oracle_provider_statement_prepare (GdaServerProvider *provider, GdaConnectio
         }
 	
 	/* create a prepared statement object */
-	/*ps = gda_oracle_pstmt_new (...);*/
+	ps = gda_oracle_pstmt_new (hstmt);
 	gda_pstmt_set_gda_statement (_GDA_PSTMT (ps), stmt);
         _GDA_PSTMT (ps)->param_ids = param_ids;
         _GDA_PSTMT (ps)->sql = sql;
@@ -990,11 +1355,11 @@ gda_oracle_provider_statement_prepare (GdaServerProvider *provider, GdaConnectio
  */
 static GObject *
 gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
-				     GdaStatement *stmt, GdaSet *params,
-				     GdaStatementModelUsage model_usage, 
-				     GType *col_types, GdaSet **last_inserted_row, 
-				     guint *task_id, 
-				     GdaServerProviderExecCallback async_cb, gpointer cb_data, GError **error)
+				       GdaStatement *stmt, GdaSet *params,
+				       GdaStatementModelUsage model_usage, 
+				       GType *col_types, GdaSet **last_inserted_row, 
+				       guint *task_id, 
+				       GdaServerProviderExecCallback async_cb, gpointer cb_data, GError **error)
 {
 	GdaOraclePStmt *ps;
 	OracleConnectionData *cdata;
@@ -1024,7 +1389,6 @@ gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 	if (!cdata) 
 		return FALSE;
 
-
 	/* get/create new prepared statement */
 	ps = (GdaOraclePStmt *) gda_connection_get_prepared_statement (cnc, stmt);
 	if (!ps) {
@@ -1049,15 +1413,13 @@ gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 		g_object_ref (ps);
 	g_assert (ps);
 
-	/* optionnally reset the prepared statement if required by the API */
-	TO_IMPLEMENT;
-	
 	/* bind statement's parameters */
 	GSList *list;
 	GdaConnectionEvent *event = NULL;
 	int i;
 	for (i = 1, list = _GDA_PSTMT (ps)->param_ids; list; list = list->next, i++) {
 		const gchar *pname = (gchar *) list->data;
+		gchar *real_pname = NULL;
 		GdaHolder *h;
 		
 		/* find requested parameter */
@@ -1075,7 +1437,10 @@ gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 			gchar *tmp = gda_alphanum_to_text (g_strdup (pname + 1));
 			if (tmp) {
 				h = gda_set_get_holder (params, tmp);
-				g_free (tmp);
+				if (h)
+					real_pname = tmp;
+				else
+					g_free (tmp);
 			}
 		}
 		if (!h) {
@@ -1091,6 +1456,7 @@ gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 			}
 			else {
                                 /* bind param to NULL */
+				/* Hint: Indicator Variables, see p. 118 */
                                 TO_IMPLEMENT;
                                 empty_rs = TRUE;
                                 continue;
@@ -1118,7 +1484,26 @@ gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 
 		/* actual binding using the C API, for parameter at position @i */
 		const GValue *value = gda_holder_get_value (h);
-		TO_IMPLEMENT;
+		GdaOracleValue *ora_value = _gda_value_to_oracle_value (value);
+		OCIBind *bindpp = (OCIBind *) 0;
+		int result;
+		result = OCIBindByName ((dvoid *) ps->hstmt,
+					(OCIBind **) &bindpp,
+					(OCIError *) cdata->herr,
+					(text *) real_pname ? real_pname : pname,
+					(sb4) strlen (real_pname ? real_pname : pname),
+					(dvoid *) ora_value->value,
+					(sb4) ora_value->defined_size,
+					(ub2) ora_value->sql_type,
+					(dvoid *) &ora_value->indicator,
+					(ub2 *) 0,
+					(ub2) 0,
+					(ub4) 0,
+					(ub4 *) 0,
+					(ub4) OCI_DEFAULT);
+		if ((event = gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+						      _("Could not bind the Oracle statement parameter"))))
+			break;
 	}
 		
 	if (event) {
@@ -1131,6 +1516,18 @@ gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 	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);
+	event = NULL;
+
+	/* get statement type */
+	ub2 stmt_type = 0;
+	int result;
+	result = OCIAttrGet (ps->hstmt, OCI_HTYPE_STMT,
+			     (dvoid *) &stmt_type, NULL,
+			     OCI_ATTR_STMT_TYPE, cdata->herr);
+	event = gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+					 _("Could not get the Oracle statement type"));
+	if (event)
+		return NULL;
 
 	if (empty_rs) {
 		/* There are some missing parameters, so the SQL can't be executed but we still want
@@ -1138,6 +1535,9 @@ gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 		 * execute another SQL which is the code shown here.
 		 *
 		 * To adapt depending on the C API and its features */
+
+		/* HINT: use the OCIStmtExecute()' OCI_DESCRIBE_ONLY flag */
+
 		GdaStatement *estmt;
                 gchar *esql;
                 estmt = gda_select_alter_select_for_empty (stmt, error);
@@ -1158,34 +1558,141 @@ gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
 		TO_IMPLEMENT;
 	}
 	else {
-		/* Execute the _GDA_PSTMT (ps)->sql SQL code */
-		TO_IMPLEMENT;
+		/* Execute the @ps prepared statement */
+		result = OCIStmtExecute (cdata->hservice,
+					 ps->hstmt,
+					 cdata->herr,
+					 (ub4) ((stmt_type == OCI_STMT_SELECT) ? 0 : 1),
+					 (ub4) 0,
+					 (CONST OCISnapshot *) NULL,
+					 (OCISnapshot *) NULL,
+					 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"));
+	}
+
+	if (event) {
+		g_object_unref (ps);
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+			     GDA_SERVER_PROVIDER_STATEMENT_EXEC_ERROR, "%s",
+			     gda_connection_event_get_description (event));
+		return NULL;
 	}
 	
 	/* execute prepared statement using C API depending on its kind */
-	if (! g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "SELECT", 6) ||
-            ! g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "EXPLAIN", 7)) {
-		GObject *data_model;
+	if (stmt_type == OCI_STMT_SELECT) {
+		GdaDataModel *data_model;
 		GdaDataModelAccessFlags flags;
-
+		GList *columns = NULL;
+                ub4 ncolumns;
+                ub4 i;
+		
 		if (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS)
 			flags = GDA_DATA_MODEL_ACCESS_RANDOM;
 		else
 			flags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD;
 
-                data_model = (GObject *) gda_oracle_recordset_new (cnc, ps, params, flags, col_types);
+                /* get the number of columns in the result set */
+                result = OCIAttrGet ((dvoid *) ps->hstmt,
+                                     (ub4) OCI_HTYPE_STMT,
+                                     (dvoid *) &ncolumns,
+                                     (ub4 *) 0,
+                                     (ub4) OCI_ATTR_PARAM_COUNT,
+                                     cdata->herr);
+                if ((event = gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+						      _("Could not get the number of columns in the result set")))) {
+			g_object_unref (ps);
+			g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+				     GDA_SERVER_PROVIDER_STATEMENT_EXEC_ERROR, "%s",
+				     gda_connection_event_get_description (event));
+                        return NULL;
+                }
+
+                for (i = 0; i < ncolumns; i += 1) {
+                        text *dummy = (text *) 0;
+                        ub4 col_name_len;
+                        OCIParam *pard = (OCIParam *) 0;
+                        gchar *name_buffer;
+
+                        result = OCIParamGet ((dvoid *) ps->hstmt,
+                                              OCI_HTYPE_STMT,
+                                              cdata->herr,
+                                              (dvoid **) &pard,
+                                              (ub4) i + 1);
+                        if ((event = gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+							      _("Could not get the parameter descripter in the result set")))) {
+				g_object_unref (ps);
+				g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+					     GDA_SERVER_PROVIDER_STATEMENT_EXEC_ERROR, "%s",
+					     gda_connection_event_get_description (event));
+                                return NULL;
+                        }
+
+                        result = OCIAttrGet ((dvoid *) pard,
+                                             (ub4) OCI_DTYPE_PARAM,
+                                             (dvoid **) &dummy,
+                                             (ub4 *) &col_name_len,
+                                             (ub4) OCI_ATTR_NAME,
+                                             (OCIError *) cdata->herr);
+                        if ((event = gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+							      _("Could not get the column name in the result set")))) {
+				g_object_unref (ps);
+				g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+					     GDA_SERVER_PROVIDER_STATEMENT_EXEC_ERROR, "%s",
+					     gda_connection_event_get_description (event));
+                                return NULL;
+                        }
+
+                        name_buffer = g_malloc0 (col_name_len + 1);
+			memcpy (name_buffer, dummy, col_name_len);
+                        name_buffer[col_name_len] = '\0';
+                        columns = g_list_append (columns, name_buffer);
+                }
+
+                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 */
 		g_object_unref (ps);
-		return data_model;
+		return (GObject*) data_model;
         }
 	else {
 		GdaSet *set = NULL;
+		int nrows = -2; /* number of rows non reported */
+
+		result = OCIAttrGet (ps->hstmt, OCI_HTYPE_STMT,
+				     (dvoid *) &nrows, NULL,
+				     OCI_ATTR_ROW_COUNT, cdata->herr);
+		if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+					     _("Could not get the number of affected rows")))
+			nrows = -2;
+
+		set = gda_set_new_inline (1, "IMPACTED_ROWS", G_TYPE_INT, nrows);
+
+		if (nrows >= 0) {
+			gchar *str = NULL;
+			switch (stmt_type) {
+			case OCI_STMT_UPDATE:
+				str = g_strdup_printf ("UPDATE %d", nrows);
+				break;
+			case OCI_STMT_DELETE:
+				str = g_strdup_printf ("DELETE %d", nrows);
+				break;
+			case OCI_STMT_INSERT:
+				str = g_strdup_printf ("INSERT %d", nrows);
+				break;
+			default:
+				break;
+			}
+			if (str) {
+				event = gda_connection_event_new (GDA_CONNECTION_EVENT_NOTICE);
+				gda_connection_event_set_description (event, str);
+				g_free (str);
+				gda_connection_add_event (cnc, event);
+			}
+		}
 
-		TO_IMPLEMENT;
-                /* Create a #GdaSet containing "IMPACTED_ROWS" */
-		/* Create GdaConnectionEvent notice with the type of command and impacted rows */
-
-		gda_connection_internal_statement_executed (cnc, stmt, params, event); /* required: help @cnc keep some stats */
+		gda_connection_internal_statement_executed (cnc, stmt, params, NULL); /* required: help @cnc keep some stats */
 		g_object_unref (ps);
 		return (GObject*) set;
 	}
@@ -1329,6 +1836,18 @@ gda_oracle_free_cnc_data (OracleConnectionData *cdata)
 	if (!cdata)
 		return;
 
-	TO_IMPLEMENT;
+	if (cdata->hsession)
+                OCIHandleFree ((dvoid *) cdata->hsession, OCI_HTYPE_SESSION);
+        if (cdata->hservice)
+                OCIHandleFree ((dvoid *) cdata->hservice, OCI_HTYPE_SVCCTX);
+        if (cdata->hserver)
+                OCIHandleFree ((dvoid *) cdata->hserver, OCI_HTYPE_SERVER);
+        if (cdata->herr)
+                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);
 }
diff --git a/providers/oracle/gda-oracle-provider.h b/providers/oracle/gda-oracle-provider.h
index 5e0338c..c09cf8c 100644
--- a/providers/oracle/gda-oracle-provider.h
+++ b/providers/oracle/gda-oracle-provider.h
@@ -1,8 +1,8 @@
 /* GDA oracle provider
- * Copyright (C) 2008 The GNOME Foundation.
+ * Copyright (C) 2009 The GNOME Foundation.
  *
  * AUTHORS:
- *      TO_ADD: your name and email
+ *      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
diff --git a/providers/oracle/gda-oracle-pstmt.c b/providers/oracle/gda-oracle-pstmt.c
index 6056e43..75dc654 100644
--- a/providers/oracle/gda-oracle-pstmt.c
+++ b/providers/oracle/gda-oracle-pstmt.c
@@ -1,8 +1,8 @@
 /* GDA Oracle provider
- * Copyright (C) 2008 The GNOME Foundation.
+ * Copyright (C) 2009 The GNOME Foundation.
  *
  * AUTHORS:
- *      TO_ADD: your name and email
+ *      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
@@ -23,6 +23,7 @@
 #include <string.h>
 #include <glib/gi18n-lib.h>
 #include "gda-oracle-pstmt.h"
+#include "gda-oracle-util.h"
 
 static void gda_oracle_pstmt_class_init (GdaOraclePStmtClass *klass);
 static void gda_oracle_pstmt_init       (GdaOraclePStmt *pstmt, GdaOraclePStmtClass *klass);
@@ -78,7 +79,8 @@ gda_oracle_pstmt_init (GdaOraclePStmt *pstmt, GdaOraclePStmtClass *klass)
 	g_return_if_fail (GDA_IS_PSTMT (pstmt));
 	
 	/* initialize specific parts of @pstmt */
-	TO_IMPLEMENT;
+	pstmt->hstmt = NULL;
+	pstmt->ora_values = NULL;
 }
 
 static void
@@ -89,8 +91,24 @@ gda_oracle_pstmt_finalize (GObject *object)
 	g_return_if_fail (GDA_IS_PSTMT (pstmt));
 
 	/* free memory */
-	TO_IMPLEMENT; /* free some specific parts of @pstmt */
+	OCIStmtRelease ((dvoid *) pstmt->hstmt, NULL, NULL, 0, OCI_STRLS_CACHE_DELETE);
+	if (pstmt->ora_values) {
+		g_list_foreach (pstmt->ora_values, (GFunc) _gda_oracle_value_free, NULL);
+		g_list_free (pstmt->ora_values);
+	}
 
 	/* chain to parent class */
 	parent_class->finalize (object);
 }
+
+GdaOraclePStmt *
+gda_oracle_pstmt_new (OCIStmt *hstmt)
+{
+	GdaOraclePStmt *pstmt;
+
+        pstmt = (GdaOraclePStmt *) g_object_new (GDA_TYPE_ORACLE_PSTMT, NULL);
+        pstmt->hstmt = hstmt;
+
+        return pstmt;
+
+}
diff --git a/providers/oracle/gda-oracle-pstmt.h b/providers/oracle/gda-oracle-pstmt.h
index cef1c3b..d49b827 100644
--- a/providers/oracle/gda-oracle-pstmt.h
+++ b/providers/oracle/gda-oracle-pstmt.h
@@ -1,8 +1,8 @@
 /* GDA Oracle library
- * Copyright (C) 2008 The GNOME Foundation.
+ * Copyright (C) 2009 The GNOME Foundation.
  *
  * AUTHORS:
- *      TO_ADD: your name and email
+ *      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
@@ -39,18 +39,16 @@ typedef struct _GdaOraclePStmtClass   GdaOraclePStmtClass;
 
 struct _GdaOraclePStmt {
 	GdaPStmt        object;
-
-	/* TO_ADD: this structure holds any information necessary to reference a prepared statement, usually a connection
-         * handle from the C or C++ API
-         */
+	OCIStmt        *hstmt;
+	GList          *ora_values; /* list of GdaOracleValue pointers, owned here */
 };
 
 struct _GdaOraclePStmtClass {
 	GdaPStmtClass  parent_class;
 };
 
-GType         gda_oracle_pstmt_get_type  (void) G_GNUC_CONST;
-/* TO_ADD: helper function to create a GdaOraclePStmt such as gda_oracle_pstmt_new() with some specific arguments */
+GType           gda_oracle_pstmt_get_type  (void) G_GNUC_CONST;
+GdaOraclePStmt *gda_oracle_pstmt_new (OCIStmt *hstmt);
 
 G_END_DECLS
 
diff --git a/providers/oracle/gda-oracle-recordset.c b/providers/oracle/gda-oracle-recordset.c
index 450b0ad..fe978cc 100644
--- a/providers/oracle/gda-oracle-recordset.c
+++ b/providers/oracle/gda-oracle-recordset.c
@@ -1,8 +1,8 @@
 /* GDA Oracle provider
- * Copyright (C) 2008 The GNOME Foundation.
+ * Copyright (C) 2009 The GNOME Foundation.
  *
  * AUTHORS:
- *      TO_ADD: your name and email
+ *      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
@@ -28,6 +28,7 @@
 #include "gda-oracle.h"
 #include "gda-oracle-recordset.h"
 #include "gda-oracle-provider.h"
+#include "gda-oracle-util.h"
 
 #define _GDA_PSTMT(x) ((GdaPStmt*)(x))
 
@@ -43,10 +44,11 @@ static gboolean gda_oracle_recordset_fetch_next (GdaDataSelect *model, GdaRow **
 static gboolean gda_oracle_recordset_fetch_prev (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error);
 static gboolean gda_oracle_recordset_fetch_at (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error);
 
+static GdaRow  *new_row (GdaDataSelect *imodel, GdaConnection *cnc, GdaOraclePStmt *ps);
 
 struct _GdaOracleRecordsetPrivate {
-	GdaConnection *cnc;
-	/* TO_ADD: specific information */
+	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;
 
@@ -59,10 +61,8 @@ gda_oracle_recordset_init (GdaOracleRecordset *recset,
 {
 	g_return_if_fail (GDA_IS_ORACLE_RECORDSET (recset));
 	recset->priv = g_new0 (GdaOracleRecordsetPrivate, 1);
-	recset->priv->cnc = NULL;
-
-	/* initialize specific information */
-	TO_IMPLEMENT;
+	recset->priv->is_scrollable = FALSE;
+	recset->priv->next_row_num = 0;
 }
 
 static void
@@ -90,11 +90,7 @@ gda_oracle_recordset_dispose (GObject *object)
 	g_return_if_fail (GDA_IS_ORACLE_RECORDSET (recset));
 
 	if (recset->priv) {
-		if (recset->priv->cnc) 
-			g_object_unref (recset->priv->cnc);
-
 		/* free specific information */
-		TO_IMPLEMENT;
 		g_free (recset->priv);
 		recset->priv = NULL;
 	}
@@ -139,12 +135,16 @@ gda_oracle_recordset_get_type (void)
  */
 GdaDataModel *
 gda_oracle_recordset_new (GdaConnection *cnc, GdaOraclePStmt *ps, GdaSet *exec_params,
-			GdaDataModelAccessFlags flags, GType *col_types)
+			  GdaDataModelAccessFlags flags, GType *col_types)
 {
 	GdaOracleRecordset *model;
         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);
@@ -153,15 +153,31 @@ gda_oracle_recordset_new (GdaConnection *cnc, GdaOraclePStmt *ps, GdaSet *exec_p
 	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;
+	/* make sure @ps reports the correct number of columns using the API */
+        if (_GDA_PSTMT (ps)->ncols < 0) {
+		ub4 ncolumns;
+		int result;
+		
+                /* get the number of columns in the result set */
+                result = OCIAttrGet ((dvoid *) ps->hstmt,
+                                     (ub4) OCI_HTYPE_STMT,
+                                     (dvoid *) &ncolumns,
+                                     (ub4 *) 0,
+                                     (ub4) OCI_ATTR_PARAM_COUNT,
+                                     cdata->herr);
+                if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+                                             _("Could not get the number of columns in the result set")))
+                        return NULL;
+		
+                _GDA_PSTMT (ps)->ncols = ncolumns;
+	}
 
         /* completing @ps if not yet done */
         if (!_GDA_PSTMT (ps)->types && (_GDA_PSTMT (ps)->ncols > 0)) {
 		/* create prepared statement's columns */
 		GSList *list;
+		GList *ora_values = NULL;
+
 		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 ());
@@ -183,19 +199,195 @@ gda_oracle_recordset_new (GdaConnection *cnc, GdaOraclePStmt *ps, GdaSet *exec_p
 			}
 		}
 		
-		/* fill GdaColumn's data */
+		/* fill GdaColumn's data and define the GdaOracleValue structures */
 		for (i=0, list = _GDA_PSTMT (ps)->tmpl_columns; 
 		     i < GDA_PSTMT (ps)->ncols; 
 		     i++, list = list->next) {
 			GdaColumn *column;
+			int result;
+			GdaOracleValue *ora_value;
+
+			ora_value = g_new0 (GdaOracleValue, 1);
+			ora_values = g_list_prepend (ora_values, ora_value);
+
+			/* parameter to get attributes */
+			result = OCIParamGet (ps->hstmt,
+					      OCI_HTYPE_STMT,
+					      cdata->herr,
+					      (dvoid **) &(ora_value->pard),
+					      (ub4) i+1);
+			if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+						     _("Could not get the Oracle parameter descripter in the result set"))) {
+				g_list_foreach (ora_values, (GFunc) _gda_oracle_value_free, NULL);
+				return NULL;
+			}
+			
+			/* data size */
+			result = OCIAttrGet ((dvoid *) (ora_value->pard),
+					     OCI_DTYPE_PARAM,
+					     &(ora_value->defined_size),
+					     0,
+					     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;
+			}
+			
+			/* data type */
+			result = OCIAttrGet ((dvoid *) (ora_value->pard),
+					     OCI_DTYPE_PARAM,
+					     &(ora_value->sql_type),
+					     0,
+					     OCI_ATTR_DATA_TYPE,
+					     cdata->herr);
+			if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+						     _("Could not get the parameter data type"))) {
+				g_list_foreach (ora_values, (GFunc) _gda_oracle_value_free, NULL);
+				return NULL;
+			}
+
+			/* column's name */
+			text *name;
+			ub4 name_len;
 			
 			column = GDA_COLUMN (list->data);
+			result = OCIAttrGet ((dvoid *) (ora_value->pard),
+                                             (ub4) OCI_DTYPE_PARAM,
+                                             (dvoid **) &name,
+                                             (ub4 *) &name_len,
+                                             (ub4) OCI_ATTR_NAME,
+                                             (OCIError *) cdata->herr);
+			if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+                                                     _("Could not get column name in the result set"))) {
+				g_list_foreach (ora_values, (GFunc) _gda_oracle_value_free, NULL);
+                                return NULL;
+			}
 
-			/* use C API to set columns' information using gda_column_set_*() */
-			TO_IMPLEMENT;
+			gchar *name_buffer;
+			name_buffer = g_new (gchar, name_len + 1);
+			memcpy (name_buffer, name, name_len);
+                        name_buffer [name_len] = '\0';
+			gda_column_set_name (column, name_buffer);
+			gda_column_set_description (column, name_buffer);
+			g_free (name_buffer);
+
+			/* for data fetching  */
+			ub2 fake_type;
+			fake_type = ora_value->sql_type;
+			switch (ora_value->sql_type) {
+			case SQLT_NUM: /* Numerics are coerced to string */
+				fake_type = SQLT_CHR;
+				break;
+			case SQLT_DAT: /* Convert SQLT_DAT to OCIDate */
+				fake_type = SQLT_ODT;
+				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;
+			}
+			*/
+			if (ora_value->g_type == GDA_TYPE_BLOB) {
+				/* allocate a Lob locator */
+				OCILobLocator *lob;
+				
+				result = OCIDescriptorAlloc ((dvoid *) cdata->henv, (dvoid **) &lob,
+							     (ub4) gda_oracle_blob_type (ora_value->sql_type), 
+							     (size_t) 0, (dvoid **) 0);
+				if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+							     _("Could not allocate Lob locator"))) {
+					g_list_foreach (ora_values, (GFunc) _gda_oracle_value_free, NULL);
+					return NULL;
+				}
+				ora_value->value = lob;
+				ora_value->defined_size = 0;
+			}
+			else if (ora_value->defined_size == 0)
+				ora_value->value = NULL;
+			else {
+				ora_value->defined_size++;
+				ora_value->value = g_malloc0 (ora_value->defined_size);
+			}
+			
+			ora_value->hdef = (OCIDefine *) 0;
+			ora_value->indicator = 0;
+			result = OCIDefineByPos ((OCIStmt *) ps->hstmt,
+						 (OCIDefine **) &(ora_value->hdef),
+						 (OCIError *) cdata->herr,
+						 (ub4) i + 1,
+						 ora_value->value,
+						 ora_value->defined_size,
+						 (ub2) fake_type,
+						 (dvoid *) &(ora_value->indicator),
+						 (ub2 *) 0,
+						 (ub2 *) 0,
+						 (ub4) 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;
+			}
 		}
+
+		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;
@@ -204,18 +396,58 @@ gda_oracle_recordset_new (GdaConnection *cnc, GdaOraclePStmt *ps, GdaSet *exec_p
 
 	/* create data model */
         model = g_object_new (GDA_TYPE_ORACLE_RECORDSET, 
+			      "connection", cnc,
 			      "prepared-stmt", ps, 
 			      "model-usage", rflags, 
 			      "exec-params", exec_params, NULL);
-        model->priv->cnc = cnc;
-	g_object_ref (cnc);
-
-	/* post init specific code */
-	TO_IMPLEMENT;
+	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);
 }
 
+static GdaRow *
+fetch_next_oracle_row (GdaOracleRecordset *model, gboolean do_store, GError **error)
+{
+	int result;
+	GdaRow *prow = NULL;
+	GdaOraclePStmt *ps = GDA_ORACLE_PSTMT (((GdaDataSelect*)model)->prep_stmt);
+	OracleConnectionData *cdata;
+	GdaConnection *cnc;
+
+	cnc = gda_data_select_get_connection ((GdaDataSelect*) 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) {
+		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;
+	}
+	
+	prow = new_row ((GdaDataSelect*) model, cnc, ps);
+	gda_data_select_take_row (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;
+}
+
 
 /*
  * Get the number of rows in @model, if possible
@@ -224,15 +456,16 @@ static gint
 gda_oracle_recordset_fetch_nb_rows (GdaDataSelect *model)
 {
 	GdaOracleRecordset *imodel;
+        GdaRow *prow = NULL;
 
-	imodel = GDA_ORACLE_RECORDSET (model);
-	if (model->advertized_nrows >= 0)
-		return model->advertized_nrows;
-
-	/* use C API to determine number of rows,if possible */
-	TO_IMPLEMENT;
+        imodel = GDA_ORACLE_RECORDSET (model);
+        if (model->advertized_nrows >= 0)
+                return model->advertized_nrows;
 
-	return model->advertized_nrows;
+        for (prow = fetch_next_oracle_row (imodel, TRUE, NULL);
+             prow;
+             prow = fetch_next_oracle_row (imodel, TRUE, NULL));
+        return model->advertized_nrows;
 }
 
 /*
@@ -253,12 +486,43 @@ gda_oracle_recordset_fetch_nb_rows (GdaDataSelect *model)
 static gboolean 
 gda_oracle_recordset_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
 {
-	GdaOracleRecordset *imodel;
-
-	imodel = GDA_ORACLE_RECORDSET (model);
+	int result;
+	GdaOraclePStmt *ps = GDA_ORACLE_PSTMT (model->prep_stmt);
+	OracleConnectionData *cdata;
+	GdaConnection *cnc;
 
-	TO_IMPLEMENT;
+	if (*prow)
+                return TRUE;
 
+	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;
+			return FALSE;
+		}
+		
+		*prow = new_row (model, cnc, ps);
+		gda_data_select_take_row (model, *prow, rownum);
+	}
+	else {
+		TO_IMPLEMENT;
+	}
 	return TRUE;
 }
 
@@ -297,10 +561,38 @@ gda_oracle_recordset_store_all (GdaDataSelect *model, GError **error)
 static gboolean 
 gda_oracle_recordset_fetch_next (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
 {
-	GdaOracleRecordset *imodel = (GdaOracleRecordset*) model;
+	int result;
+	GdaOraclePStmt *ps = GDA_ORACLE_PSTMT (model->prep_stmt);
+	OracleConnectionData *cdata;
+	GdaConnection *cnc;
 
-	TO_IMPLEMENT;
+	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;
 }
 
@@ -319,10 +611,43 @@ 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)
 {
-	GdaOracleRecordset *imodel = (GdaOracleRecordset*) model;
+	int result;
+	GdaOraclePStmt *ps = GDA_ORACLE_PSTMT (model->prep_stmt);
+	OracleConnectionData *cdata;
+	GdaConnection *cnc;
 
-	TO_IMPLEMENT;
+	if (*prow)
+                return TRUE;
 
+	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_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;
 }
 
@@ -341,10 +666,25 @@ gda_oracle_recordset_fetch_prev (GdaDataSelect *model, GdaRow **prow, gint rownu
 static gboolean 
 gda_oracle_recordset_fetch_at (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
 {
-	GdaOracleRecordset *imodel = (GdaOracleRecordset*) model;
-	
-	TO_IMPLEMENT;
-
-	return TRUE;
+	return gda_oracle_recordset_fetch_random (model, prow, rownum, error);
 }
 
+/* create a new GdaRow from the last read row */
+static GdaRow *
+new_row (GdaDataSelect *imodel, GdaConnection *cnc, GdaOraclePStmt *ps)
+{
+	GdaRow *prow;
+	GList *nodes;
+	gint i;
+
+	prow = gda_row_new (((GdaDataSelect*) imodel)->prep_stmt->ncols);
+	for (i = 0, nodes = ps->ora_values;
+	     nodes; 
+	     i++, nodes = nodes->next) {
+		GdaOracleValue *ora_value = (GdaOracleValue *) nodes->data;
+                GValue *value = gda_row_get_value (prow, i); 
+                _gda_oracle_set_value (value, ora_value, cnc);
+	}
+
+	return prow;
+}
diff --git a/providers/oracle/gda-oracle-recordset.h b/providers/oracle/gda-oracle-recordset.h
index 7db421b..c034819 100644
--- a/providers/oracle/gda-oracle-recordset.h
+++ b/providers/oracle/gda-oracle-recordset.h
@@ -1,8 +1,8 @@
 /* GDA Oracle provider
- * Copyright (C) 2008 The GNOME Foundation.
+ * Copyright (C) 2009 The GNOME Foundation.
  *
  * AUTHORS:
- *      TO_ADD: your name and email
+ *      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
@@ -50,7 +50,7 @@ struct _GdaOracleRecordsetClass {
 
 GType         gda_oracle_recordset_get_type  (void) G_GNUC_CONST;
 GdaDataModel *gda_oracle_recordset_new       (GdaConnection *cnc, GdaOraclePStmt *ps, GdaSet *exec_params,
-					    GdaDataModelAccessFlags flags, GType *col_types);
+					      GdaDataModelAccessFlags flags, GType *col_types);
 
 G_END_DECLS
 
diff --git a/providers/oracle/gda-oracle-util.c b/providers/oracle/gda-oracle-util.c
new file mode 100644
index 0000000..caed135
--- /dev/null
+++ b/providers/oracle/gda-oracle-util.c
@@ -0,0 +1,570 @@
+/* GDA Oracle provider
+ * Copyright (C) 2002 - 2009 The GNOME Foundation.
+ *
+ * AUTHORS:
+ * 	Tim Coleman <tim timcoleman com>
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * Borrowed from Mysql utils.c, written by:
+ *      Michael Lausch <michael lausch at>
+ *	Rodrigo Moya <rodrigo 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
+ * 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 <stdlib.h>
+#include <string.h>
+#include "gda-oracle.h"
+#include "gda-oracle-util.h"
+#include "gda-oracle-blob-op.h"
+
+/* 
+ * _gda_oracle_make_error
+ * This function uses OCIErrorGet to get a description of the error to
+ * display.  The parameters are one of an OCIError or a OCIEnv handle
+ * depending on the type, which is either OCI_HTYPE_ERROR or OCI_HTYPE_ENV.
+ * Read the documentation on OCIErrorGet to understand why this is
+ *
+ * If the handle is NULL, which is an unhappy situation, it will set the
+ * error description to "NO DESCRIPTION".
+ *
+ * The error number is set to the Oracle error code.
+ */
+GdaConnectionEvent *
+_gda_oracle_make_error (dvoid *hndlp, ub4 type, const gchar *file, gint line)
+{
+	GdaConnectionEvent *error;
+	gchar errbuf[512];
+	ub4 errcode;
+	gchar *source;
+
+	error = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+
+	if (hndlp != NULL) {
+		OCIErrorGet ((dvoid *) hndlp,
+			     (ub4) 1, 
+			     (text *) NULL, 
+			     &errcode, 
+			     errbuf, 
+			     (ub4) sizeof (errbuf), 
+			     (ub4) type);
+	
+		gda_connection_event_set_description (error, errbuf);
+		/*g_warning ("Oracle error:%s", errbuf);*/
+	} 
+	else 
+		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);
+	
+	return error;
+}
+
+/* 
+ * _gda_oracle_handle_error
+ * This function is used for checking the result of an OCI
+ * call.  The result itself is the return value, and we
+ * need the GdaConnection and OracleConnectionData to do
+ * our thing.  The type is OCI_HTYPE_ENV or OCI_HTYPE_ERROR
+ * as described for OCIErrorGet.
+ *
+ * The return value is true if there is no error, or false otherwise
+ *
+ * If the return value is OCI_SUCCESS or OCI_SUCCESS_WITH_INFO,
+ * we return TRUE.  Otherwise, if it is OCI_ERROR, try to get the
+ * Oracle error message using _gda_oracle_make_error.  Otherwise,
+ * make an error using the given message.
+ */
+GdaConnectionEvent * 
+_gda_oracle_handle_error (gint result, GdaConnection *cnc, 
+			  OracleConnectionData *cdata,
+			  ub4 type, const gchar *msg,
+			  const gchar *file, gint line)
+{
+	GdaConnectionEvent *error = NULL;
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+
+	switch (result) {
+	case OCI_SUCCESS:
+	case OCI_SUCCESS_WITH_INFO:
+		return NULL;
+	case OCI_ERROR:
+		switch(type) {
+		case OCI_HTYPE_ERROR:
+			error = _gda_oracle_make_error (cdata->herr, type, file, line);
+			gda_connection_add_event (cnc, error);
+			break;
+		case OCI_HTYPE_ENV:
+			error = _gda_oracle_make_error (cdata->henv, type, file, line);
+			gda_connection_add_event (cnc, error);
+			break;
+		default:
+			error = gda_connection_add_event_string (cnc, msg);
+			gda_connection_add_event (cnc, error);
+			break;
+		}
+		break;
+	case OCI_NO_DATA:
+		g_warning ("Internal implementation error: OCI_NO_DATA not handled!\n");
+		break;
+	case OCI_INVALID_HANDLE:
+		g_warning ("Internal error: Invalid handle!");
+	default:
+		error = gda_connection_add_event_string (cnc, msg);
+	}
+
+	if (error)
+		g_print ("HANDLED error: %s\n", gda_connection_event_get_description (error));
+	return error;
+}
+
+GType 
+_oracle_sqltype_to_g_type (const ub2 sqltype)
+{
+	/* an incomplete list of all the oracle types */
+	switch (sqltype) {
+	case SQLT_CHR:
+	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:
+		return G_TYPE_STRING;
+	case SQLT_NUM:
+		return GDA_TYPE_NUMERIC;
+	case SQLT_INT:
+		return G_TYPE_INT;
+	case SQLT_UIN:
+		return G_TYPE_UINT;
+	case SQLT_FLT:
+		return G_TYPE_FLOAT;
+	case SQLT_VBI:
+	case SQLT_BIN:
+	case SQLT_LBI:
+	case SQLT_LVB:
+	case SQLT_BLOB:
+	case SQLT_BFILEE:
+	case SQLT_CFILEE:
+	case SQLT_CLOB:
+		return GDA_TYPE_BLOB;
+	case SQLT_DAT:
+	case SQLT_ODT:
+	case SQLT_DATE:
+		return G_TYPE_DATE;
+	case SQLT_TIME:
+	case SQLT_TIME_TZ:
+		return GDA_TYPE_TIME;
+	case SQLT_TIMESTAMP:
+	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:
+	default:
+		return G_TYPE_INVALID;
+	}
+}
+
+gchar * 
+_oracle_sqltype_to_string (const ub2 sqltype)
+{
+	/* an incomplete list of all the oracle types */
+	switch (sqltype) {
+	case SQLT_CHR:
+		return "VARCHAR2";
+	case SQLT_NUM:
+		return "NUMBER";
+	case SQLT_INT:
+		return "INTEGER";
+	case SQLT_FLT:
+		return "FLOAT";
+	case SQLT_STR:
+		return "STRING";
+	case SQLT_VNU:
+		return "VARNUM";
+	case SQLT_PDN:
+		return "";
+	case SQLT_LNG:
+		return "LONG";
+	case SQLT_VCS:
+		return "VARCHAR";
+	case SQLT_NON:
+		return "";
+	case SQLT_RID:
+		return "ROWID";
+	case SQLT_DAT:
+		return "DATE";
+	case SQLT_VBI:
+		return "VARRAW";
+	case SQLT_BIN:
+		return "RAW";
+	case SQLT_LBI:
+		return "LONG RAW";
+	case SQLT_UIN:
+		return "UNSIGNED INT";
+	case SQLT_SLS:
+		return "";
+	case SQLT_LVC:
+		return "LONG VARCHAR";
+	case SQLT_LVB:
+		return "LONG VARRAW";
+	case SQLT_AFC:
+		return "CHAR";
+	case SQLT_AVC:
+		return "CHARZ";
+	case SQLT_CUR:
+		return "CURSOR";
+	case SQLT_RDD:
+		return "ROWID";
+	case SQLT_LAB:
+		return "LABEL";
+	case SQLT_OSL:
+		return "OSLABEL";
+	case SQLT_NTY:
+		return "";
+	case SQLT_REF:
+		return "";
+	case SQLT_CLOB:
+		return "CLOB";
+	case SQLT_BLOB:
+		return "BLOB";
+	case SQLT_BFILEE:
+		return "BFILE";
+	case SQLT_CFILEE:
+		return "CFILE";
+	case SQLT_RSET:
+		return "RESULT SET";
+	case SQLT_NCO:
+		return "";
+	case SQLT_VST:
+		return "";
+	case SQLT_ODT:
+		return "OCI DATE";
+	case SQLT_DATE:
+		return "ANSI DATE";
+	case SQLT_TIME:
+		return "TIME";
+	case SQLT_TIME_TZ:
+		return "TIME WITH TIME ZONE";
+	case SQLT_TIMESTAMP:
+		return "TIMESTAMP";
+	case SQLT_TIMESTAMP_TZ:
+		return "TIMESTAMP WITH TIME ZONE";
+	case SQLT_INTERVAL_YM:
+		return "INTERVAL YEAR TO MONTH";
+	case SQLT_INTERVAL_DS:
+		return "INTERVAL DAY TO SECOND";
+	case SQLT_TIMESTAMP_LTZ:
+		return "TIMESTAMP WITH LOCAL TIME ZONE";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+gchar *
+_gda_oracle_value_to_sql_string (GValue *value)
+{
+	gchar *val_str;
+	gchar *ret;
+	GType type;
+
+	g_return_val_if_fail (value != NULL, NULL);
+
+	val_str = gda_value_stringify (value);
+	if (!val_str)
+		return NULL;
+
+	type = G_VALUE_TYPE (value);
+	if ((type == G_TYPE_INT64) ||
+	    (type == G_TYPE_DOUBLE) ||
+	    (type == G_TYPE_INT) ||
+	    (type == GDA_TYPE_NUMERIC) ||
+	    (type == G_TYPE_FLOAT) ||
+	    (type == GDA_TYPE_SHORT) ||
+	    (type == G_TYPE_CHAR))
+		ret = val_str;
+	else {
+		ret = g_strdup_printf ("\"%s\"", val_str);
+		g_free(val_str);
+	}
+	
+	return ret;
+}
+
+GdaOracleValue *
+_gda_value_to_oracle_value (const GValue *value)
+{
+	GdaOracleValue *ora_value;
+	OCIDate *oci_date;
+	GType type;
+
+	ora_value = g_new0 (GdaOracleValue, 1);
+
+	ora_value->g_type = G_VALUE_TYPE (value);
+	ora_value->indicator = 0;
+	ora_value->hdef = (OCIDefine *) 0;
+	ora_value->pard = (OCIParam *) 0;
+	type = ora_value->g_type;
+
+	if (type == GDA_TYPE_NULL)
+		ora_value->indicator = -1;
+	else if ((type == G_TYPE_INT64) ||
+		 (type == G_TYPE_DOUBLE) ||
+		 (type == G_TYPE_INT) ||
+		 (type == GDA_TYPE_NUMERIC) ||
+		 (type == G_TYPE_FLOAT) ||
+		 (type == GDA_TYPE_SHORT) ||
+		 (type == G_TYPE_CHAR)) {
+		gchar *val_str;
+		val_str = gda_value_stringify ((GValue *) value);
+		if (!val_str)
+			return NULL;
+		
+		ora_value->sql_type = SQLT_NUM;
+		ora_value->value = (void *) val_str;
+		ora_value->defined_size = strlen (val_str);
+	}
+	else if (type == G_TYPE_DATE) {
+		GDate *gda_date;
+		ora_value->sql_type = SQLT_ODT;
+		gda_date = (GDate*) g_value_get_boxed (value);
+		oci_date = g_new0(OCIDate, 1);
+		OCIDateSetDate(oci_date, gda_date->year, gda_date->month, gda_date->day);
+		ora_value->defined_size = sizeof (OCIDate);
+		ora_value->value = oci_date;
+	}
+	else if (type == GDA_TYPE_TIME) {
+		GdaTime *gda_time;
+		ora_value->sql_type = SQLT_ODT;
+		gda_time = (GdaTime *) gda_value_get_time ((GValue *) value);
+		oci_date = g_new0(OCIDate, 1);
+		OCIDateSetTime(oci_date, gda_time->hour, gda_time->minute, gda_time->second);
+		ora_value->defined_size = sizeof (OCIDate);
+		ora_value->value = oci_date;
+	}
+	else if (type == GDA_TYPE_TIMESTAMP) {
+		GdaTimestamp *gda_timestamp;
+		ora_value->sql_type = SQLT_ODT;
+		gda_timestamp = (GdaTimestamp *) gda_value_get_timestamp ((GValue *) value);
+		oci_date = g_new0(OCIDate, 1);
+		OCIDateSetDate(oci_date, gda_timestamp->year, gda_timestamp->month, gda_timestamp->day);
+		OCIDateSetTime(oci_date, gda_timestamp->hour, gda_timestamp->minute, gda_timestamp->second);
+		ora_value->defined_size = sizeof (OCIDate);
+		ora_value->value = oci_date;
+	}
+	else if (type == GDA_TYPE_BLOB) {
+		GdaBinary *bin;
+
+		bin = (GdaBinary *) gda_value_get_blob ((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);
+		if (!val_str)
+			return NULL;
+
+		ora_value->sql_type = SQLT_CHR;
+		ora_value->value = val_str;
+		ora_value->defined_size = strlen (val_str);
+	}
+
+	return ora_value;
+}
+
+void
+_gda_oracle_set_value (GValue *value, 
+		       GdaOracleValue *ora_value,
+		       GdaConnection *cnc)
+{
+	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)) {
+		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';
+		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);
+	}
+	else if (type == G_TYPE_DATE) {
+		GDate *date;
+		OCIDateGetDate ((CONST OCIDate *) ora_value->value,
+				(sb2 *) &year,
+				(ub1 *) &month,
+				(ub1 *) &day);
+		date = g_date_new_dmy (day, month, year);
+		g_value_take_boxed (value, date);
+	}
+	else if (type == GDA_TYPE_GEOMETRIC_POINT) {}
+	else if (type == GDA_TYPE_NULL)
+		gda_value_set_null (value);
+	else if (type == GDA_TYPE_TIMESTAMP) {
+		OCIDateGetDate ((CONST OCIDate *) ora_value->value,
+				(sb2 *) &year,
+				(ub1 *) &month,
+				(ub1 *) &day);
+		OCIDateGetTime ((CONST OCIDate *) ora_value->value,
+				(ub1 *) &hour,
+				(ub1 *) &min,
+				(ub1 *) &sec);
+		timestamp.year = year;
+		timestamp.month = month;
+		timestamp.day = day;
+		timestamp.hour = hour;
+		timestamp.minute = min;
+		timestamp.second = sec;
+		timestamp.fraction = 0;
+		timestamp.timezone = 0;
+		gda_value_set_timestamp(value, &timestamp);
+	}
+	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);
+	}
+	else if (type == GDA_TYPE_BINARY) {
+		g_warning ("GdaBinary type is not supported by Oracle");
+	}
+	else if (type == GDA_TYPE_BLOB) {
+		GdaBlob *blob;
+		GdaBlobOp *op;
+		OCILobLocator *lobloc;
+		OracleConnectionData *cdata;
+		gint result;
+
+		/* REM: we need to make a "copy" of the lob locator to give to the GdaOracleblobOp object */
+		cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data (cnc);
+		if (!cdata) {
+			gda_connection_add_event_string (cnc, _("Invalid Oracle handle"));
+			gda_value_set_null (value);
+			return;
+		}
+
+		result = OCIDescriptorAlloc ((dvoid *) cdata->henv, (dvoid **) &lobloc, 
+					     (ub4) gda_oracle_blob_type (ora_value->sql_type), (size_t) 0, (dvoid **) 0);
+		if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+					     _("Could not allocate Lob locator"))) {
+			gda_value_set_null (value);
+			return;
+		}
+
+		result = OCILobAssign ((dvoid *) cdata->henv, (dvoid *) cdata->herr, ora_value->value, &lobloc);
+		if (gda_oracle_check_result (result, cnc, cdata, OCI_HTYPE_ERROR,
+					     _("Could not copy Lob locator"))) {
+			gda_value_set_null (value);
+			return;
+		}
+
+		blob = g_new0 (GdaBlob, 1);
+		op = gda_oracle_blob_op_new (cnc, lobloc);
+		gda_blob_set_op (blob, op);
+		g_object_unref (op);
+
+		gda_value_take_blob (value, blob);
+	}
+	else
+		g_value_set_string (value, ora_value->value);
+}
+
+void
+_gda_oracle_value_free (GdaOracleValue *ora_value)
+{
+	if (ora_value->g_type == GDA_TYPE_BLOB)
+                OCIDescriptorFree ((dvoid *) ora_value->value, (ub4) gda_oracle_blob_type (ora_value->sql_type));
+        else
+                g_free (ora_value->value);
+        OCIDescriptorFree ((dvoid *) ora_value->pard, OCI_DTYPE_PARAM);
+        g_free (ora_value);
+}
diff --git a/providers/oracle/gda-oracle-util.h b/providers/oracle/gda-oracle-util.h
new file mode 100644
index 0000000..55c4892
--- /dev/null
+++ b/providers/oracle/gda-oracle-util.h
@@ -0,0 +1,69 @@
+/* GDA oracle 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_ORACLE_UTIL_H__
+#define __GDA_ORACLE_UTIL_H__
+
+#include "gda-oracle.h"
+
+G_BEGIN_DECLS
+
+#define gda_oracle_check_result(result, cnc, cdata, type, msg) \
+        (((result) == OCI_SUCCESS || (result) == OCI_SUCCESS_WITH_INFO) \
+	 ? NULL : _gda_oracle_handle_error ((result), (cnc), (cdata),	\
+					    (type), (msg), __FILE__, __LINE__))
+
+#define gda_oracle_blob_type(sqltype) \
+        ((((sqltype) == SQLT_BFILEE) || ((sqltype) == SQLT_CFILEE)) ? OCI_DTYPE_FILE : OCI_DTYPE_LOB)
+
+
+typedef struct {
+	OCIDefine *hdef;
+        OCIParam *pard;
+        sb2 indicator;
+        ub2 sql_type;
+        ub2 defined_size;
+        gpointer value;
+        GType g_type;
+} GdaOracleValue;
+
+GdaConnectionEvent *_gda_oracle_make_error (dvoid *hndlp, ub4 type, const gchar *file, gint line);
+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);
+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);
+void                _gda_oracle_set_value (GValue *value,
+					   GdaOracleValue *ora_value,
+					   GdaConnection *cnc);
+void                _gda_oracle_value_free (GdaOracleValue *ora_value);
+
+
+
+G_END_DECLS
+
+#endif
+
diff --git a/providers/oracle/gda-oracle.h b/providers/oracle/gda-oracle.h
index f48ea10..1afd601 100644
--- a/providers/oracle/gda-oracle.h
+++ b/providers/oracle/gda-oracle.h
@@ -1,8 +1,8 @@
 /* GDA oracle provider
- * Copyright (C) 2008 The GNOME Foundation.
+ * Copyright (C) 2009 The GNOME Foundation.
  *
  * AUTHORS:
- *      TO_ADD: your name and email
+ *      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
@@ -28,16 +28,20 @@
  */
 #define ORACLE_PROVIDER_NAME "Oracle"
 
-/* TO_ADD: include headers necessary for the C or C++ API */
+/* headers necessary for the C or C++ API */
+#include <libgda/libgda.h>
+#include <oci.h>
 
 /*
  * Provider's specific connection data
  */
 typedef struct {
-	/* TO_ADD: this structure holds any information necessary to specialize the GdaConnection, usually a connection
-	 * handle from the C or C++ API
-	 */
-	int foo;
+	OCIEnv *henv;
+        OCIError *herr;
+        OCIServer *hserver;
+        OCISvcCtx *hservice;
+        OCISession *hsession;
+        gchar *schema; /* the same as the username which opened the connection */
 } OracleConnectionData;
 
 #endif
diff --git a/providers/oracle/libmain.c b/providers/oracle/libmain.c
index 82ae921..f41ae91 100644
--- a/providers/oracle/libmain.c
+++ b/providers/oracle/libmain.c
@@ -1,8 +1,8 @@
 /* GDA Oracle Provider
- * Copyright (C) 2008 The GNOME Foundation
+ * Copyright (C) 2009 The GNOME Foundation
  *
  * AUTHORS:
- *      TO_ADD: your name and email
+ *      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
@@ -68,7 +68,7 @@ plugin_get_name (void)
 const gchar *
 plugin_get_description (void)
 {
-	return _("Example provider for C API databases");
+	return _("Provider for Oracle databases");
 }
 
 gchar *



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