[libgda] Added support for SQL reserved keywords



commit 666923a5d84fcdb64d0f2779ef7011f9e7c4e809
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.

 doc/C/libgda-4.0-sections.txt                      |    2 +
 doc/C/prov-writing.xml                             |   24 +-
 doc/C/tmpl/provider-support.sgml                   |   18 +
 libgda/gda-data-meta-wrapper.c                     |   48 ++-
 libgda/gda-data-meta-wrapper.h                     |    3 +-
 libgda/gda-decl.h                                  |    5 +
 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 ++++
 providers/skel-implementation/capi/Makefile.am     |   14 +-
 providers/skel-implementation/capi/gda-capi-meta.c |   10 +
 providers/skel-implementation/capi/keywords.list   |   82 ++++
 21 files changed, 1110 insertions(+), 51 deletions(-)
---
diff --git a/doc/C/libgda-4.0-sections.txt b/doc/C/libgda-4.0-sections.txt
index 95f70ef..5277fbf 100644
--- a/doc/C/libgda-4.0-sections.txt
+++ b/doc/C/libgda-4.0-sections.txt
@@ -1459,6 +1459,8 @@ gda_meta_store_modify
 gda_meta_store_modify_with_context
 GdaSqlIdentifierStyle
 gda_meta_store_set_identifiers_style
+GdaSqlReservedKeywordsFunc
+gda_meta_store_set_reserved_keywords_func
 <SUBSECTION>
 gda_compute_dml_statements
 gda_compute_select_statement_from_update
