[libgda/LIBGDA_4.0] Added support for SQL reserved keywords



commit ff3e0c1dd77426e25f29e2b4a08609e26803cafe
Author: Vivien Malerba <malerba gnome-db org>
Date:   Tue Jul 7 21:03:10 2009 +0200

    Added support for SQL reserved keywords
    
    SQL reserved keywords (specific to each database engine) are now
    taken into account (for SQLite and PostgreSQL for the moment) when
    extracting meta data.
    
    Specifically, each provider needs to have a file listing its SQL
    reserved keywords and a new program (modified from SQLite's tools)
    creates a static hash table and a lookup function which is used
    in the meta data extraction routines.

 libgda/gda-data-meta-wrapper.c         |   48 +++-
 libgda/gda-data-meta-wrapper.h         |    3 +-
 libgda/gda-decl.h                      |    4 +
 libgda/gda-meta-store.c                |   25 ++-
 libgda/gda-meta-store.h                |    2 +
 libgda/sql-parser/gda-sql-parser.c     |    2 +-
 libgda/sqlite/.gitignore               |    4 +-
 libgda/sqlite/Makefile.am              |   12 +-
 libgda/sqlite/gda-sqlite-meta.c        |   61 +++-
 libgda/sqlite/keywords.list            |  119 ++++++++
 libgda/sqlite/mkkeywordhash.c          |  514 ++++++++++++++++++++++++++++++++
 providers/.gitignore                   |    4 +-
 providers/postgres/Makefile.am         |   13 +-
 providers/postgres/gda-postgres-meta.c |   98 ++++++-
 providers/postgres/keywords.list       |  101 +++++++
 15 files changed, 963 insertions(+), 47 deletions(-)
---
diff --git a/libgda/gda-data-meta-wrapper.c b/libgda/gda-data-meta-wrapper.c
index 9e32493..9ca8f5c 100644
--- a/libgda/gda-data-meta-wrapper.c
+++ b/libgda/gda-data-meta-wrapper.c
@@ -60,6 +60,8 @@ struct _GdaDataMetaWrapperPrivate {
 	gint *cols_to_wrap;
 	gint cols_to_wrap_size;
 	GdaSqlIdentifierStyle mode;
+	GdaSqlReservedKeywordsFunc reserved_keyword_func;
+
 	GHashTable *computed_rows; /* key = row number, value = a CompRow pointer
 				    * may be %NULL if we don't keep computed values */
 	CompRow *buffer; /* may be %NULL if we keep computed values */
@@ -197,6 +199,7 @@ gda_data_meta_wrapper_init (GdaDataMetaWrapper *model, GdaDataMetaWrapperClass *
 	model->priv->cols_to_wrap = NULL;
 	model->priv->cols_to_wrap_size = 0;
 	model->priv->mode = GDA_DATA_META_WRAPPER_MODE_LC;
+	model->priv->reserved_keyword_func = NULL;
 	model->priv->computed_rows = NULL;
 	model->priv->buffer = NULL;
 }
@@ -321,7 +324,8 @@ gda_data_meta_wrapper_get_property (GObject *object,
  * Returns: a pointer to the newly created #GdaDataModel.
  */
 GdaDataModel *
-_gda_data_meta_wrapper_new (GdaDataModel *model, gboolean reuseable, gint *cols, gint size, GdaSqlIdentifierStyle mode)
+_gda_data_meta_wrapper_new (GdaDataModel *model, gboolean reuseable, gint *cols, gint size, GdaSqlIdentifierStyle mode,
+			    GdaSqlReservedKeywordsFunc reserved_keyword_func)
 {
 	GdaDataMetaWrapper *retmodel;
 
@@ -334,6 +338,7 @@ _gda_data_meta_wrapper_new (GdaDataModel *model, gboolean reuseable, gint *cols,
 	memcpy (retmodel->priv->cols_to_wrap, cols, sizeof (gint) * size);
 	retmodel->priv->cols_to_wrap_size = size;
 	retmodel->priv->mode = mode;
+	retmodel->priv->reserved_keyword_func = reserved_keyword_func;
 	
 	if (reuseable)
 		retmodel->priv->computed_rows = g_hash_table_new_full (g_int_hash, g_int_equal,
@@ -454,7 +459,7 @@ to_lower (gchar *str)
  *  - a new GValue if changes were necessary
  */
 static GValue *
-compute_value (const GValue *value, GdaSqlIdentifierStyle mode)
+compute_value (const GValue *value, GdaSqlIdentifierStyle mode, GdaSqlReservedKeywordsFunc reserved_keyword_func)
 {
 	GValue *retval = NULL;
 	const gchar *str;
@@ -477,9 +482,18 @@ compute_value (const GValue *value, GdaSqlIdentifierStyle mode)
 				sa[i] = tmp;
 				onechanged = TRUE;
 			}
-			else if (! identifier_is_all_lower (sa[i])) {
-				to_lower (sa[i]);
-				onechanged = TRUE;
+			else {
+				if (! identifier_is_all_lower (sa[i])) {
+					to_lower (sa[i]);
+					onechanged = TRUE;
+				}
+
+				if (reserved_keyword_func && reserved_keyword_func (sa[i])) {
+					gchar *tmp = gda_sql_identifier_add_quotes (sa[i]);
+					g_free (sa[i]);
+					sa[i] = tmp;
+					onechanged = TRUE;
+				}
 			}
 		}
 		if (onechanged) {
@@ -492,11 +506,21 @@ compute_value (const GValue *value, GdaSqlIdentifierStyle mode)
 			retval = gda_value_new (G_TYPE_STRING);
 			g_value_take_string (retval, gda_sql_identifier_add_quotes (str));
 		}
-		else if (! identifier_is_all_lower (str)) {
-			gchar *tmp;
-			tmp = to_lower (g_strdup (str));
-			retval = gda_value_new (G_TYPE_STRING);
-			g_value_take_string (retval, tmp);
+		else {
+			gchar *tmp = NULL;
+			if (! identifier_is_all_lower (str))
+				tmp = to_lower (g_strdup (str));
+
+			if (reserved_keyword_func && reserved_keyword_func (tmp ? tmp : str)) {
+				gchar *tmp2 = gda_sql_identifier_add_quotes (tmp ? tmp : str);
+				if (tmp)
+					g_free (tmp);
+				tmp = tmp2;
+			}
+			if (tmp) {
+				retval = gda_value_new (G_TYPE_STRING);
+				g_value_take_string (retval, tmp);
+			}
 		}
 	}
 	g_strfreev (sa);
@@ -552,7 +576,7 @@ gda_data_meta_wrapper_get_value_at (GdaDataModel *model, gint col, gint row, GEr
 				return NULL;
 			
 			GValue *retval;
-			retval = compute_value (cvalue, imodel->priv->mode);
+			retval = compute_value (cvalue, imodel->priv->mode, imodel->priv->reserved_keyword_func);
 			if (!retval)
 				return cvalue;
 			
@@ -579,7 +603,7 @@ gda_data_meta_wrapper_get_value_at (GdaDataModel *model, gint col, gint row, GEr
 			return NULL;
 
 		GValue *retval;
-		retval = compute_value (cvalue, imodel->priv->mode);
+		retval = compute_value (cvalue, imodel->priv->mode, imodel->priv->reserved_keyword_func);
 		if (!retval)
 			return cvalue;
 		if (imodel->priv->buffer->values [indexcol])
diff --git a/libgda/gda-data-meta-wrapper.h b/libgda/gda-data-meta-wrapper.h
index 82b897f..eff38c0 100644
--- a/libgda/gda-data-meta-wrapper.h
+++ b/libgda/gda-data-meta-wrapper.h
@@ -60,7 +60,8 @@ struct _GdaDataMetaWrapperClass {
 
 GType         _gda_data_meta_wrapper_get_type    (void) G_GNUC_CONST;
 GdaDataModel *_gda_data_meta_wrapper_new         (GdaDataModel *model, gboolean reuseable,
-						  gint *cols, gint size, GdaSqlIdentifierStyle mode);
+						  gint *cols, gint size, GdaSqlIdentifierStyle mode,
+						  GdaSqlReservedKeywordsFunc reserved_keyword_func);
 
 G_END_DECLS
 
diff --git a/libgda/gda-decl.h b/libgda/gda-decl.h
index c2a674b..5afcc7c 100644
--- a/libgda/gda-decl.h
+++ b/libgda/gda-decl.h
@@ -105,6 +105,10 @@ typedef struct _GdaMetaStruct        GdaMetaStruct;
 typedef struct _GdaMetaStructClass   GdaMetaStructClass;
 typedef struct _GdaMetaStructPrivate GdaMetaStructPrivate;
 
+/*
+ * Determines if @word is a reserved SQL keyword
+ */
+typedef gboolean (*GdaSqlReservedKeywordsFunc) (const gchar *word);
 
 /*
  * Win32 adaptations
diff --git a/libgda/gda-meta-store.c b/libgda/gda-meta-store.c
index c78bf45..1031b9d 100644
--- a/libgda/gda-meta-store.c
+++ b/libgda/gda-meta-store.c
@@ -207,6 +207,8 @@ static gboolean ProviderSpecific_equal (gconstpointer a, gconstpointer b);
 struct _GdaMetaStorePrivate {
 	GdaConnection *cnc;
 	GdaSqlIdentifierStyle ident_style;
+	GdaSqlReservedKeywordsFunc reserved_keyword_func;
+
 	gint           version;
 	gboolean       schema_ok;
 
@@ -490,6 +492,7 @@ gda_meta_store_init (GdaMetaStore *store)
 	store->priv = g_new0 (GdaMetaStorePrivate, 1);
 	store->priv->cnc = NULL;
 	store->priv->ident_style = GDA_SQL_IDENTIFIERS_LOWER_CASE;
+	store->priv->reserved_keyword_func = NULL;
 	store->priv->schema_ok = FALSE;
 	store->priv->version = 0;
 
@@ -767,6 +770,25 @@ gda_meta_store_get_property (GObject *object,
 	}
 }
 
+/**
+ * gda_meta_store_set_reserved_keywords_func
+ * @store: a #GdaMetaStore object
+ * @func: a #GdaSqlReservedKeywordsFunc function, or %NULL
+ *
+ * Specifies a function which @store will use to determine if a keyword is an SQL reserved
+ * keyword or not.
+ *
+ * This method is mainly used by database providers.
+ *
+ * Since: 4.0.3
+ */
+void
+gda_meta_store_set_reserved_keywords_func(GdaMetaStore *store, GdaSqlReservedKeywordsFunc func)
+{
+	g_return_if_fail (GDA_IS_META_STORE (store));
+	store->priv->reserved_keyword_func = func;
+}
+
 /*
  * Checks the structure of @store->priv->cnc and update it if necessary
  */
@@ -2294,7 +2316,8 @@ gda_meta_store_modify_v (GdaMetaStore *store, const gchar *table_name,
 		if (schema_set->ident_cols)
 			wrapped_data = _gda_data_meta_wrapper_new (new_data, !store->priv->override_mode,
 								   schema_set->ident_cols, schema_set->ident_cols_size,
-								   store->priv->ident_style);
+								   store->priv->ident_style,
+								   store->priv->reserved_keyword_func);
 		else
 			wrapped_data = g_object_ref (new_data);
 
diff --git a/libgda/gda-meta-store.h b/libgda/gda-meta-store.h
index 4b9775f..740f024 100644
--- a/libgda/gda-meta-store.h
+++ b/libgda/gda-meta-store.h
@@ -115,6 +115,8 @@ gboolean          gda_meta_store_modify_with_context      (GdaMetaStore *store,
 							   GdaDataModel *new_data, GError **error);
 GdaDataModel     *gda_meta_store_create_modify_data_model (GdaMetaStore *store, const gchar *table_name);
 
+void              gda_meta_store_set_reserved_keywords_func(GdaMetaStore *store, GdaSqlReservedKeywordsFunc func);
+
 gboolean          gda_meta_store_get_attribute_value      (GdaMetaStore *store, const gchar *att_name, 
 							   gchar **att_value, GError **error);
 gboolean          gda_meta_store_set_attribute_value      (GdaMetaStore *store, const gchar *att_name, 
diff --git a/libgda/sql-parser/gda-sql-parser.c b/libgda/sql-parser/gda-sql-parser.c
index a778f8e..5a02762 100644
--- a/libgda/sql-parser/gda-sql-parser.c
+++ b/libgda/sql-parser/gda-sql-parser.c
@@ -851,7 +851,7 @@ static const char AsciiIdChar[] = {
 };
 #define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && AsciiIdChar[c-0x20]))
 
-const unsigned char UpperToLower[] = {
+static const unsigned char UpperToLower[] = {
       0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
      18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
      36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
diff --git a/libgda/sqlite/.gitignore b/libgda/sqlite/.gitignore
index f87b75b..38bce2a 100644
--- a/libgda/sqlite/.gitignore
+++ b/libgda/sqlite/.gitignore
@@ -1,2 +1,4 @@
 gen_emb_string
-xml_embedded.h
\ No newline at end of file
+xml_embedded.h
+mkkeywordhash
+keywords_hash.c
diff --git a/libgda/sqlite/Makefile.am b/libgda/sqlite/Makefile.am
index 9d27177..fa9ce5f 100644
--- a/libgda/sqlite/Makefile.am
+++ b/libgda/sqlite/Makefile.am
@@ -20,6 +20,12 @@ AM_CPPFLAGS = \
 	$(SQLITE_CFLAGS) \
 	$(sqliteinc) 
 
+mkkeywordhash$(EXEEXT_FOR_BUILD): mkkeywordhash.c
+	$(CC_FOR_BUILD) -o mkkeywordhash$(EXEEXT_FOR_BUILD) $(GDA_DEBUG_FLAGS) $<
+
+keywords_hash.c: mkkeywordhash$(EXEEXT_FOR_BUILD) keywords.list
+	./mkkeywordhash$(EXEEXT_FOR_BUILD) keywords.list > keywords_hash.c
+
 gen_emb_string$(EXEEXT_FOR_BUILD): gen_emb_string.c
 	$(CC_FOR_BUILD) -o gen_emb_string$(EXEEXT_FOR_BUILD) $<
 
@@ -28,7 +34,7 @@ xml_embedded.h: gen_emb_string$(EXEEXT_FOR_BUILD) $(top_srcdir)/providers/sqlite
 
 sqliteheaders = gda-sqlite-provider.h
 
-$(libgda_sqlite_la_OBJECTS): xml_embedded.h
+$(libgda_sqlite_la_OBJECTS): xml_embedded.h keywords_hash.c
 
 libgda_sqlite_la_SOURCES = \
 	$(sqliteheaders) \
@@ -57,6 +63,6 @@ libgda_sqlite_la_LIBADD = \
 gdaincludedir=$(includedir)/libgda-$(GDA_ABI_MAJOR_VERSION).$(GDA_ABI_MINOR_VERSION)/libgda/sqlite
 gdainclude_HEADERS=$(sqliteheaders)
 
-EXTRA_DIST = gen_emb_string.c
+EXTRA_DIST = gen_emb_string.c keywords.list
 
-CLEANFILES = gen_emb_string$(EXEEXT_FOR_BUILD) xml_embedded.h
+CLEANFILES = gen_emb_string$(EXEEXT_FOR_BUILD) xml_embedded.h mkkeywordhash$(EXEEXT_FOR_BUILD) keywords_hash.c
diff --git a/libgda/sqlite/gda-sqlite-meta.c b/libgda/sqlite/gda-sqlite-meta.c
index 106ba28..6504f94 100644
--- a/libgda/sqlite/gda-sqlite-meta.c
+++ b/libgda/sqlite/gda-sqlite-meta.c
@@ -32,6 +32,7 @@
 #include <libgda/gda-connection-private.h>
 #include <libgda/gda-data-model-array.h>
 #include <libgda/gda-set.h>
+#include "keywords_hash.c" /* this one is dynamically generated */
 
 static gboolean append_a_row (GdaDataModel *to_model, GError **error, gint nb, ...);
 
@@ -198,8 +199,10 @@ _gda_sqlite_meta__info (GdaServerProvider *prov, GdaConnection *cnc,
 	g_assert (model);
 
 	retval = append_a_row (model, error, 1, FALSE, catalog_value);
-	if (retval)
+	if (retval) {
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
+	}
 	g_object_unref (model);
 	return retval;
 }
@@ -255,8 +258,10 @@ _gda_sqlite_meta__btypes (GdaServerProvider *prov, GdaConnection *cnc,
 			break;
 		}
 	}
-	if (retval) 
+	if (retval) {
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify (store, context->table_name, mod_model, NULL, error, NULL);
+	}
 	g_object_unref (mod_model);
 
 	return retval;
@@ -437,8 +442,10 @@ _gda_sqlite_meta__udt (GdaServerProvider *prov, GdaConnection *cnc,
 	g_hash_table_destroy (added_hash);
 
 	/* actually use mod_model */
-	if (retval) 
+	if (retval) {
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify (store, context->table_name, mod_model, NULL, error, NULL);
+	}
 	g_object_unref (mod_model);
 
 	return retval;
@@ -471,8 +478,10 @@ _gda_sqlite_meta_udt (GdaServerProvider *prov, GdaConnection *cnc,
 	g_hash_table_destroy (added_hash);
 
 	/* actually use mod_model */
-	if (retval) 
+	if (retval) {
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify (store, context->table_name, mod_model, NULL, error, NULL);
+	}
 	g_object_unref (mod_model);
 
 	return retval;
@@ -655,8 +664,10 @@ _gda_sqlite_meta_schemata (GdaServerProvider *prov, GdaConnection *cnc,
 		}
 	}
 	g_object_unref (tmpmodel);
-	if (retval)
+	if (retval){
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify_with_context (store, context, model, error);
+	}
 	g_object_unref (model);
 
 	return retval;
@@ -801,10 +812,12 @@ _gda_sqlite_meta__tables_views (GdaServerProvider *prov, GdaConnection *cnc,
 	c2 = *context; /* copy contents, just because we need to modify @context->table_name */
 	if (retval) {
 		c2.table_name = "_tables";
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify_with_context (store, &c2, tables_model, error);
 	}
 	if (retval) {
 		c2.table_name = "_views";
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify_with_context (store, &c2, views_model, error);
 	}
 	g_object_unref (tables_model);
@@ -833,10 +846,12 @@ _gda_sqlite_meta_tables_views (GdaServerProvider *prov, GdaConnection *cnc,
 	c2 = *context; /* copy contents, just because we need to modify @context->table_name */
 	if (retval) {
 		c2.table_name = "_tables";
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify_with_context (store, &c2, tables_model, error);
 	}
 	if (retval) {
 		c2.table_name = "_views";
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify_with_context (store, &c2, views_model, error);
 	}
 	g_object_unref (tables_model);
@@ -1058,8 +1073,10 @@ _gda_sqlite_meta__columns (GdaServerProvider *prov, GdaConnection *cnc,
 	}
 	g_object_unref (tmpmodel);
 
-	if (retval)
+	if (retval) {
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify_with_context (store, context, mod_model, error);
+	}
 	g_object_unref (mod_model);
 
 	return retval;
@@ -1082,8 +1099,10 @@ _gda_sqlite_meta_columns (GdaServerProvider *prov, GdaConnection *cnc,
 	g_assert (mod_model);
 
 	retval = fill_columns_model (cnc, cdata, mod_model, table_schema, table_name, error);	
-	if (retval)
+	if (retval) {
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify_with_context (store, context, mod_model, error);
+	}
 	g_object_unref (mod_model);
 
 	return retval;
@@ -1395,8 +1414,10 @@ _gda_sqlite_meta__constraints_tab (GdaServerProvider *prov, GdaConnection *cnc,
 	}
 	g_object_unref (tmpmodel);
 
-	if (retval)
+	if (retval) {
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify_with_context (store, context, mod_model, error);
+	}
 	g_object_unref (mod_model);
 
 	return retval;
@@ -1420,8 +1441,10 @@ _gda_sqlite_meta_constraints_tab (GdaServerProvider *prov, GdaConnection *cnc,
 	g_assert (mod_model);
 
 	retval = fill_constraints_tab_model (cnc, cdata, mod_model, table_schema, table_name, constraint_name_n, error);	
-	if (retval)
+	if (retval) {
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify_with_context (store, context, mod_model, error);
+	}
 	g_object_unref (mod_model);
 
 	return retval;
@@ -1582,8 +1605,10 @@ _gda_sqlite_meta__constraints_ref (GdaServerProvider *prov, GdaConnection *cnc,
 	}
 	g_object_unref (tmpmodel);
 
-	if (retval)
+	if (retval) {
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify_with_context (store, context, mod_model, error);
+	}
 	g_object_unref (mod_model);
 
 	return retval;
@@ -1607,8 +1632,10 @@ _gda_sqlite_meta_constraints_ref (GdaServerProvider *prov, GdaConnection *cnc,
 	g_assert (mod_model);
 
 	retval = fill_constraints_ref_model (cnc, cdata, mod_model, table_schema, table_name, constraint_name, error);
-	if (retval)
+	if (retval) {
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify_with_context (store, context, mod_model, error);
+	}
 	g_object_unref (mod_model);
 
 	return retval;
@@ -1916,8 +1943,10 @@ _gda_sqlite_meta__key_columns (GdaServerProvider *prov, GdaConnection *cnc,
 	}
 	g_object_unref (const_model);
 
-	if (retval)
+	if (retval) {
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify_with_context (store, context, mod_model, error);
+	}
 	g_object_unref (mod_model);
 
 	return retval;
@@ -1941,8 +1970,10 @@ _gda_sqlite_meta_key_columns (GdaServerProvider *prov, GdaConnection *cnc,
 	g_assert (mod_model);
 
 	retval = fill_key_columns_model (cnc, cdata, mod_model, table_schema, table_name, constraint_name, error);
-	if (retval) 
+	if (retval) {
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify_with_context (store, context, mod_model, error);
+	}
 	g_object_unref (mod_model);
 
 	return retval;
@@ -2089,8 +2120,10 @@ _gda_sqlite_meta_routines (GdaServerProvider *prov, GdaConnection *cnc,
 		}
 	}
 	
-	if (retval)
+	if (retval) {
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify_with_context (store, context, mod_model, error);
+	}
 	g_object_unref (mod_model);
 	g_object_unref (tmpmodel);
 #endif
diff --git a/libgda/sqlite/keywords.list b/libgda/sqlite/keywords.list
new file mode 100644
index 0000000..51bdd79
--- /dev/null
+++ b/libgda/sqlite/keywords.list
@@ -0,0 +1,119 @@
+ABORT,
+ADD,
+AFTER,
+ALL,
+ALTER,
+ANALYZE,
+AND,
+AS,
+ASC,
+ATTACH,
+AUTOINCREMENT,
+BEFORE,
+BEGIN,
+BETWEEN,
+BY,
+CASCADE,
+CASE,
+CAST,
+CHECK,
+COLLATE,
+COLUMN,
+COMMIT,
+CONFLICT,
+CONSTRAINT,
+CREATE,
+CROSS,
+CURRENT_DATE,
+CURRENT_TIME,
+CURRENT_TIMESTAMP,TK_CTIME_KW,
+DATABASE,
+DEFAULT,
+DEFERRED,
+DEFERRABLE,
+DELETE,
+DESC,
+DETACH,
+DISTINCT,
+DROP,
+END,
+EACH,
+ELSE,
+ESCAPE,
+EXCEPT,
+EXCLUSIVE,
+EXISTS,
+EXPLAIN,
+FAIL,
+FOR,
+FOREIGN,
+FROM,
+FULL,
+GLOB,
+GROUP,
+HAVING,
+IF,
+IGNORE,
+IMMEDIATE,
+IN,
+INDEX,
+INDEXED,
+INITIALLY,
+INNER,
+INSERT,
+INSTEAD,
+INTERSECT,
+INTO,
+IS,
+ISNULL,
+JOIN,
+KEY,
+LEFT,
+LIKE,
+LIMIT,
+MATCH,
+NATURAL,
+NOT,
+NOTNULL,
+NULL,
+OF,
+OFFSET,
+ON,
+OR,
+ORDER,
+OUTER,
+PLAN,
+PRAGMA,
+PRIMARY,
+QUERY,
+RAISE,
+REFERENCES,
+REGEXP,
+REINDEX,
+RELEASE,
+RENAME,
+REPLACE,
+RESTRICT,
+RIGHT,
+ROLLBACK,
+ROW,
+SAVEPOINT,
+SELECT,
+SET,
+TABLE,
+TEMP,
+TEMPORARY,
+THEN,
+TO,
+TRANSACTION,
+TRIGGER,
+UNION,
+UNIQUE,
+UPDATE,
+USING,
+VACUUM,
+VALUES,
+VIEW,
+VIRTUAL,
+WHEN,
+WHERE,
diff --git a/libgda/sqlite/mkkeywordhash.c b/libgda/sqlite/mkkeywordhash.c
new file mode 100644
index 0000000..04e6fab
--- /dev/null
+++ b/libgda/sqlite/mkkeywordhash.c
@@ -0,0 +1,514 @@
+/*
+** Compile and run this standalone program in order to generate code that
+** implements a function that will translate alphabetic identifiers into
+** parser token codes.
+*/
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+/* if TEST_RESERVED_WORDS is defined, then the test_keywords() function is created
+ * which displays errors for any keyword
+ */
+#ifndef TEST_RESERVED_WORDS
+#ifdef GDA_DEBUG
+#define TEST_RESERVED_WORDS
+#endif
+#endif
+
+/*
+** A header comment placed at the beginning of generated code.
+*/
+static const char zHdr[] = 
+	"/* file contains automatically generated code, DO NOT MODIFY *\n"
+	" *\n"
+	" * The code in this file implements a function that determines whether\n"
+	" * or not a given identifier is really an SQL keyword.  The same thing\n"
+	" * might be implemented more directly using a hand-written hash table.\n"
+	" * But by using this automatically generated code, the size of the code\n"
+	" * is substantially reduced.  This is important for embedded applications\n"
+	" * on platforms with limited memory.\n"
+	" *\n"
+	" * This code has been copied from SQLite's mkkeywordhash.c file and modified.\n"
+	" * to read the SQL keywords from a file instead of static ones\n"
+	" */\n";
+static const char zCode[] = 
+	"static const unsigned char UpperToLower[] = {\n"
+	"      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,\n"
+	"     18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,\n"
+	"     36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,\n"
+	"     54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,\n"
+	"    104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,\n"
+	"    122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,\n"
+	"    108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,\n"
+	"    126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,\n"
+	"    144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,\n"
+	"    162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,\n"
+	"    180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,\n"
+	"    198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,\n"
+	"    216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,\n"
+	"    234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,\n"
+	"    252,253,254,255\n"
+	"};\n"
+	"#define charMap(X) UpperToLower[(unsigned char)X]\n"
+	"static int casecmp(const char *zLeft, const char *zRight, int N){\n"
+	"	register unsigned char *a, *b;\n"
+	"	a = (unsigned char *)zLeft;\n"
+	"	b = (unsigned char *)zRight;\n"
+	"	while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }\n"
+	"	return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b];\n"
+	"}\n";
+
+/*
+** All the keywords of the SQL language are stored in a hash
+** table composed of instances of the following structure.
+*/
+typedef struct Keyword Keyword;
+struct Keyword {
+	char *zName;         /* The keyword name */
+	int id;              /* Unique ID for this record */
+	int hash;            /* Hash on the keyword */
+	int offset;          /* Offset to start of name string */
+	int len;             /* Length of this keyword, not counting final \000 */
+	int prefix;          /* Number of characters in prefix */
+	int longestSuffix;   /* Longest suffix that is a prefix on another word */
+	int iNext;           /* Index in aKeywordTable[] of next with same hash */
+	int substrId;        /* Id to another keyword this keyword is embedded in */
+	int substrOffset;    /* Offset into substrId for start of this keyword */
+	char zOrigName[40];  /* Original keyword name before processing */
+};
+
+Keyword *aKeywordTable = NULL;
+int nKeyword = 0;
+
+/* An array to map all upper-case characters into their corresponding
+** lower-case character. 
+*/
+const unsigned char UpperToLower[] = {
+	0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
+	18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+	36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+	54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,
+	104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,
+	122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,
+	108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,
+	126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
+	144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
+	162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
+	180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
+	198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
+	216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
+	234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
+	252,253,254,255
+};
+
+/*
+** Comparision function for two Keyword records
+*/
+static int keywordCompare1(const void *a, const void *b){
+	const Keyword *pA = (Keyword*)a;
+	const Keyword *pB = (Keyword*)b;
+	int n = pA->len - pB->len;
+	if( n==0 ){
+		n = strcmp(pA->zName, pB->zName);
+	}
+	return n;
+}
+static int keywordCompare2(const void *a, const void *b){
+	const Keyword *pA = (Keyword*)a;
+	const Keyword *pB = (Keyword*)b;
+	int n = pB->longestSuffix - pA->longestSuffix;
+	if( n==0 ){
+		n = strcmp(pA->zName, pB->zName);
+	}
+	return n;
+}
+static int keywordCompare3(const void *a, const void *b){
+	const Keyword *pA = (Keyword*)a;
+	const Keyword *pB = (Keyword*)b;
+	int n = pA->offset - pB->offset;
+	return n;
+}
+
+/*
+** Return a KeywordTable entry with the given id
+*/
+static Keyword *findById(int id){
+	int i;
+	for(i=0; i<nKeyword; i++){
+		if( aKeywordTable[i].id==id ) break;
+	}
+	return &aKeywordTable[i];
+}
+
+static void
+parse_input (const char *filename)
+{
+#define BUFSIZE 500
+#define MAXKEYWORDS 1000
+	FILE *stream;
+        char buffer[BUFSIZE];
+        int read;
+        char *end;
+
+	stream = fopen (filename, "r");
+	if (!stream)
+		return;
+
+	printf ("\n/* Parsed keywords\n");
+
+	aKeywordTable = malloc (sizeof (Keyword) * MAXKEYWORDS);
+	memset (aKeywordTable, 0, sizeof (Keyword) * MAXKEYWORDS);
+        read = fread (buffer, 1, BUFSIZE, stream);
+        end = buffer + read;
+        while (read > 0) {
+		char *ptr;
+
+                /* read all complete lines in buffer */
+                while (end > buffer) {
+                        char *hold = NULL;
+                        for (ptr = buffer; (ptr < end) && *ptr && (*ptr != '\n'); ptr++);
+                        if (ptr == end)
+                                break;
+                        if (*ptr)
+                                hold = ptr+1;
+                        *ptr = 0;
+                        
+                        /* treat the line */
+			char *tmp1, *tmp2;
+			printf (" *\n * From line: %s\n", buffer);
+			for (tmp1 = tmp2 = buffer; *tmp2; tmp2++) {
+				if (((*tmp2 < 'A') || (*tmp2 > 'Z')) &&
+				    ((*tmp2 < 'a') || (*tmp2 > 'z')) &&
+				    ((*tmp2 < '0') || (*tmp2 > '9')) &&
+				    (*tmp2 != '_')) {
+					/* keyword found */
+					int len;
+
+					len = tmp2 - tmp1 + 1;
+					
+					aKeywordTable [nKeyword].zName = malloc (sizeof (char) * len);
+					memcpy (aKeywordTable [nKeyword].zName, tmp1, sizeof (char) * (len - 1));
+					aKeywordTable [nKeyword].zName [len - 1] = 0;
+
+					tmp1 = tmp2 + 1;
+
+					printf (" * KEYWORD: %s\n", aKeywordTable [nKeyword].zName);
+
+					nKeyword ++;
+					if (nKeyword > MAXKEYWORDS) {
+						fprintf (stderr, "Maximum number of SQL keywords exceeded, "
+							 "change the MAXKEYWORDS constant and recompile\n");
+						aKeywordTable = NULL; /* we don't care about mem leaks here */
+						return;
+					}
+				}
+			}
+			if ((tmp1 != tmp2) && *tmp1) {
+				int len;
+				len = tmp2 - tmp1 + 2;
+				aKeywordTable [nKeyword].zName = malloc (sizeof (char) * len);
+				memcpy (aKeywordTable [nKeyword].zName, tmp1, sizeof (char) * (len - 1));
+				aKeywordTable [nKeyword].zName [len - 1] = 0;
+				printf (" * KEYWORD: %s\n", aKeywordTable [nKeyword].zName);
+
+				nKeyword ++;
+				if (nKeyword > MAXKEYWORDS) {
+					fprintf (stderr, "Maximum number of SQL keywords exceeded, "
+						 "change the MAXKEYWORDS constant and recompile\n");
+					aKeywordTable = NULL; /* we don't care about mem leaks here */
+					return;
+				}
+			}
+                                
+                        if (hold) {
+                                int l = end - hold;
+                                end -= hold - buffer;
+                                memmove (buffer, hold, l);
+                        }
+                        else
+                                break;
+                }
+
+		read = fread (end, 1, BUFSIZE - (end - buffer), stream);
+                end += read;
+	}
+
+	printf (" */\n");
+
+#ifdef TEST_RESERVED_WORDS
+	int i;
+	printf ("char *keywords[] = {\n");
+	for (i = 0; i < nKeyword; i++)
+		printf ("\t\"%s\",\n", aKeywordTable [i].zName);
+	printf ("};\n");
+#endif
+
+	fclose (stream);
+}
+
+/*
+** This routine does the work.  The generated code is printed on standard
+** output.
+*/
+int
+main (int argc, char **argv)
+{
+	int i, j, k, h;
+	int bestSize, bestCount;
+	int count;
+	int nChar;
+	int totalLen = 0;
+	int aHash[5000];  /* 2000 is much bigger than nKeyword */
+	char zText[10000];
+
+	if (argc != 2) {
+		printf ("Usage: %s <file with SQL keywords>\n", argv[0]);
+		return 1;
+	}
+
+	printf("%s", zHdr);
+	parse_input (argv[1]);
+	if (!aKeywordTable) {
+		printf ("Error parsing file '%s', aborting\n", argv[1]);
+		return 1;
+	}
+
+	/* Fill in the lengths of strings and hashes for all entries. */
+	for(i=0; i<nKeyword; i++){
+		Keyword *p = &aKeywordTable[i];
+		p->len = strlen(p->zName);
+		assert( p->len<sizeof(p->zOrigName) );
+		strcpy(p->zOrigName, p->zName);
+		totalLen += p->len;
+		p->hash = (UpperToLower[(int)p->zName[0]]*4) ^
+			(UpperToLower[(int)p->zName[p->len-1]] *3) ^ p->len;
+		p->id = i+1;
+	}
+
+	/* Sort the table from shortest to longest keyword */
+	qsort(aKeywordTable, nKeyword, sizeof(aKeywordTable[0]), keywordCompare1);
+
+	/* Look for short keywords embedded in longer keywords */
+	for(i=nKeyword-2; i>=0; i--){
+		Keyword *p = &aKeywordTable[i];
+		for(j=nKeyword-1; j>i && p->substrId==0; j--){
+			Keyword *pOther = &aKeywordTable[j];
+			if( pOther->substrId ) continue;
+			if( pOther->len<=p->len ) continue;
+			for(k=0; k<=pOther->len-p->len; k++){
+				if( memcmp(p->zName, &pOther->zName[k], p->len)==0 ){
+					p->substrId = pOther->id;
+					p->substrOffset = k;
+					break;
+				}
+			}
+		}
+	}
+
+	/* Compute the longestSuffix value for every word */
+	for(i=0; i<nKeyword; i++){
+		Keyword *p = &aKeywordTable[i];
+		if( p->substrId ) continue;
+		for(j=0; j<nKeyword; j++){
+			Keyword *pOther;
+			if( j==i ) continue;
+			pOther = &aKeywordTable[j];
+			if( pOther->substrId ) continue;
+			for(k=p->longestSuffix+1; k<p->len && k<pOther->len; k++){
+				if( memcmp(&p->zName[p->len-k], pOther->zName, k)==0 ){
+					p->longestSuffix = k;
+				}
+			}
+		}
+	}
+
+	/* Sort the table into reverse order by length */
+	qsort(aKeywordTable, nKeyword, sizeof(aKeywordTable[0]), keywordCompare2);
+
+	/* Fill in the offset for all entries */
+	nChar = 0;
+	for(i=0; i<nKeyword; i++){
+		Keyword *p = &aKeywordTable[i];
+		if( p->offset>0 || p->substrId ) continue;
+		p->offset = nChar;
+		nChar += p->len;
+		for(k=p->len-1; k>=1; k--){
+			for(j=i+1; j<nKeyword; j++){
+				Keyword *pOther = &aKeywordTable[j];
+				if( pOther->offset>0 || pOther->substrId ) continue;
+				if( pOther->len<=k ) continue;
+				if( memcmp(&p->zName[p->len-k], pOther->zName, k)==0 ){
+					p = pOther;
+					p->offset = nChar - k;
+					nChar = p->offset + p->len;
+					p->zName += k;
+					p->len -= k;
+					p->prefix = k;
+					j = i;
+					k = p->len;
+				}
+			}
+		}
+	}
+	for(i=0; i<nKeyword; i++){
+		Keyword *p = &aKeywordTable[i];
+		if( p->substrId ){
+			p->offset = findById(p->substrId)->offset + p->substrOffset;
+		}
+	}
+
+	/* Sort the table by offset */
+	qsort(aKeywordTable, nKeyword, sizeof(aKeywordTable[0]), keywordCompare3);
+
+	/* Figure out how big to make the hash table in order to minimize the
+	** number of collisions */
+	bestSize = nKeyword;
+	bestCount = nKeyword*nKeyword;
+	for(i=nKeyword/2; i<=2*nKeyword; i++){
+		for(j=0; j<i; j++) aHash[j] = 0;
+		for(j=0; j<nKeyword; j++){
+			h = aKeywordTable[j].hash % i;
+			aHash[h] *= 2;
+			aHash[h]++;
+		}
+		for(j=count=0; j<i; j++) count += aHash[j];
+		if( count<bestCount ){
+			bestCount = count;
+			bestSize = i;
+		}
+	}
+
+	/* Compute the hash */
+	for(i=0; i<bestSize; i++) aHash[i] = 0;
+	for(i=0; i<nKeyword; i++){
+		h = aKeywordTable[i].hash % bestSize;
+		aKeywordTable[i].iNext = aHash[h];
+		aHash[h] = i+1;
+	}
+
+	/* Begin generating code */
+	printf("%s\n", zCode);
+	printf("/* Hash score: %d */\n", bestCount);
+	printf("static int keywordCode(const char *z, int n){\n");
+	printf("  /* zText[] encodes %d bytes of keywords in %d bytes */\n",
+	       totalLen + nKeyword, nChar+1 );
+	for(i=j=k=0; i<nKeyword; i++){
+		Keyword *p = &aKeywordTable[i];
+		if( p->substrId ) continue;
+		memcpy(&zText[k], p->zName, p->len);
+		k += p->len;
+		if( j+p->len>70 ){
+			printf("%*s */\n", 74-j, "");
+			j = 0;
+		}
+		if( j==0 ){
+			printf("  /*   ");
+			j = 8;
+		}
+		printf("%s", p->zName);
+		j += p->len;
+	}
+	if( j>0 ){
+		printf("%*s */\n", 74-j, "");
+	}
+	printf("  static const char zText[%d] = {\n", nChar);
+	zText[nChar] = 0;
+	for(i=j=0; i<k; i++){
+		if( j==0 ){
+			printf("    ");
+		}
+		if( zText[i]==0 ){
+			printf("0");
+		}else{
+			printf("'%c',", zText[i]);
+		}
+		j += 4;
+		if( j>68 ){
+			printf("\n");
+			j = 0;
+		}
+	}
+	if( j>0 ) printf("\n");
+	printf("  };\n");
+
+	printf("  static const unsigned int aHash[%d] = {\n", bestSize);
+	for(i=j=0; i<bestSize; i++){
+		if( j==0 ) printf("    ");
+		printf(" %d,", aHash[i]);
+		j++;
+		if( j>12 ){
+			printf("\n");
+			j = 0;
+		}
+	}
+	printf("%s  };\n", j==0 ? "" : "\n");    
+
+	printf("  static const unsigned int aNext[%d] = {\n", nKeyword);
+	for(i=j=0; i<nKeyword; i++){
+		if( j==0 ) printf("    ");
+		printf(" %3d,", aKeywordTable[i].iNext);
+		j++;
+		if( j>12 ){
+			printf("\n");
+			j = 0;
+		}
+	}
+	printf("%s  };\n", j==0 ? "" : "\n");    
+
+	printf("  static const unsigned char aLen[%d] = {\n", nKeyword);
+	for(i=j=0; i<nKeyword; i++){
+		if( j==0 ) printf("    ");
+		printf(" %3d,", aKeywordTable[i].len+aKeywordTable[i].prefix);
+		j++;
+		if( j>12 ){
+			printf("\n");
+			j = 0;
+		}
+	}
+	printf("%s  };\n", j==0 ? "" : "\n");    
+
+	printf("  static const unsigned short int aOffset[%d] = {\n", nKeyword);
+	for(i=j=0; i<nKeyword; i++){
+		if( j==0 ) printf("    ");
+		printf(" %3d,", aKeywordTable[i].offset);
+		j++;
+		if( j>12 ){
+			printf("\n");
+			j = 0;
+		}
+	}
+	printf("%s  };\n", j==0 ? "" : "\n");
+
+
+	printf("  int h, i;\n");
+	printf("  if( n<2 ) return 0;\n");
+	printf("  h = ((charMap(z[0])*4) ^\n"
+	       "      (charMap(z[n-1])*3) ^\n"
+	       "      n) %% %d;\n", bestSize);
+	printf("  for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){\n");
+	printf("    if( aLen[i]==n &&"
+	       " casecmp(&zText[aOffset[i]],z,n)==0 ){\n");
+	printf("      return 1;\n");
+	printf("    }\n");
+	printf("  }\n");
+	printf("  return 0;\n");
+	printf("}\n");
+	printf("\ngboolean\nis_keyword (const char *z)\n{\n");
+	printf("\treturn keywordCode(z, strlen (z));\n");
+	printf("}\n");
+
+#ifdef TEST_RESERVED_WORDS
+	printf("\nvoid\ntest_keywords (void)\n{\n");
+	printf("\tint i;\n");
+	printf("\tfor (i = 0; i < %d; i++) {\n", nKeyword);
+	printf("\t\tif (! is_keyword (keywords[i]))\n");
+	printf("\t\t\tprintf (\"KEYWORK %%s ignored!\\n\", keywords[i]);\n");
+	printf("\t}\n");
+	printf("}\n");
+#endif
+
+
+	return 0;
+}
diff --git a/providers/.gitignore b/providers/.gitignore
index 1d465da..c7ae772 100644
--- a/providers/.gitignore
+++ b/providers/.gitignore
@@ -2,4 +2,6 @@
 parser.c
 parser.h
 gen_def
-*token_types.h
\ No newline at end of file
+*token_types.h
+keywords_hash.c
+mkkeywordhash
diff --git a/providers/postgres/Makefile.am b/providers/postgres/Makefile.am
index 56ab097..51418e9 100644
--- a/providers/postgres/Makefile.am
+++ b/providers/postgres/Makefile.am
@@ -11,13 +11,19 @@ AM_CPPFLAGS = \
 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
 
+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) keywords.list
+	./mkkeywordhash$(EXEEXT_FOR_BUILD) keywords.list > keywords_hash.c
+
 gen_def$(EXEEXT_FOR_BUILD): gen_def.c
 	$(CC_FOR_BUILD) -o gen_def$(EXEEXT_FOR_BUILD) -DIMPOSED_HEADER=\""$(top_srcdir)/libgda/sql-parser/token_types.h"\" $(srcdir)/gen_def.c
 
 postgres_token_types.h: gen_def$(EXEEXT_FOR_BUILD) parser.h
 	./gen_def$(EXEEXT_FOR_BUILD) > postgres_token_types.h
 
-$(OBJECTS) $(libgda_postgres_la_OBJECTS): postgres_token_types.h
+$(OBJECTS) $(libgda_postgres_la_OBJECTS): postgres_token_types.h keywords_hash.c
 
 libgda_postgres_la_SOURCES = \
 	gda-postgres-blob-op.c \
@@ -71,7 +77,8 @@ xml_DATA = $(xml_in_files:.xml.in=.xml)
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libgda-postgres-4.0.pc
 
-EXTRA_DIST = $(xml_in_files) libgda-postgres-4.0.pc.in parser.y gen_def.c
+EXTRA_DIST = $(xml_in_files) libgda-postgres-4.0.pc.in parser.y gen_def.c keywords.list
 DISTCLEANFILES = $(xml_DATA)
 
-CLEANFILES = parser.h parser.c parser.out postgres_token_types.h gen_def$(EXEEXT_FOR_BUILD)
+CLEANFILES = parser.h parser.c parser.out postgres_token_types.h gen_def$(EXEEXT_FOR_BUILD) \
+	mkkeywordhash$(EXEEXT_FOR_BUILD) keywords_hash.c
diff --git a/providers/postgres/gda-postgres-meta.c b/providers/postgres/gda-postgres-meta.c
index 299b323..a1b7472 100644
--- a/providers/postgres/gda-postgres-meta.c
+++ b/providers/postgres/gda-postgres-meta.c
@@ -32,6 +32,7 @@
 #include <libgda/gda-connection-private.h>
 #include <libgda/gda-data-model-array.h>
 #include <libgda/gda-set.h>
+#include "keywords_hash.c" /* this one is dynamically generated */
 
 /*
  * predefined statements' IDs
@@ -275,6 +276,9 @@ _gda_postgres_provider_meta_init (GdaServerProvider *provider)
 				    "name2", G_TYPE_STRING, "");
 
 	g_static_mutex_unlock (&init_mutex);
+#ifdef GDA_DEBUG
+	test_keywords ();
+#endif
 }
 
 gboolean
@@ -288,6 +292,7 @@ _gda_postgres_meta__info (GdaServerProvider *prov, GdaConnection *cnc,
 	if (!model)
 		return FALSE;
 
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
 	g_object_unref (model);
 
@@ -337,8 +342,10 @@ _gda_postgres_meta__btypes (GdaServerProvider *prov, GdaConnection *cnc,
 	}
 
 	/* modify meta store with @proxy */
-	if (retval)
+	if (retval) {
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify (store, context->table_name, proxy, NULL, error, NULL);
+	}
 	g_object_unref (proxy);
 	g_object_unref (model);
 
@@ -356,6 +363,8 @@ _gda_postgres_meta__udt (GdaServerProvider *prov, GdaConnection *cnc,
 							 error);
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 		
@@ -377,6 +386,8 @@ _gda_postgres_meta_udt (GdaServerProvider *prov, GdaConnection *cnc,
 	model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_UDT], i_set, error);
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 
@@ -394,6 +405,8 @@ _gda_postgres_meta__udt_cols (GdaServerProvider *prov, GdaConnection *cnc,
 							 error);
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 		
@@ -417,6 +430,8 @@ _gda_postgres_meta_udt_cols (GdaServerProvider *prov, GdaConnection *cnc,
 	model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_UDT_COLUMNS], i_set, error);
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 
@@ -451,6 +466,8 @@ _gda_postgres_meta__domains (GdaServerProvider *prov, GdaConnection *cnc,
 							 error);
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 		
@@ -472,6 +489,8 @@ _gda_postgres_meta_domains (GdaServerProvider *prov, GdaConnection *cnc,
 	model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_DOMAINS], i_set, error);
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 
@@ -489,6 +508,8 @@ _gda_postgres_meta__constraints_dom (GdaServerProvider *prov, GdaConnection *cnc
 							 error);
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 		
@@ -513,6 +534,8 @@ _gda_postgres_meta_constraints_dom (GdaServerProvider *prov, GdaConnection *cnc,
 	model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_DOMAINS_CONSTRAINTS], i_set, error);
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 
@@ -541,6 +564,8 @@ _gda_postgres_meta__el_types (GdaServerProvider *prov, GdaConnection *cnc,
 							 error);
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 		
@@ -590,6 +615,8 @@ _gda_postgres_meta_el_types (GdaServerProvider *prov, GdaConnection *cnc,
 	
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 		
@@ -642,6 +669,8 @@ _gda_postgres_meta__schemata (GdaServerProvider *prov, GdaConnection *cnc,
 	model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_SCHEMAS_ALL], i_set, error);
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 	
@@ -662,6 +691,8 @@ _gda_postgres_meta_schemata (GdaServerProvider *prov, GdaConnection *cnc,
 		model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_SCHEMAS], i_set, error);
 		if (!model)
 			return FALSE;
+
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
 	}
 	else {
@@ -671,6 +702,7 @@ _gda_postgres_meta_schemata (GdaServerProvider *prov, GdaConnection *cnc,
 		if (!model)
 			return FALSE;
 		
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify (store, context->table_name, model, "schema_name = ##name::string", error, 
 						"name", schema_name_n, NULL);
 	}
@@ -710,10 +742,12 @@ _gda_postgres_meta__tables_views (GdaServerProvider *prov, GdaConnection *cnc,
 	c2 = *context; /* copy contents, just because we need to modify @context->table_name */
 	if (retval) {
 		c2.table_name = "_tables";
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify_with_context (store, &c2, tables_model, error);
 	}
 	if (retval) {
 		c2.table_name = "_views";
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify_with_context (store, &c2, views_model, error);
 	}
 	g_object_unref (tables_model);
@@ -773,10 +807,12 @@ _gda_postgres_meta_tables_views (GdaServerProvider *prov, GdaConnection *cnc,
 	c2 = *context; /* copy contents, just because we need to modify @context->table_name */
 	if (retval) {
 		c2.table_name = "_tables";
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify_with_context (store, &c2, tables_model, error);
 	}
 	if (retval) {
 		c2.table_name = "_views";
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify_with_context (store, &c2, views_model, error);
 	}
 	g_object_unref (tables_model);
@@ -867,8 +903,10 @@ gboolean _gda_postgres_meta__columns (GdaServerProvider *prov, GdaConnection *cn
 	}
 
 	/* modify meta store with @proxy */
-	if (retval)
+	if (retval) {
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify_with_context (store, context, proxy, error);
+	}
 	g_object_unref (proxy);
 	g_object_unref (model);
 
@@ -971,10 +1009,12 @@ _gda_postgres_meta_columns (GdaServerProvider *prov, GdaConnection *cnc,
 	}
 
 	/* modify meta store with @proxy */
-	if (retval)
+	if (retval) {
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify (store, context->table_name, proxy, 
 						"table_schema = ##schema::string AND table_name = ##name::string", error, 
 						"schema", table_schema, "name", table_name, NULL);
+	}
 	g_object_unref (proxy);
 	g_object_unref (model);
 
@@ -1002,6 +1042,8 @@ _gda_postgres_meta__view_cols (GdaServerProvider *prov, GdaConnection *cnc,
 	model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_VIEWS_COLUMNS_ALL], i_set, error);
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 	
@@ -1026,6 +1068,8 @@ _gda_postgres_meta_view_cols (GdaServerProvider *prov, GdaConnection *cnc,
 	model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_VIEWS_COLUMNS], i_set, error);
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 
@@ -1043,6 +1087,8 @@ _gda_postgres_meta__constraints_tab (GdaServerProvider *prov, GdaConnection *cnc
 							 error);
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 		
@@ -1070,11 +1116,13 @@ _gda_postgres_meta_constraints_tab (GdaServerProvider *prov, GdaConnection *cnc,
 								 error);
 		if (!model)
 			return FALSE;
-		if (retval)
+		if (retval) {
+			gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 			retval = gda_meta_store_modify (store, context->table_name, model, 
 							"table_schema = ##schema::string AND table_name = ##name::string", 
 							error, 
 							"schema", table_schema, "name", table_name, NULL);
+		}
 
 	}
 	else {
@@ -1084,10 +1132,12 @@ _gda_postgres_meta_constraints_tab (GdaServerProvider *prov, GdaConnection *cnc,
 								 error);
 		if (!model)
 			return FALSE;
-		if (retval)
+		if (retval) {
+			gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 			retval = gda_meta_store_modify (store, context->table_name, model, 
 							"table_schema = ##schema::string AND table_name = ##name::string AND constraint_name = ##name2::string", error, 
 							"schema", table_schema, "name", table_name, "name2", constraint_name_n, NULL);
+		}
 	}
 
 	g_object_unref (model);
@@ -1106,6 +1156,8 @@ _gda_postgres_meta__constraints_ref (GdaServerProvider *prov, GdaConnection *cnc
 							 error);
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 		
@@ -1136,11 +1188,13 @@ _gda_postgres_meta_constraints_ref (GdaServerProvider *prov, GdaConnection *cnc,
 
 
 	/* modify meta store */
-	if (retval)
+	if (retval) {
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify (store, context->table_name, model, 
 						"table_schema = ##schema::string AND table_name = ##name::string AND constraint_name = ##name2::string", 
 						error, 
 						"schema", table_schema, "name", table_name, "name2", constraint_name, NULL);
+	}
 	g_object_unref (model);
 
 	return retval;
@@ -1157,6 +1211,8 @@ _gda_postgres_meta__key_columns (GdaServerProvider *prov, GdaConnection *cnc,
 							 error);
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 		
@@ -1187,11 +1243,13 @@ _gda_postgres_meta_key_columns (GdaServerProvider *prov, GdaConnection *cnc,
 
 
 	/* modify meta store */
-	if (retval)
+	if (retval) {
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify (store, context->table_name, model, 
 						"table_schema = ##schema::string AND table_name = ##name::string AND constraint_name = ##name2::string", 
 						error, 
 						"schema", table_schema, "name", table_name, "name2", constraint_name, NULL);
+	}
 	g_object_unref (model);
 
 	return retval;	
@@ -1208,6 +1266,8 @@ _gda_postgres_meta__check_columns (GdaServerProvider *prov, GdaConnection *cnc,
 							 error);
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 		
@@ -1238,11 +1298,13 @@ _gda_postgres_meta_check_columns (GdaServerProvider *prov, GdaConnection *cnc,
 
 
 	/* modify meta store */
-	if (retval)
+	if (retval) {
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify (store, context->table_name, model, 
 						"table_schema = ##schema::string AND table_name = ##name::string AND constraint_name = ##name2::string", 
 						error, 
 						"schema", table_schema, "name", table_name, "name2", constraint_name, NULL);
+	}
 	g_object_unref (model);
 
 	return retval;	
@@ -1270,6 +1332,8 @@ _gda_postgres_meta__triggers (GdaServerProvider *prov, GdaConnection *cnc,
 							 error);
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 		
@@ -1307,6 +1371,8 @@ _gda_postgres_meta_triggers (GdaServerProvider *prov, GdaConnection *cnc,
 							 error);
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 		
@@ -1335,6 +1401,8 @@ _gda_postgres_meta__routines (GdaServerProvider *prov, GdaConnection *cnc,
 							 error);
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 		
@@ -1377,6 +1445,8 @@ _gda_postgres_meta_routines (GdaServerProvider *prov, GdaConnection *cnc,
 
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 		
@@ -1433,8 +1503,10 @@ _gda_postgres_meta__routine_col (GdaServerProvider *prov, GdaConnection *cnc,
 			break;
 	}
 
-	if (retval)
+	if (retval) {
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify_with_context (store, context, proxy, error);
+	}
 	g_object_unref (model);
 	g_object_unref (proxy);
 		
@@ -1501,8 +1573,10 @@ GdaDataModel *model, *proxy;
 			break;
 	}
 
-	if (retval)
+	if (retval) {
+		gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 		retval = gda_meta_store_modify_with_context (store, context, proxy, error);
+	}
 	g_object_unref (model);
 	g_object_unref (proxy);
 		
@@ -1531,6 +1605,8 @@ _gda_postgres_meta__routine_par (GdaServerProvider *prov, GdaConnection *cnc,
 							 error);
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 		
@@ -1568,6 +1644,8 @@ _gda_postgres_meta_routine_par (GdaServerProvider *prov, GdaConnection *cnc,
 							 error);
 	if (!model)
 		return FALSE;
+
+	gda_meta_store_set_reserved_keywords_func (store, is_keyword);
 	retval = gda_meta_store_modify_with_context (store, context, model, error);
 	g_object_unref (model);
 		
diff --git a/providers/postgres/keywords.list b/providers/postgres/keywords.list
new file mode 100644
index 0000000..1be2b38
--- /dev/null
+++ b/providers/postgres/keywords.list
@@ -0,0 +1,101 @@
+ALL
+ANALYSE
+ANALYZE
+AND
+ANY
+ARRAY
+AS
+ASC
+ASYMMETRIC
+AUTHORIZATION
+BETWEEN
+BINARY
+BOTH
+CASE
+CAST
+CHECK
+COLLATE
+COLUMN
+CONSTRAINT
+CREATE
+CROSS
+CURRENT_CATALOG
+CURRENT_DATE
+CURRENT_ROLE
+CURRENT_SCHEMA
+CURRENT_TIME
+CURRENT_TIMESTAMP
+CURRENT_USER
+DEFAULT
+DEFERRABLE
+DESC
+DISTINCT
+DO
+ELSE
+END
+EXCEPT
+FALSE
+FETCH
+FOLLOWING
+FOR
+FOREIGN
+FREEZE
+FROM
+FULL
+GRANT
+GROUP
+HAVING
+ILIKE
+IN
+INITIALLY
+INNER
+INTERSECT
+INTO
+IS
+ISNULL
+JOIN
+LEADING
+LEFT
+LIKE
+LIMIT
+LOCALTIME
+LOCALTIMESTAMP
+NATURAL
+NEW
+NOT
+NOTNULL
+NULL
+OFF
+OFFSET
+OLD
+ON
+ONLY
+OR
+ORDER
+OUTER
+OVERLAPS
+PLACING
+PRIMARY
+PRIOR
+REFERENCES
+RETURNING
+RIGHT
+SELECT
+SESSION_USER
+SIMILAR
+SOME
+SYMMETRIC
+TABLE
+THEN
+TO
+TRAILING
+TRUE
+UNION
+UNIQUE
+USER
+USING
+VARIADIC
+VERBOSE
+WHEN
+WHERE
+WITH



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