[libgda] Brought the Oracle provider up to date
- From: Vivien Malerba <vivien src gnome org>
- To: svn-commits-list gnome org
- Subject: [libgda] Brought the Oracle provider up to date
- Date: Thu, 23 Jul 2009 19:37:35 +0000 (UTC)
commit 59752c39afc506204ce57dd920eaf4825ce58e25
Author: Vivien Malerba <malerba gnome-db org>
Date: Thu Jul 23 20:50:42 2009 +0200
Brought the Oracle provider up to date
* with SQL reserved keywords for v8 and V9
* with the implementation of the identifier_quote() virtual method
* with an update test-identifiers-quotes test
providers/oracle/Makefile.am | 16 ++-
providers/oracle/gda-oracle-provider.c | 213 +++++++++++++++++++++++++++++++-
providers/oracle/gda-oracle-util.c | 28 ++++
providers/oracle/gda-oracle-util.h | 4 +
providers/oracle/keywords_8.list | 29 +++++
providers/oracle/keywords_9.list | 109 ++++++++++++++++
tests/test-identifiers-quotes.c | 11 ++
7 files changed, 406 insertions(+), 4 deletions(-)
---
diff --git a/providers/oracle/Makefile.am b/providers/oracle/Makefile.am
index d73a8ac..88911b1 100644
--- a/providers/oracle/Makefile.am
+++ b/providers/oracle/Makefile.am
@@ -11,6 +11,15 @@ AM_CPPFLAGS = \
$(LIBGDA_CFLAGS) \
$(ORACLE_CFLAGS)
+keyword_files=keywords_8.list keywords_9.list
+pkeyword_files=$(addprefix $(top_srcdir)/providers/oracle/,$(keyword_files))
+mkkeywordhash$(EXEEXT_FOR_BUILD): $(top_srcdir)/libgda/sqlite/mkkeywordhash.c
+ $(CC_FOR_BUILD) -g -o mkkeywordhash$(EXEEXT_FOR_BUILD) $(GDA_DEBUG_FLAGS) $<
+
+keywords_hash.c: mkkeywordhash$(EXEEXT_FOR_BUILD) $(pkeyword_files)
+ ./mkkeywordhash$(EXEEXT_FOR_BUILD) $(top_srcdir)/providers/oracle/keywords_8.list V8 > keywords_hash.c
+ ./mkkeywordhash$(EXEEXT_FOR_BUILD) $(top_srcdir)/providers/oracle/keywords_9.list V9 >> keywords_hash.c
+
# parser generation
parser.c parser.h: parser.y $(top_builddir)/libgda/sql-parser/lemon$(EXEEXT_FOR_BUILD)
- $(top_builddir)/libgda/sql-parser/lemon$(EXEEXT_FOR_BUILD) -q -d $(srcdir)/parser.y $(top_srcdir)/libgda/sql-parser/lempar.c
@@ -21,7 +30,7 @@ gen_def$(EXEEXT_FOR_BUILD): gen_def.c
oracle_token_types.h: gen_def$(EXEEXT_FOR_BUILD) parser.h
./gen_def$(EXEEXT_FOR_BUILD) > oracle_token_types.h
-$(OBJECTS) $(libgda_oracle_la_OBJECTS): oracle_token_types.h
+$(OBJECTS) $(libgda_oracle_la_OBJECTS): oracle_token_types.h keywords_hash.c
libgda_oracle_la_SOURCES = \
gda-oracle-blob-op.c \
@@ -63,7 +72,8 @@ xml_DATA = $(xml_in_files:.xml.in=.xml)
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libgda-oracle-4.0.pc
-EXTRA_DIST = $(xml_in_files) libgda-oracle-4.0.pc.in parser.y gen_def.c
+EXTRA_DIST = $(xml_in_files) libgda-oracle-4.0.pc.in parser.y gen_def.c $(keyword_files)
DISTCLEANFILES = $(xml_DATA)
-CLEANFILES = parser.h parser.c parser.out oracle_token_types.h gen_def$(EXEEXT_FOR_BUILD)
+CLEANFILES = parser.h parser.c parser.out oracle_token_types.h gen_def$(EXEEXT_FOR_BUILD) \
+ mkkeywordhash$(EXEEXT_FOR_BUILD) keywords_hash.c
diff --git a/providers/oracle/gda-oracle-provider.c b/providers/oracle/gda-oracle-provider.c
index 5799185..dd80ea9 100644
--- a/providers/oracle/gda-oracle-provider.c
+++ b/providers/oracle/gda-oracle-provider.c
@@ -117,6 +117,11 @@ static GObject *gda_oracle_provider_statement_execute (GdaServerProv
guint *task_id, GdaServerProviderExecCallback async_cb,
gpointer cb_data, GError **error);
+/* Quoting */
+static gchar *gda_oracle_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
+ const gchar *id,
+ gboolean meta_store_convention, gboolean force_quotes);
+
/* distributed transactions */
static gboolean gda_oracle_provider_xa_start (GdaServerProvider *provider, GdaConnection *cnc,
const GdaXaTransactionId *xid, GError **error);
@@ -197,6 +202,7 @@ gda_oracle_provider_class_init (GdaOracleProviderClass *klass)
provider_class->is_busy = NULL;
provider_class->cancel = NULL;
provider_class->create_connection = NULL;
+ provider_class->identifier_quote = gda_oracle_identifier_quote;
memset (&(provider_class->meta_funcs), 0, sizeof (GdaServerProviderMeta));
provider_class->meta_funcs._info = _gda_oracle_meta__info;
@@ -727,7 +733,6 @@ static const gchar *
gda_oracle_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc)
{
OracleConnectionData *cdata;
- static guchar version[512];
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
@@ -2107,6 +2112,212 @@ gda_oracle_provider_xa_recover (GdaServerProvider *provider, GdaConnection *cnc,
return NULL;
}
+static gchar *
+identifier_add_quotes (const gchar *str)
+{
+ gchar *retval, *rptr;
+ const gchar *sptr;
+ gint len;
+
+ if (!str)
+ return NULL;
+
+ len = strlen (str);
+ retval = g_new (gchar, 2*len + 3);
+ *retval = '"';
+ for (rptr = retval+1, sptr = str; *sptr; sptr++, rptr++) {
+ if (*sptr == '"') {
+ *rptr = '\\';
+ rptr++;
+ *rptr = *sptr;
+ }
+ else
+ *rptr = *sptr;
+ }
+ *rptr = '"';
+ rptr++;
+ *rptr = 0;
+ return retval;
+}
+
+static gboolean
+_sql_identifier_needs_quotes (const gchar *str)
+{
+ const gchar *ptr;
+
+ g_return_val_if_fail (str, FALSE);
+ for (ptr = str; *ptr; ptr++) {
+ /* quote if 1st char is a number */
+ if ((*ptr <= '9') && (*ptr >= '0')) {
+ if (ptr == str)
+ return TRUE;
+ continue;
+ }
+ if (((*ptr >= 'A') && (*ptr <= 'Z')) ||
+ ((*ptr >= 'a') && (*ptr <= 'z')))
+ continue;
+
+ if ((*ptr != '$') && (*ptr != '_') && (*ptr != '#'))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* Returns: @str */
+static gchar *
+ora_remove_quotes (gchar *str)
+{
+ glong total;
+ gchar *ptr;
+ glong offset = 0;
+ char delim;
+
+ if (!str)
+ return NULL;
+ delim = *str;
+ if ((delim != '\'') && (delim != '"'))
+ return str;
+
+
+ total = strlen (str);
+ if (str[total-1] == delim) {
+ /* string is correclty terminated */
+ g_memmove (str, str+1, total-2);
+ total -=2;
+ }
+ else {
+ /* string is _not_ correclty terminated */
+ g_memmove (str, str+1, total-1);
+ total -=1;
+ }
+ str[total] = 0;
+
+ ptr = (gchar *) str;
+ while (offset < total) {
+ /* we accept the "''" as a synonym of "\'" */
+ if (*ptr == delim) {
+ if (*(ptr+1) == delim) {
+ g_memmove (ptr+1, ptr+2, total - offset);
+ offset += 2;
+ }
+ else {
+ *str = 0;
+ return str;
+ }
+ }
+ if (*ptr == '\\') {
+ if (*(ptr+1) == '\\') {
+ g_memmove (ptr+1, ptr+2, total - offset);
+ offset += 2;
+ }
+ else {
+ if (*(ptr+1) == delim) {
+ *ptr = delim;
+ g_memmove (ptr+1, ptr+2, total - offset);
+ offset += 2;
+ }
+ else {
+ *str = 0;
+ return str;
+ }
+ }
+ }
+ else
+ offset ++;
+
+ ptr++;
+ }
+
+ return str;
+}
+
+static gchar *
+gda_oracle_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
+ const gchar *id,
+ gboolean for_meta_store, gboolean force_quotes)
+{
+ GdaSqlReservedKeywordsFunc kwfunc;
+ OracleConnectionData *cdata = NULL;
+
+ if (cnc) {
+ cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
+ return NULL;
+ }
+
+ kwfunc = _gda_oracle_get_reserved_keyword_func (cdata);
+
+ if (for_meta_store) {
+ gchar *tmp, *ptr;
+ tmp = ora_remove_quotes (g_strdup (id));
+ if (kwfunc (tmp)) {
+ ptr = gda_sql_identifier_add_quotes (tmp);
+ g_free (tmp);
+ return ptr;
+ }
+ else if (force_quotes) {
+ /* quote if non UC characters or digits at the 1st char or non allowed characters */
+ for (ptr = tmp; *ptr; ptr++) {
+ if (((*ptr >= 'A') && (*ptr <= 'Z')) ||
+ ((*ptr >= '0') && (*ptr <= '9') && (ptr != tmp)) ||
+ (*ptr == '_'))
+ continue;
+ else {
+ ptr = gda_sql_identifier_add_quotes (tmp);
+ g_free (tmp);
+ return ptr;
+ }
+ }
+ for (ptr = tmp; *ptr; ptr++) {
+ if ((*ptr >= 'A') && (*ptr <= 'Z'))
+ *ptr += 'a' - 'A';
+ }
+ return tmp;
+ }
+ else {
+ for (ptr = tmp; *ptr; ptr++) {
+ if (*id == '"') {
+ if (((*ptr >= 'A') && (*ptr <= 'Z')) ||
+ ((*ptr >= '0') && (*ptr <= '9') && (ptr != tmp)) ||
+ (*ptr == '_'))
+ continue;
+ else {
+ ptr = gda_sql_identifier_add_quotes (tmp);
+ g_free (tmp);
+ return ptr;
+ }
+ }
+ else if ((*ptr >= 'A') && (*ptr <= 'Z'))
+ *ptr += 'a' - 'A';
+ else if ((*ptr >= '0') && (*ptr <= '9') && (ptr == tmp)) {
+ ptr = gda_sql_identifier_add_quotes (tmp);
+ g_free (tmp);
+ return ptr;
+ }
+ }
+ if (*id == '"') {
+ for (ptr = tmp; *ptr; ptr++) {
+ if ((*ptr >= 'A') && (*ptr <= 'Z'))
+ *ptr += 'a' - 'A';
+ }
+ }
+ return tmp;
+ }
+ }
+ else {
+ if (*id == '"') {
+ /* there are already some quotes */
+ return g_strdup (id);
+ }
+ if (kwfunc (id) || _sql_identifier_needs_quotes (id) || force_quotes)
+ return identifier_add_quotes (id);
+
+ /* nothing to do */
+ return g_strdup (id);
+ }
+}
+
+
/*
* Free connection's specific data
*/
diff --git a/providers/oracle/gda-oracle-util.c b/providers/oracle/gda-oracle-util.c
index 2930efc..ba743ba 100644
--- a/providers/oracle/gda-oracle-util.c
+++ b/providers/oracle/gda-oracle-util.c
@@ -33,6 +33,9 @@
#include "gda-oracle-util.h"
#include "gda-oracle-blob-op.h"
+#include <libgda/sqlite/keywords_hash.h>
+#include "keywords_hash.c" /* this one is dynamically generated */
+
/*
* _gda_oracle_make_error
* This function uses OCIErrorGet to get a description of the error to
@@ -715,3 +718,28 @@ gda_g_type_to_static_type (GType type)
g_error ("Missing type '%s' in GDA static types", g_type_name (type));
return 0;
}
+
+#ifdef GDA_DEBUG
+void
+_gda_oracle_test_keywords (void)
+{
+ V8test_keywords();
+ V9test_keywords();
+}
+#endif
+
+GdaSqlReservedKeywordsFunc
+_gda_oracle_get_reserved_keyword_func (OracleConnectionData *cdata)
+{
+ if (cdata) {
+ switch (cdata->major_version) {
+ case 8:
+ return V8is_keyword;
+ case 9:
+ default:
+ return V9is_keyword;
+ break;
+ }
+ }
+ return V9is_keyword;
+}
diff --git a/providers/oracle/gda-oracle-util.h b/providers/oracle/gda-oracle-util.h
index e381553..8764b0c 100644
--- a/providers/oracle/gda-oracle-util.h
+++ b/providers/oracle/gda-oracle-util.h
@@ -107,6 +107,10 @@ void _gda_oracle_set_value (GValue *value,
GdaConnection *cnc);
void _gda_oracle_value_free (GdaOracleValue *ora_value);
+#ifdef GDA_DEBUG
+void _gda_oracle_test_keywords (void);
+#endif
+GdaSqlReservedKeywordsFunc _gda_oracle_get_reserved_keyword_func (OracleConnectionData *cdata);
G_END_DECLS
diff --git a/providers/oracle/keywords_8.list b/providers/oracle/keywords_8.list
new file mode 100644
index 0000000..7ce5e56
--- /dev/null
+++ b/providers/oracle/keywords_8.list
@@ -0,0 +1,29 @@
+ACCESS ELSE MODIFY START
+ADD EXCLUSIVE NOAUDIT SELECT
+ALL EXISTS NOCOMPRESS SESSION
+ALTER FILE NOT SET
+AND FLOAT NOTFOUND SHARE
+ANY FOR NOWAIT SIZE
+ARRAYLEN FROM NULL SMALLINT
+AS GRANT NUMBER SQLBUF
+ASC GROUP OF SUCCESSFUL
+AUDIT HAVING OFFLINE SYNONYM
+BETWEEN IDENTIFIED ON SYSDATE
+BY IMMEDIATE ONLINE TABLE
+CHAR IN OPTION THEN
+CHECK INCREMENT OR TO
+CLUSTER INDEX ORDER TRIGGER
+COLUMN INITIAL PCTFREE UID
+COMMENT INSERT PRIOR UNION
+COMPRESS INTEGER PRIVILEGES UNIQUE
+CONNECT INTERSECT PUBLIC UPDATE
+CREATE INTO RAW USER
+CURRENT IS RENAME VALIDATE
+DATE LEVEL RESOURCE VALUES
+DECIMAL LIKE REVOKE VARCHAR
+DEFAULT LOCK ROW VARCHAR2
+DELETE LONG ROWID VIEW
+DESC MAXEXTENTS ROWLABEL WHENEVER
+DISTINCT MINUS ROWNUM WHERE
+DROP MODE ROWS WITH
+
diff --git a/providers/oracle/keywords_9.list b/providers/oracle/keywords_9.list
new file mode 100644
index 0000000..9c8a856
--- /dev/null
+++ b/providers/oracle/keywords_9.list
@@ -0,0 +1,109 @@
+ACCESS
+ADD
+ALL
+ALTER
+AND
+ANY
+AS
+ASC
+AUDIT
+BETWEEN
+BY
+CHAR
+CHECK
+CLUSTER
+COLUMN
+COMMENT
+COMPRESS
+CONNECT
+CREATE
+CURRENT
+DATE
+DECIMAL
+DEFAULT
+DELETE
+DESC
+DISTINCT
+DROP
+ELSE
+EXCLUSIVE
+EXISTS
+FILE
+FLOAT
+FOR
+FROM
+GRANT
+GROUP
+HAVING
+IDENTIFIED
+IMMEDIATE
+IN
+INCREMENT
+INDEX
+INITIAL
+INSERT
+INTEGER
+INTERSECT
+INTO
+IS
+LEVEL
+LIKE
+LOCK
+LONG
+MAXEXTENTS
+MINUS
+MLSLABEL
+MODE
+MODIFY
+NOAUDIT
+NOCOMPRESS
+NOT
+NOWAIT
+NULL
+NUMBER
+OF
+OFFLINE
+ON
+ONLINE
+OPTION
+OR
+ORDER
+PCTFREE
+PRIOR
+PRIVILEGES
+PUBLIC
+RAW
+RENAME
+RESOURCE
+REVOKE
+ROW
+ROWID
+ROWNUM
+ROWS
+SELECT
+SESSION
+SET
+SHARE
+SIZE
+SMALLINT
+START
+SUCCESSFUL
+SYNONYM
+SYSDATE
+TABLE
+THEN
+TO
+TRIGGER
+UID
+UNION
+UNIQUE
+UPDATE
+USER
+VALIDATE
+VALUES
+VARCHAR
+VARCHAR2
+VIEW
+WHENEVER
+WHERE
+WITH
diff --git a/tests/test-identifiers-quotes.c b/tests/test-identifiers-quotes.c
index 79f6792..4193fa8 100644
--- a/tests/test-identifiers-quotes.c
+++ b/tests/test-identifiers-quotes.c
@@ -112,6 +112,17 @@ ATest tests[] = {
{"SQLite", "[5ive]", "\"5ive\"", "\"5ive\"", "\"5ive\"", "\"5ive\""},
{"SQLite", "`5ive`", "\"5ive\"", "\"5ive\"", "\"5ive\"", "\"5ive\""},
+ {"Oracle", "\"double word\"", "\"double word\"", "\"double word\"", "\"double word\"", "\"double word\""},
+ {"Oracle", "\"CapitalTest\"", "\"CapitalTest\"", "\"CapitalTest\"", "\"CapitalTest\"", "\"CapitalTest\""},
+ {"Oracle", "CapitalTest", "CapitalTest", "capitaltest", "\"CapitalTest\"", "\"CapitalTest\""},
+ {"Oracle", "\"mytable\"", "\"mytable\"", "\"mytable\"", "\"mytable\"", "\"mytable\""},
+ {"Oracle", "mytable", "mytable", "mytable", "\"mytable\"", "\"mytable\""},
+ {"Oracle", "MYTABLE", "MYTABLE", "mytable", "\"MYTABLE\"", "mytable"},
+ {"Oracle", "\"MYTABLE\"", "\"MYTABLE\"", "mytable", "\"MYTABLE\"", "mytable"},
+ {"Oracle", "desc", "\"desc\"", "\"desc\"", "\"desc\"", "\"desc\""},
+ {"Oracle", "5ive", "\"5ive\"", "\"5ive\"", "\"5ive\"", "\"5ive\""},
+ {"Oracle", "\"5ive\"", "\"5ive\"", "\"5ive\"", "\"5ive\"", "\"5ive\""},
+
};
static gboolean
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]