diff --git a/doc/C/prov-writing.xml b/doc/C/prov-writing.xml
index 1bd301d..ff1cca5 100644
--- a/doc/C/prov-writing.xml
+++ b/doc/C/prov-writing.xml
@@ -408,11 +408,33 @@ gboolean (*tables_views) (GdaServerProvider *, GdaConnection *, GdaMetaStore *,
 	  </para></listitem>
 	  <listitem><para>for case sensitive SQL identifiers: without the double quotes, but possibily with
 	      mixed or not lower and upper characters</para></listitem>
-	  <listitem><para></para></listitem>
 	</itemizedlist>
       </para>
     </sect2>
     <sect2>
+      <title>Reserved SQL keywords</title>
+      <para>
+	Every database engine reserves some keywords for its own usage or because they are part of the SQL
+	language. Reserved keywords can be used as SQL identifiers if they are put between double quotes.
+      </para>
+      <para>
+	As Each database engine has its own set of reserved keywords, the database provider has to tell the
+	<link linkend="GdaMetaStore">GdaMetaStore</link> object what its keywords are, which is done using
+	<link linkend="gda-meta-store-set-reserved-keywords-func">gda_meta_store_set_reserved_keywords_func()</link>
+	and passing a function which determines if a specific string is a reserved keyword. The usage of
+	this function is similar to the usage of the
+	<link linkend="gda-meta-store-set-identifiers-style">gda_meta_store_set_identifiers_style()</link>
+	mentionned above.
+      </para>
+      <para>
+	Writing a function which tests if a string is a reserved keyword is a non complicated but error
+	prone and not optimized, in the same way as writing a parser/lexer directly, so &LIBGDA; has a tool
+	which generates a static hash table from a list of reserved keywords, which is in the
+	<filename>keywords.list</filename> (several keywords can appear on the same line, separated by spaces or commas
+	but the last line must remain empty).
+      </para>
+    </sect2>
+    <sect2>
       <title>_info()</title>
       <para>
 	<programlisting>
diff --git a/doc/C/tmpl/provider-support.sgml b/doc/C/tmpl/provider-support.sgml
index 260654d..67efd17 100644
--- a/doc/C/tmpl/provider-support.sgml
+++ b/doc/C/tmpl/provider-support.sgml
@@ -366,6 +366,24 @@ Methods dedicated to implementing providers
 @style: 
 
 
+<!-- ##### USER_FUNCTION GdaSqlReservedKeywordsFunc ##### -->
+<para>
+
+</para>
+
+ word: 
+ Returns: 
+
+
+<!-- ##### FUNCTION gda_meta_store_set_reserved_keywords_func ##### -->
+<para>
+
+</para>
+
+ store: 
+ func: 
+
+
 <!-- ##### FUNCTION gda_compute_dml_statements ##### -->
 <para>
 
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 0db3879..e7affca 100644
--- a/libgda/gda-decl.h
+++ b/libgda/gda-decl.h
@@ -109,6 +109,11 @@ typedef struct _GdaMetaStructClass   GdaMetaStructClass;
 typedef struct _GdaMetaStructPrivate GdaMetaStructPrivate;
 
 /*
+ * Determines if @word is a reserved SQL keyword
+ */
+typedef gboolean (*GdaSqlReservedKeywordsFunc) (const gchar *word);
+
+/*
  * GdaTree
  */
 typedef struct _GdaTree GdaTree;
diff --git a/libgda/gda-meta-store.c b/libgda/gda-meta-store.c
index 2d7c286..8ba93aa 100644
--- a/libgda/gda-meta-store.c
+++ b/libgda/gda-meta-store.c
@@ -210,6 +210,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;
 
@@ -495,6 +497,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;
 
@@ -804,6 +807,25 @@ gda_meta_store_set_identifiers_style (GdaMetaStore *store, GdaSqlIdentifierStyle
 	store->priv->ident_style = style;
 }
 
+/**
+ * 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.2
+ */
+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
  */
@@ -2348,7 +2370,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 2f1f520..c575ef2 100644
--- a/libgda/gda-meta-store.h
+++ b/libgda/gda-meta-store.h
@@ -114,7 +114,9 @@ gboolean          gda_meta_store_modify                   (GdaMetaStore *store,
 gboolean          gda_meta_store_modify_with_context      (GdaMetaStore *store, GdaMetaContext *context, 
 							   GdaDataModel *new_data, GError **error);
 GdaDataModel     *gda_meta_store_create_modify_data_model (GdaMetaStore *store, const gchar *table_name);
+
 void              gda_meta_store_set_identifiers_style    (GdaMetaStore *store, GdaSqlIdentifierStyle style);
+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);
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 d72771a..be1267d 100644
--- a/providers/postgres/gda-postgres-meta.c
+++ b/providers/postgres/gda-postgres-meta.c
@@ -33,6 +33,7 @@
 #include <libgda/gda-data-model-array.h>
 #include <libgda/gda-set.h>
 #include <libgda/providers-support/gda-meta-column-types.h>
+#include "keywords_hash.c" /* this one is dynamically generated */
 
 /*
  * predefined statements' IDs
@@ -276,6 +277,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
@@ -289,6 +293,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);
 
@@ -338,8 +343,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);
 
@@ -357,6 +364,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);
 		
@@ -378,6 +387,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);
 
@@ -399,6 +410,8 @@ _gda_postgres_meta__udt_cols (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);
 		
@@ -426,6 +439,8 @@ _gda_postgres_meta_udt_cols (GdaServerProvider *prov, GdaConnection *cnc,
 							      _col_types_udt_columns, 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);
 
@@ -460,6 +475,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);
 		
@@ -481,6 +498,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);
 
@@ -498,6 +517,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);
 		
@@ -522,6 +543,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);
 
@@ -550,6 +573,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);
 		
@@ -599,6 +624,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);
 		
@@ -651,6 +678,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);
 	
@@ -671,6 +700,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 {
@@ -680,6 +711,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);
 	}
@@ -719,10 +751,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);
@@ -782,10 +816,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);
@@ -874,8 +910,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);
 
@@ -977,10 +1015,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);
 
@@ -1008,6 +1048,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);
 	
@@ -1032,6 +1074,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);
 
@@ -1049,6 +1093,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);
 		
@@ -1076,11 +1122,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 {
@@ -1090,10 +1138,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);
@@ -1112,6 +1162,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);
 		
@@ -1142,11 +1194,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;
@@ -1163,6 +1217,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);
 		
@@ -1193,11 +1249,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;	
@@ -1214,6 +1272,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);
 		
@@ -1244,11 +1304,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;	
@@ -1276,6 +1338,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);
 		
@@ -1313,6 +1377,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);
 		
@@ -1341,6 +1407,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);
 		
@@ -1383,6 +1451,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);
 		
@@ -1439,8 +1509,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);
 		
@@ -1507,8 +1579,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);
 		
@@ -1537,6 +1611,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);
 		
@@ -1574,6 +1650,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
diff --git a/providers/skel-implementation/capi/Makefile.am b/providers/skel-implementation/capi/Makefile.am
index ac3e543..60aaea1 100644
--- a/providers/skel-implementation/capi/Makefile.am
+++ b/providers/skel-implementation/capi/Makefile.am
@@ -11,6 +11,13 @@ AM_CPPFLAGS = \
 	-I$(top_builddir) \
 	$(LIBGDA_CFLAGS) #$(CAPI_CFLAGS) 
 
+# SQL keywords HASH generation
+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
+
 # 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 +28,7 @@ gen_def$(EXEEXT_FOR_BUILD): gen_def.c
 capi_token_types.h: gen_def$(EXEEXT_FOR_BUILD) parser.h
 	./gen_def$(EXEEXT_FOR_BUILD) > capi_token_types.h
 
-$(OBJECTS) $(libgda_capi_la_OBJECTS): capi_token_types.h
+$(OBJECTS) $(libgda_capi_la_OBJECTS): capi_token_types.h keywords_hash.c
 
 libgda_capi_la_SOURCES = \
 	gda-capi-blob-op.c \
@@ -63,7 +70,8 @@ pkgconfigdir = $(libdir)/pkgconfig
 #pkgconfig_DATA = libgda-capi-4.0.pc
 noinst_DATA += libgda-capi-4.0.pc
 
-EXTRA_DIST = $(xml_in_files) libgda-capi-4.0.pc.in parser.y gen_def.c
+EXTRA_DIST = $(xml_in_files) libgda-capi-4.0.pc.in parser.y gen_def.c keywords.list
 DISTCLEANFILES = $(noinst_DATA)
 
-CLEANFILES = parser.h parser.c parser.out capi_token_types.h gen_def$(EXEEXT_FOR_BUILD)
+CLEANFILES = parser.h parser.c parser.out capi_token_types.h gen_def$(EXEEXT_FOR_BUILD) \
+	mkkeywordhash$(EXEEXT_FOR_BUILD) keywords_hash.c
diff --git a/providers/skel-implementation/capi/gda-capi-meta.c b/providers/skel-implementation/capi/gda-capi-meta.c
index ebecca3..9e91e41 100644
--- a/providers/skel-implementation/capi/gda-capi-meta.c
+++ b/providers/skel-implementation/capi/gda-capi-meta.c
@@ -32,6 +32,7 @@
 #include <libgda/gda-data-model-array.h>
 #include <libgda/gda-set.h>
 #include <libgda/gda-holder.h>
+#include "keywords_hash.c" /* this one is dynamically generated */
 
 /*
  * predefined statements' IDs
@@ -84,6 +85,11 @@ _gda_capi_provider_meta_init (GdaServerProvider *provider)
 				    "name2", G_TYPE_STRING, "");
 
 	g_static_mutex_unlock (&init_mutex);
+
+#ifdef GDA_DEBUG
+	/* make sure the reserved keywords hash works correctly */
+        test_keywords ();
+#endif
 }
 
 gboolean
