[libgda] Improved Oracle provider
- From: Vivien Malerba <vivien src gnome org>
- To: svn-commits-list gnome org
- Subject: [libgda] Improved Oracle provider
- Date: Thu, 23 Apr 2009 14:57:33 -0400 (EDT)
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, ¶ms, 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, ×tamp);
+ }
+ 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, >ime);
+ }
+ 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]