@@ -100,6 +106,8 @@ _gda_capi_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_with_context (store, context, model, error);
 	g_object_unref (model);
 		
@@ -142,6 +150,8 @@ _gda_capi_meta_udt (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);
 
diff --git a/providers/skel-implementation/capi/keywords.list b/providers/skel-implementation/capi/keywords.list
new file mode 100644
index 0000000..7fa6da1
--- /dev/null
+++ b/providers/skel-implementation/capi/keywords.list
@@ -0,0 +1,82 @@
+ALL
+ANALYSE
+ANALYZE
+AND
+ANY
+ARRAY
+AS
+ASC
+ASYMMETRIC
+BETWEEN
+BINARY
+BOTH
+CASE
+CAST
+CHECK
+COLLATE
+COLUMN
+CONSTRAINT
+CREATE
+CROSS
+DEFAULT
+DEFERRABLE
+DESC
+DISTINCT
+DO
+ELSE
+END
+EXCEPT
+FALSE
+FETCH
+FOLLOWING
+FOR
+FOREIGN
+FREEZE
+FROM
+FULL
+GRANT
+GROUP
+HAVING
+IN
+INITIALLY
+INNER
+INTERSECT
+INTO
+IS
+JOIN
+LEADING
+LEFT
+LIKE
+LIMIT
+NATURAL
+NEW
+NOT
+NULL
+OFF
+OFFSET
+OLD
+ON
+ONLY
+OR
+ORDER
+OUTER
+OVERLAPS
+PRIMARY
+PRIOR
+REFERENCES
+RETURNING
+RIGHT
+SELECT
+SIMILAR
+SOME
+TABLE
+THEN
+TO
+TRUE
+UNION
+UNIQUE
+USER
+USING
+WHEN
+WHERE
+WITH



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