libgda r3085 - in trunk: . doc/C doc/C/tmpl libgda libgda/sqlite po providers/postgres tests/providers tools
- From: vivien svn gnome org
- To: svn-commits-list gnome org
- Subject: libgda r3085 - in trunk: . doc/C doc/C/tmpl libgda libgda/sqlite po providers/postgres tests/providers tools
- Date: Mon, 17 Mar 2008 19:34:20 +0000 (GMT)
Author: vivien
Date: Mon Mar 17 19:34:20 2008
New Revision: 3085
URL: http://svn.gnome.org/viewvc/libgda?rev=3085&view=rev
Log:
2008-03-17 Vivien Malerba <malerba gnome-db org>
* libgda/gda-statement.h: correctly define gda_statement_to_sql(), thanks
to Carlos Savoretti
* po/POTFILES.skip: remove mention of temporary files
* libgda/gda-data-model.c: fixed documentation for bug #522365
* doc/C: dosumentation improvements
* libgda/gda-meta-store.[ch]:
* libgda/gda-connection.c: make the partial metadata sync with the database work, and
added the possibility for applications to add their own database objects in a GdaMetaStore
* libgda/gda-server-provider.c: fix a memory leak in the server operations handling (reported by
Phil Longstaff)
* libgda/information_schema.xml: more descriptions of the tables and columns
* libgda/sqlite/gda-sqlite-provider.c: make the "internal_stmt" array static to avoid collisions
* libgda/gda-server-provider.h:
* libgda/gda-connection.c:
* providers/postgres/gda-postgres-provider.c:
* providers/postgres/gda-postgres-meta.[ch]:
* libgda/sqlite/gda-sqlite-provider.c:
* libgda/sqlite/gda-sqlite-meta.[ch]: more meta data retreival implemented (constraints' columns)
* tests/providers/prov-test-common.c: follow API changes
* tools/command-exec.c: added a description of the table's constraints
Added:
trunk/doc/C/MetaStore1.dia (contents, props changed)
trunk/doc/C/MetaStore1.png (contents, props changed)
trunk/doc/C/MetaStore2.dia (contents, props changed)
trunk/doc/C/MetaStore2.png (contents, props changed)
Modified:
trunk/ChangeLog
trunk/doc/C/Makefile.am
trunk/doc/C/libgda-4.0-docs.sgml
trunk/doc/C/migration2.xml
trunk/doc/C/tmpl/gda-meta-store.sgml
trunk/doc/C/tmpl/gda-server-provider.sgml
trunk/libgda/gda-connection.c
trunk/libgda/gda-data-model.c
trunk/libgda/gda-meta-store.c
trunk/libgda/gda-meta-store.h
trunk/libgda/gda-server-provider.c
trunk/libgda/gda-server-provider.h
trunk/libgda/gda-statement.h
trunk/libgda/gda-util.c
trunk/libgda/information_schema.xml
trunk/libgda/sqlite/gda-sqlite-meta.c
trunk/libgda/sqlite/gda-sqlite-meta.h
trunk/libgda/sqlite/gda-sqlite-provider.c
trunk/po/POTFILES.skip
trunk/providers/postgres/gda-postgres-meta.c
trunk/providers/postgres/gda-postgres-meta.h
trunk/providers/postgres/gda-postgres-provider.c
trunk/tests/providers/prov-test-common.c
trunk/tools/command-exec.c
Modified: trunk/doc/C/Makefile.am
==============================================================================
--- trunk/doc/C/Makefile.am (original)
+++ trunk/doc/C/Makefile.am Mon Mar 17 19:34:20 2008
@@ -34,6 +34,7 @@
-I$(top_srcdir)/libgda \
$(LIBGDA_CFLAGS) \
-DGETTEXT_PACKAGE=\""$(GETTEXT_PACKAGE)"\"
+
GTKDOC_LIBS = $(top_builddir)/libgda/libgda-4.0.la \
$(top_builddir)/libgda-report/libgda-report-4.0.la \
$(LIBGDA_LIBS)
@@ -47,7 +48,8 @@
# Images to copy into HTML directory
HTML_IMAGES = DataModels.png \
architecture.png parts.png stmt-unknown.png stmt-select.png stmt-insert1.png stmt-insert2.png \
- stmt-update.png stmt-compound.png information_schema.png
+ stmt-update.png stmt-compound.png information_schema.png \
+ MetaStore1.png MetaStore2.png
# Extra options to supply to gtkdoc-fixref
FIXXREF_OPTIONS=
Added: trunk/doc/C/MetaStore1.dia
==============================================================================
Binary file. No diff available.
Added: trunk/doc/C/MetaStore1.png
==============================================================================
Binary file. No diff available.
Added: trunk/doc/C/MetaStore2.dia
==============================================================================
Binary file. No diff available.
Added: trunk/doc/C/MetaStore2.png
==============================================================================
Binary file. No diff available.
Modified: trunk/doc/C/libgda-4.0-docs.sgml
==============================================================================
--- trunk/doc/C/libgda-4.0-docs.sgml (original)
+++ trunk/doc/C/libgda-4.0-docs.sgml Mon Mar 17 19:34:20 2008
@@ -302,7 +302,8 @@
<listitem>
<para>Create, maintain and extend a view of the database's structure and meta data including the definitions of
the tables, constraints, data types, .... It is defined as closely as possible to the information schema SQL
- standard (ISO/IEC 9075).</para>
+ standard (ISO/IEC 9075); see the <link linkend="gda-dict">Dictionary - metadata</link> section
+ for more information.</para>
</listitem>
<listitem>
<para>Easy to extend data models for custom requirements</para>
@@ -627,26 +628,159 @@
&libgda-GdaHandlerType;
</chapter>
- <chapter>
+ <chapter id="gda-dict">
<title>Dictionary - metadata</title>
<para>
Each connection has a dictionary object (a <link linkend="GdaMetaStore">GdaMetaStore</link>) attached to it. That
- dictionary is either created by the connection when it needs it, or is set by the user (to be able to re-use
- a dictionary), using the <link linkend="GdaConnection--meta-store">"meta-store"</link> property of the
- <link linkend="GdaConnection">GdaConnection</link> object.
+ dictionary is either created by the connection when it needs it, or is created and set by the user
+ (to be able to re-use a dictionary), using the <link linkend="GdaConnection--meta-store">"meta-store"</link>
+ property of the <link linkend="GdaConnection">GdaConnection</link> object.
+ </para>
+ <para>
+ Previous versions of &LIBGDA; used an XML file based dictionary which had several drawbacks (see the
+ <link linkend="migration-2-dict">migrations notes</link> for more details), now a database is used: the default
+ is to use an SQLite base database which is easily transportable and can be used in the same way the previous
+ XML based dictionary was used.
</para>
<para>
- &LIBGDA; requires (and creates) a default dictionary structure which is a set of tables implementing an
- "information schema" schema (as defined in the SQL standard and adapted to add more information). The user
- is then free to add more tables to contain his own data in the dictionary.
+ Each <link linkend="GdaMetaStore">GdaMetaStore</link> requires (and creates) a dictionary
+ structure which is a set of tables implementing an
+ "information schema" schema (as defined in the information schema SQL standard (ISO/IEC 9075), and adapted).
+ The user is then free to add more database objects (tables and views) to contain his own data in the dictionary,
+ using the <link linkend="gda-meta-store-schema-add-custom-object">gda_meta_store_schema_add_custom_object()</link>
+ method.
</para>
<para>
- Extracting information about database objects can easily be done using a
- <link linkend="GdaMetaStruct">GdaMetaStruct</link> object which creates an easy to use in-memory representation
- of some database objects.
+ Extracting information can be done using SQL statements on the dictionary database (a special
+ <link linkend="gda_meta_store_extract">gda_meta_store_extract()</link> method), or, for information about
+ the database structure, using the <link linkend="GdaMetaStruct">GdaMetaStruct</link> object which creates
+ an easy to use in-memory representation of some database objects.
</para>
+
&libgda-GdaMetaStore;
&libgda-GdaMetaStruct;
+
+ <sect2 id="GdaMetaStoreSetup">
+ <title>GdaConnection and GdaMetaStore setups</title>
+ <para>
+ Each <link linkend="GdaMetaStore">GdaMetaStore</link> object internally uses a (private)
+ <link linkend="GdaConnection">GdaConnection</link> connection object. The following figure illustrates
+ the situation when the programmer uses a <link linkend="GdaConnection">GdaConnection</link> connection object
+ when the meta data is stored in a different database (usually an SQLite file):
+ <mediaobject>
+ <imageobject role="html">
+ <imagedata fileref="MetaStore1.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase></phrase>
+ </textobject>
+ <caption>
+ <para>
+ GdaConnection object and its associated GdaMetaStore using its own database to store the
+ meta data.
+ </para>
+ </caption>
+ </mediaobject>
+ </para>
+ <para>
+ From a programmer's point of view, the following code example shows how to get a connection's associated
+ meta store object, without being able to specify anything about the meta store's private connection (in which
+ case the private connection will be an in-memory database destroyed when the meta store object is destroyed):
+ <programlisting>
+GdaConnection *cnc;
+GdaMetaStore *store;
+
+cnc = gda_connection_open_from_dsn (...);
+g_object_get (G_OBJECT (cnc), "meta-store", &store, NULL);
+
+[... use the meta store object ...]
+g_object_unref (store);
+ </programlisting>
+ </para>
+ <para>
+ One can also specify the meta store object to be used by a connection, as in:
+ <programlisting>
+GdaConnection *cnc;
+GdaMetaStore *store;
+
+cnc = gda_connection_open_from_dsn (...);
+store = gda_meta_store_new_with_file ("/path/to/file");
+/* or */
+store = gda_meta_store_new ("PostgreSQL://DB_NAME=meta_db");
+
+g_object_set (G_OBJECT (cnc), "meta-store", store, NULL);
+g_object_unref (store);
+ </programlisting>
+ </para>
+
+ <para>
+ The meta data can also be stored in the same database as the connection the meta data is for. In this case
+ (and if the associated database provider supports it), the dictionary structure can be placed into a spearate
+ schema. The next figure illustrates this situation:
+ <mediaobject>
+ <imageobject role="html">
+ <imagedata fileref="MetaStore2.png" format="PNG"/>
+ </imageobject>
+ <textobject>
+ <phrase></phrase>
+ </textobject>
+ <caption>
+ <para>
+ GdaConnection object and its associated GdaMetaStore using the same database.
+ </para>
+ </caption>
+ </mediaobject>
+ </para>
+ <para>
+ From a programmer's point of view, the following code example shows how to do the setup:
+ <programlisting>
+GdaConnection *cnc;
+GdaMetaStore *store;
+
+cnc = gda_connection_open_from_dsn (...);
+store = GDA_META_STORE (GDA_TYPE_META_STORE, "cnc", cnc, NULL);
+g_object_set (G_OBJECT (cnc), "meta-store", store, NULL);
+g_object_unref (store);
+ </programlisting>
+ </para>
+ </sect2>
+
+ <sect2 id="GdaMetaStoreCustomData">
+ <title>How to store custom data in a GdaMetaStore</title>
+ <para>
+ This section explains how to add application specific data to a #GdaMetaStore object.
+ </para>
+ <para>
+ Applications of course don't need to use that feature to manage their own data but it makes sense to use
+ it if the application also uses metadata to avoid having to manipulate several files for the same "task".
+ </para>
+ <sect3>
+ <title>Storing data as (key, value) pairs</title>
+ <para>
+ In very simple cases, when the data to store is made of named values, the easiest way is to use the
+ <link linkend="gda-meta-store-set-attribute-value">gda_meta_store_set_attribute_value()</link> and
+ <link linkend="gda-meta-store-get-attribute-value">gda_meta_store_get_attribute_value()</link> methods
+ where the values are stored and retreived as strings.
+ </para>
+ </sect3>
+ <sect3>
+ <title>Declaring the new custom database objects</title>
+ <para>
+ </para>
+ </sect3>
+ <sect3>
+ <title>Adding and removing data</title>
+ <para>
+ </para>
+ </sect3>
+ <sect3>
+ <title>Removing custom database objects</title>
+ <para>
+ </para>
+ </sect3>
+ <para>
+ </para>
+ </sect2>
</chapter>
<chapter>
Modified: trunk/doc/C/migration2.xml
==============================================================================
--- trunk/doc/C/migration2.xml (original)
+++ trunk/doc/C/migration2.xml Mon Mar 17 19:34:20 2008
@@ -49,7 +49,7 @@
See this object's documentation for more information.</para>
</sect1>
- <sect1><title>Dictionary changes</title>
+ <sect1 id="migration-2-dict"><title>Dictionary changes</title>
<para>The GdaDict object has been removed and the <link linkend="GdaMetaStore">GdaMetaStore</link> object introduced to
replace it, but with slightly different features.</para>
<para>The GdaDict object used an XML file to store its data which imposed parsing potentially big XML files and creating its own
Modified: trunk/doc/C/tmpl/gda-meta-store.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-meta-store.sgml (original)
+++ trunk/doc/C/tmpl/gda-meta-store.sgml Mon Mar 17 19:34:20 2008
@@ -68,6 +68,11 @@
@arg1:
@Returns:
+<!-- ##### ARG GdaMetaStore:catalog ##### -->
+<para>
+
+</para>
+
<!-- ##### ARG GdaMetaStore:cnc ##### -->
<para>
@@ -78,6 +83,11 @@
</para>
+<!-- ##### ARG GdaMetaStore:schema ##### -->
+<para>
+
+</para>
+
<!-- ##### ENUM GdaMetaStoreError ##### -->
<para>
@@ -86,10 +96,12 @@
@GDA_META_STORE_INCORRECT_SCHEMA:
@GDA_META_STORE_UNSUPPORTED_PROVIDER:
@GDA_META_STORE_INTERNAL_ERROR:
+ GDA_META_STORE_META_CONTEXT_ERROR:
@GDA_META_STORE_MODIFY_CONTENTS_ERROR:
@GDA_META_STORE_EXTRACT_SQL_ERROR:
@GDA_META_STORE_ATTRIBUTE_NOT_FOUND_ERROR:
@GDA_META_STORE_ATTRIBUTE_ERROR:
+ GDA_META_STORE_SCHEMA_OBJECT_NOT_FOUND_ERROR:
@GDA_META_STORE_SCHEMA_OBJECT_CONFLICT_ERROR:
@GDA_META_STORE_SCHEMA_OBJECT_DESCR_ERROR:
Modified: trunk/doc/C/tmpl/gda-server-provider.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-server-provider.sgml (original)
+++ trunk/doc/C/tmpl/gda-server-provider.sgml Mon Mar 17 19:34:20 2008
@@ -103,6 +103,8 @@
@constraints_tab:
@_constraints_ref:
@constraints_ref:
+ _key_columns:
+ key_columns:
<!-- ##### USER_FUNCTION GdaServerProviderAsyncCallback ##### -->
<para>
Modified: trunk/libgda/gda-connection.c
==============================================================================
--- trunk/libgda/gda-connection.c (original)
+++ trunk/libgda/gda-connection.c Mon Mar 17 19:34:20 2008
@@ -1676,6 +1676,65 @@
return gda_server_provider_supports_feature (cnc->priv->provider_obj, cnc, feature);
}
+/* builds a list of #GdaMetaContext contexts templates: contexts which have a non NULL table_name,
+ * and empty or partially filled column names and values specifications */
+GSList *
+build_upstream_context_templates (GdaMetaStore *store, GdaMetaContext *context, GSList *elist, GError **error)
+{
+ GSList *depend_on_contexts;
+ GSList *retlist;
+ GError *lerror = NULL;
+ depend_on_contexts = _gda_meta_store_schema_get_upstream_contexts (store, context, &lerror);
+ if (!depend_on_contexts) {
+ if (lerror) {
+ /* error while getting dependencies */
+ g_propagate_error (error, lerror);
+ return FALSE;
+ }
+ return elist;
+ }
+ else {
+ GSList *list;
+ retlist = NULL;
+ for (list = depend_on_contexts; list; list = list->next)
+ retlist = build_upstream_context_templates (store, (GdaMetaContext *) list->data,
+ retlist, error);
+ list = g_slist_concat (depend_on_contexts, elist);
+ retlist = g_slist_concat (retlist, list);
+ return retlist;
+ }
+}
+
+
+/* builds a list of #GdaMetaContext contexts templates: contexts which have a non NULL table_name,
+ * and empty or partially filled column names and values specifications */
+GSList *
+build_downstream_context_templates (GdaMetaStore *store, GdaMetaContext *context, GSList *elist, GError **error)
+{
+ GSList *depending_contexts;
+ GSList *retlist;
+ GError *lerror = NULL;
+ depending_contexts = _gda_meta_store_schema_get_downstream_contexts (store, context, &lerror);
+ if (!depending_contexts) {
+ if (lerror) {
+ /* error while getting dependencies */
+ g_propagate_error (error, lerror);
+ return NULL;
+ }
+ return elist;
+ }
+ else {
+ GSList *list;
+ retlist = NULL;
+ for (list = depending_contexts; list; list = list->next)
+ retlist = build_downstream_context_templates (store, (GdaMetaContext *) list->data,
+ retlist, error);
+ list = g_slist_concat (elist, depending_contexts);
+ retlist = g_slist_concat (list, retlist);
+ return retlist;
+ }
+}
+
/*
*
*/
@@ -1742,12 +1801,29 @@
}
else
g_set_error (error, 0, 0,
- _("Missing and/or wrong arguments"));
+ _("Missing or wrong arguments"));
/*g_print ("Check arguments context => found %d\n", retval);*/
return retval;
}
+static void
+meta_context_dump (GdaMetaContext *context)
+{
+ gint i;
+ g_print ("GdaMetaContext for table %s:", context->table_name);
+ for (i = 0; i < context->size; i++) {
+ gchar *str;
+ str = gda_value_stringify (context->column_values[i]);
+ g_print (" [%s => %s]", context->column_names[i], str);
+ g_free (str);
+ }
+ if (i == 0)
+ g_print (" ---\n");
+ else
+ g_print ("\n");
+}
+
static gboolean
local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaContext *context, GError **error)
{
@@ -1764,6 +1840,11 @@
GdaMetaStore *store;
gboolean retval;
+#ifdef GDA_DEBUG_NO
+ g_print ("%s() => ", __FUNCTION__);
+ meta_context_dump (context);
+#endif
+
if (*tname != '_')
return TRUE;
tname ++;
@@ -1783,18 +1864,7 @@
WARN_META_UPDATE_FAILURE (retval, "_btypes");
return retval;
}
- case 'i':
- /* _information_schema_catalog_name, params:
- * - none
- */
- ASSERT_TABLE_NAME (tname, "information_schema_catalog_name");
- if (!PROV_CLASS (provider)->meta_funcs._info) {
- WARN_METHOD_NOT_IMPLEMENTED (provider, "_info");
- break;
- }
- retval = PROV_CLASS (provider)->meta_funcs._info (provider, cnc, store, context, error);
- WARN_META_UPDATE_FAILURE (retval, "_info");
- return retval;
+
case 'c':
if ((tname[1] == 'o') && (tname[2] == 'l') && (tname[3] == 'u')) {
/* _columns, params:
@@ -1834,6 +1904,56 @@
}
break;
+ case 'i':
+ /* _information_schema_catalog_name, params:
+ * - none
+ */
+ ASSERT_TABLE_NAME (tname, "information_schema_catalog_name");
+ if (!PROV_CLASS (provider)->meta_funcs._info) {
+ WARN_METHOD_NOT_IMPLEMENTED (provider, "_info");
+ break;
+ }
+ retval = PROV_CLASS (provider)->meta_funcs._info (provider, cnc, store, context, error);
+ WARN_META_UPDATE_FAILURE (retval, "_info");
+ return retval;
+
+ case 'k': {
+ /* _key_column_usage, params:
+ * -0- @table_catalog, @table_schema, @table_name, @constraint_name
+ * -0- @ref_table_catalog, @ref_table_schema, @ref_table_name, @ref_constraint_name
+ */
+ const GValue *catalog = NULL;
+ const GValue *schema = NULL;
+ const GValue *tabname = NULL;
+ const GValue *cname = NULL;
+ gint i;
+ i = check_parameters (context, error, 2,
+ &catalog, G_TYPE_STRING,
+ &schema, G_TYPE_STRING,
+ &tabname, G_TYPE_STRING,
+ &cname, G_TYPE_STRING, NULL,
+ "table_catalog", &catalog, "table_schema", &schema, "table_name", &tabname, "constraint_name", &cname, NULL,
+ "table_catalog", &catalog, "table_schema", &schema, "table_name", &tabname, "column_name", &cname, NULL);
+ if (i < 0)
+ return FALSE;
+
+ ASSERT_TABLE_NAME (tname, "key_column_usage");
+ if (i == 0) {
+ if (!PROV_CLASS (provider)->meta_funcs.key_columns) {
+ WARN_METHOD_NOT_IMPLEMENTED (provider, "key_columns");
+ break;
+ }
+ retval = PROV_CLASS (provider)->meta_funcs.key_columns (provider, cnc, store, context, error,
+ catalog, schema, tabname, cname);
+ WARN_META_UPDATE_FAILURE (retval, "key_columns");
+ return retval;
+ }
+ else {
+ /* nothing to do */
+ return TRUE;
+ }
+ }
+
case 'r':
if ((tname[1] == 'e') && (tname[2] == 'f')) {
/* _referential_constraints, params:
@@ -1971,14 +2091,90 @@
GdaConnection *cnc;
GError **error;
gboolean error_set;
-} DetailledCallbackData;
+ GSList *context_templates;
+ GHashTable *context_templates_hash;
+} DownstreamCallbackData;
static GError *
-suggest_update_cb_detailled (GdaMetaStore *store, GdaMetaContext *suggest, DetailledCallbackData *data)
+suggest_update_cb_downstream (GdaMetaStore *store, GdaMetaContext *suggest, DownstreamCallbackData *data)
{
+#define MAX_CONTEXT_SIZE 10
if (data->error && *(data->error))
return *(data->error);
+ GdaMetaContext *templ_context;
+ GdaMetaContext loc_suggest;
+
+ /* if there is no context with the same table name in the templates, then exit right now */
+ templ_context = g_hash_table_lookup (data->context_templates_hash, suggest->table_name);
+ if (!templ_context)
+ return NULL;
+
+ if (templ_context->size > 0) {
+ /* setup @loc_suggest */
+
+ gchar *column_names[MAX_CONTEXT_SIZE];
+ GValue *column_values[MAX_CONTEXT_SIZE];
+ gint i, j;
+
+ if (suggest->size > MAX_CONTEXT_SIZE) {
+ g_warning ("Internal limitation at %s(), limitation should be at least %d, please report a bug",
+ __FUNCTION__, suggest->size);
+ return NULL;
+ }
+ loc_suggest.size = suggest->size;
+ loc_suggest.table_name = suggest->table_name;
+ loc_suggest.column_names = column_names;
+ loc_suggest.column_values = column_values;
+ memcpy (loc_suggest.column_names, suggest->column_names, sizeof (gchar *) * suggest->size);
+ memcpy (loc_suggest.column_values, suggest->column_values, sizeof (GValue *) * suggest->size);
+
+ /* check that any @suggest's columns which is in @templ_context's has the same values */
+ for (j = 0; j < suggest->size; j++) {
+ for (i = 0; i < templ_context->size; i++) {
+ if (!strcmp (templ_context->column_names[i], suggest->column_names[j])) {
+ /* same column name, now check column value */
+ if (G_VALUE_TYPE (templ_context->column_values[i]) !=
+ G_VALUE_TYPE (suggest->column_values[j])) {
+ g_warning ("Internal error: column types mismatch for GdaMetaContext "
+ "table '%s' and column '%s' (%s/%s)",
+ templ_context->table_name, templ_context->column_names[i],
+ g_type_name (G_VALUE_TYPE (templ_context->column_values[i])),
+ g_type_name (G_VALUE_TYPE (suggest->column_values[j])));
+ return NULL;
+ }
+ if (gda_value_compare_ext (templ_context->column_values[i],
+ (suggest->column_values[j])))
+ /* different values */
+ return NULL;
+ break;
+ }
+ }
+ }
+
+ /* @templ_context may contain some more columns => add them to @loc_suggest */
+ for (i = 0; i < templ_context->size; i++) {
+ for (j = 0; j < suggest->size; j++) {
+ if (!strcmp (templ_context->column_names[i], suggest->column_names[j])) {
+ j = -1;
+ break;
+ }
+ }
+ if (j >= 0) {
+ if (loc_suggest.size >= MAX_CONTEXT_SIZE) {
+ g_warning ("Internal limitation at %s(), limitation should be at least %d, please report a bug",
+ __FUNCTION__, loc_suggest.size + 1);
+ return NULL;
+ }
+ loc_suggest.column_names [loc_suggest.size] = templ_context->column_names [i];
+ loc_suggest.column_values [loc_suggest.size] = templ_context->column_values [i];
+ loc_suggest.size ++;
+ }
+ }
+
+ suggest = &loc_suggest;
+ }
+
if (!local_meta_update (data->prov, data->cnc, suggest, data->error)) {
data->error_set = TRUE;
@@ -1988,11 +2184,10 @@
return *(data->error);
}
+
return NULL;
}
-static gboolean gda_connection_update_meta_clean_first = TRUE;
-
/**
* gda_connection_update_meta_store
* @cnc: a #GdaConnection object.
@@ -2008,7 +2203,6 @@
gda_connection_update_meta_store (GdaConnection *cnc, GdaMetaContext *context, GError **error)
{
GdaMetaStore *store;
- gboolean retval = TRUE;
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
@@ -2019,15 +2213,97 @@
/* prepare local context */
GdaMetaContext lcontext;
+
if (context) {
+ GSList *list;
+ GSList *up_templates;
+ GSList *dn_templates;
+ GError *lerror = NULL;
lcontext = *context;
/* alter local context because "_tables" and "_views" always go together so only
"_tables" should be updated and providers should always update "_tables" and "_views"
*/
if (!strcmp (lcontext.table_name, "_views"))
lcontext.table_name = "_tables";
+
+ up_templates = build_upstream_context_templates (store, context, NULL, &lerror);
+ if (!up_templates) {
+ if (lerror) {
+ g_propagate_error (error, lerror);
+ return FALSE;
+ }
+ }
+ dn_templates = build_downstream_context_templates (store, context, NULL, &lerror);
+ if (!dn_templates) {
+ if (lerror) {
+ g_propagate_error (error, lerror);
+ return FALSE;
+ }
+ }
+
+#ifdef GDA_DEBUG_NO
+ g_print ("\n*********** TEMPLATES:\n");
+ for (list = up_templates; list; list = list->next) {
+ g_print ("UP: ");
+ meta_context_dump ((GdaMetaContext*) list->data);
+ }
+ g_print ("->: ");
+ meta_context_dump (context);
+ for (list = dn_templates; list; list = list->next) {
+ g_print ("DN: ");
+ meta_context_dump ((GdaMetaContext*) list->data);
+ }
+#endif
+
+ gulong signal_id;
+ DownstreamCallbackData cbd;
+ gboolean retval = TRUE;
+
+ cbd.prov = cnc->priv->provider_obj;
+ cbd.cnc = cnc;
+ cbd.error = &lerror;
+ cbd.error_set = FALSE;
+ cbd.context_templates = g_slist_concat (g_slist_append (up_templates, context), dn_templates);
+ cbd.context_templates_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ for (list = cbd.context_templates; list; list = list->next)
+ g_hash_table_insert (cbd.context_templates_hash, ((GdaMetaContext*)list->data)->table_name,
+ list->data);
+
+ signal_id = g_signal_connect (store, "suggest_update",
+ G_CALLBACK (suggest_update_cb_downstream), &cbd);
+
+ retval = local_meta_update (cnc->priv->provider_obj, cnc,
+ (GdaMetaContext*) (cbd.context_templates->data), error);
+
+ g_signal_handler_disconnect (store, signal_id);
+ if (cbd.error_set) {
+ if (lerror) {
+ if (error && !*error)
+ g_propagate_error (error, lerror);
+ else
+ g_error_free (lerror);
+ }
+ retval = FALSE;
+ }
+
+ /* free the memory associated with each template */
+ for (list = cbd.context_templates; list; list = list->next) {
+ GdaMetaContext *c = (GdaMetaContext *) list->data;
+ if (c != context) {
+ if (c->size > 0) {
+ g_free (c->column_names);
+ g_free (c->column_values);
+ }
+ g_free (c);
+ }
+ }
+ g_slist_free (cbd.context_templates);
+ g_hash_table_destroy (cbd.context_templates_hash);
+
+ return retval;
}
else {
+ /* no context specified => update everything */
memset (&lcontext, 0, sizeof (GdaMetaContext));
lcontext.table_name = "_builtin_data_types";
if (!gda_connection_update_meta_store (cnc, &lcontext, error))
@@ -2040,29 +2316,6 @@
return FALSE;
return TRUE;
}
-
- /* actual update */
- gulong signal_id;
- DetailledCallbackData cbd;
- GError *lerror = NULL;
-
- cbd.prov = cnc->priv->provider_obj;
- cbd.cnc = cnc;
- cbd.error = &lerror;
- cbd.error_set = FALSE;
- signal_id = g_signal_connect (store, "suggest_update",
- G_CALLBACK (suggest_update_cb_detailled), &cbd);
-
- retval = local_meta_update (cnc->priv->provider_obj, cnc, &lcontext, NULL);
-
- g_signal_handler_disconnect (store, signal_id);
- if (cbd.error_set) {
- if (lerror)
- g_propagate_error (error, lerror);
- retval = FALSE;
- }
-
- return retval;
}
/*
Modified: trunk/libgda/gda-data-model.c
==============================================================================
--- trunk/libgda/gda-data-model.c (original)
+++ trunk/libgda/gda-data-model.c Mon Mar 17 19:34:20 2008
@@ -165,7 +165,10 @@
* @model: a #GdaDataModel object.
* @row: row number.
*
- * Emits the 'row_inserted' and 'changed' signals on @model.
+ * Emits the 'row_inserted' and 'changed' signals on @model.
+ *
+ * This method should only be used by #GdaDataModel implementations to
+ * signal that a row has been inserted.
*/
void
gda_data_model_row_inserted (GdaDataModel *model, gint row)
@@ -204,6 +207,9 @@
* @row: row number.
*
* Emits the 'row_updated' and 'changed' signals on @model.
+ *
+ * This method should only be used by #GdaDataModel implementations to
+ * signal that a row has been updated.
*/
void
gda_data_model_row_updated (GdaDataModel *model, gint row)
@@ -225,6 +231,9 @@
* @row: row number.
*
* Emits the 'row_removed' and 'changed' signal on @model.
+ *
+ * This method should only be used by #GdaDataModel implementations to
+ * signal that a row has been removed
*/
void
gda_data_model_row_removed (GdaDataModel *model, gint row)
@@ -536,8 +545,10 @@
* gda_data_model_create_iter().
*
* Note that the returned #GValue must not be modified directly (unexpected behaviours may
- * occur if you do so). If you want to
- * modify a value stored in a #GdaDataModel, use the gda_data_model_set_value() method.
+ * occur if you do so). Also that value may become invalid as soon as any Libgda part is executed again,
+ * which means if you want to keep the value, a copy must be made.
+ *
+ * If you want to modify a value stored in a #GdaDataModel, use the gda_data_model_set_value() method.
*
* Returns: a #GValue containing the value stored in the given
* position, or %NULL on error (out-of-bound position, etc).
Modified: trunk/libgda/gda-meta-store.c
==============================================================================
--- trunk/libgda/gda-meta-store.c (original)
+++ trunk/libgda/gda-meta-store.c Mon Mar 17 19:34:20 2008
@@ -116,6 +116,8 @@
* It is available for tables, views, triggers, ...
*/
typedef struct {
+ GdaMetaStore *store; /* if not NULL, the store in which this db object is,
+ * or %NULL if it's a class db object */
GdaServerOperationType obj_type;
gchar *obj_name; /* may be %NULL */
GdaServerOperation *create_op; /* may be %NULL */
@@ -195,12 +197,15 @@
gint version;
gboolean schema_ok;
- GSList *custom_db_objects; /* list of DbObject structures */
- GHashTable *custom_db_objects_hash; /* key = table name, value = a DbObject structure */
+ gchar *catalog; /* name of the catalog in which all the objects are created, or NULL if none specified */
+ gchar *schema; /* name of the schema in which all the objects are created, or NULL if none specified */
+
+ GSList *p_db_objects; /* list of DbObject structures */
+ GHashTable *p_db_objects_hash; /* key = table name, value = a DbObject structure */
};
static void db_object_free (DbObject *dbobj);
-static void create_db_objects (GdaMetaStoreClass *klass);
+static void create_db_objects (GdaMetaStoreClass *klass, GdaMetaStore *store);
/* get a pointer to the parents to be able to call their destructor */
@@ -220,6 +225,8 @@
PROP_0,
PROP_CNC_STRING,
PROP_CNC_OBJECT,
+ PROP_CATALOG,
+ PROP_SCHEMA
};
/* module error */
@@ -308,7 +315,8 @@
}
static void
-gda_meta_store_class_init (GdaMetaStoreClass *klass) {
+gda_meta_store_class_init (GdaMetaStoreClass *klass)
+{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
@@ -354,6 +362,12 @@
g_param_spec_object ("cnc", _ ("Connection object internally used"),
NULL, GDA_TYPE_CONNECTION,
(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
+ g_object_class_install_property (object_class, PROP_CATALOG,
+ g_param_spec_string ("catalog", _ ("Catalog in which the database objects will be created"), NULL, NULL,
+ (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
+ g_object_class_install_property (object_class, PROP_SCHEMA,
+ g_param_spec_string ("schema", _ ("Schema in which the database objects will be created"), NULL, NULL,
+ (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
object_class->constructor = gda_meta_store_constructor;
object_class->dispose = gda_meta_store_dispose;
@@ -365,7 +379,7 @@
klass->cpriv->parser = gda_sql_parser_new ();
klass->cpriv->provider_specifics = g_hash_table_new (ProviderSpecific_hash, ProviderSpecific_equal);
klass->cpriv->db_objects_hash = g_hash_table_new (g_str_hash, g_str_equal);
- create_db_objects (klass);
+ create_db_objects (klass, NULL);
klass->cpriv->table_cond_info_hash = g_hash_table_new (g_str_hash, g_str_equal);
klass->cpriv->prep_stmts[STMT_SET_VERSION] =
@@ -424,20 +438,25 @@
static void
-gda_meta_store_init (GdaMetaStore *store) {
+gda_meta_store_init (GdaMetaStore *store)
+{
store->priv = g_new0 (GdaMetaStorePrivate, 1);
store->priv->cnc = NULL;
store->priv->schema_ok = FALSE;
store->priv->version = 0;
- store->priv->custom_db_objects = NULL;
- store->priv->custom_db_objects_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ store->priv->catalog = NULL;
+ store->priv->schema = NULL;
+
+ store->priv->p_db_objects = NULL;
+ store->priv->p_db_objects_hash = g_hash_table_new (g_str_hash, g_str_equal);
}
static GObject *
gda_meta_store_constructor (GType type,
- guint n_construct_properties,
- GObjectConstructParam *construct_properties) {
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
GObject *object;
gint i;
GError *error = NULL;
@@ -473,6 +492,25 @@
g_error_free (error);
}
}
+
+ /* create a local copy of all the DbObject structures defined in klass->cpriv */
+ if (store->priv->catalog && !store->priv->schema) {
+ g_warning (_("Catalog specified but no schema specified, store will not be useable"));
+ store->priv->schema_ok = FALSE;
+ }
+ else {
+ GdaMetaStoreClass *klass = (GdaMetaStoreClass *) G_OBJECT_GET_CLASS (store);
+ GSList *list;
+ if (!store->priv->schema) {
+ /* uses all the klass->cpriv->db_objects AS IS in store->priv->p_db_objects */
+ store->priv->p_db_objects = g_slist_copy (klass->cpriv->db_objects);
+ for (list = store->priv->p_db_objects; list; list = list->next)
+ g_hash_table_insert (store->priv->p_db_objects_hash, DB_OBJECT (list->data)->obj_name,
+ list->data);
+ }
+ else
+ create_db_objects (klass, store);
+ }
return object;
}
@@ -543,10 +581,17 @@
store = GDA_META_STORE (object);
if (store->priv) {
+ GSList *list;
+ g_free (store->priv->catalog);
+ g_free (store->priv->schema);
+
/* custom db objects */
- g_hash_table_destroy (store->priv->custom_db_objects_hash);
- g_slist_foreach (store->priv->custom_db_objects, (GFunc) db_object_free, NULL);
- g_slist_free (store->priv->custom_db_objects);
+ g_hash_table_destroy (store->priv->p_db_objects_hash);
+ for (list = store->priv->p_db_objects; list; list = list->next) {
+ if (DB_OBJECT (list->data)->store == store)
+ db_object_free (DB_OBJECT (list->data));
+ }
+ g_slist_free (store->priv->p_db_objects);
/* internal connection */
if (store->priv->cnc) {
@@ -589,20 +634,34 @@
store = GDA_META_STORE (object);
if (store->priv) {
switch (param_id) {
- case PROP_CNC_STRING:
- if (!store->priv->cnc) {
- cnc_string = g_value_get_string (value);
- if (cnc_string) {
- GdaConnection *cnc;
- cnc = gda_connection_open_from_string (NULL, cnc_string, NULL, 0, NULL);
- store->priv->cnc = cnc;
- }
+ case PROP_CNC_STRING:
+ if (!store->priv->cnc) {
+ cnc_string = g_value_get_string (value);
+ if (cnc_string) {
+ GdaConnection *cnc;
+ cnc = gda_connection_open_from_string (NULL, cnc_string, NULL, 0, NULL);
+ store->priv->cnc = cnc;
}
- break;
- case PROP_CNC_OBJECT:
- if (!store->priv->cnc)
- store->priv->cnc = g_value_get_object (value);
- break;
+ }
+ break;
+ case PROP_CNC_OBJECT:
+ if (!store->priv->cnc)
+ store->priv->cnc = g_value_get_object (value);
+ break;
+ case PROP_CATALOG:
+ g_free (store->priv->catalog);
+ if (g_value_get_string (value) && *g_value_get_string (value))
+ store->priv->catalog = g_strdup (g_value_get_string (value));
+ else
+ store->priv->catalog = NULL;
+ break;
+ case PROP_SCHEMA:
+ g_free (store->priv->schema);
+ if (g_value_get_string (value) && *g_value_get_string (value))
+ store->priv->schema = g_strdup (g_value_get_string (value));
+ else
+ store->priv->schema = NULL;
+ break;
}
}
}
@@ -618,12 +677,18 @@
if (store->priv) {
switch (param_id) {
- case PROP_CNC_STRING:
- g_assert_not_reached ();
- break;
- case PROP_CNC_OBJECT:
- g_value_set_object (value, (GObject *) store->priv->cnc);
- break;
+ case PROP_CNC_STRING:
+ g_assert_not_reached ();
+ break;
+ case PROP_CNC_OBJECT:
+ g_value_set_object (value, (GObject *) store->priv->cnc);
+ break;
+ case PROP_CATALOG:
+ g_value_set_string (value, store->priv->catalog);
+ break;
+ case PROP_SCHEMA:
+ g_value_set_string (value, store->priv->schema);
+ break;
}
}
}
@@ -694,44 +759,54 @@
static GdaServerOperation *create_server_operation_for_view (GHashTable *specific_hash,
GdaServerProvider *prov, GdaConnection *cnc,
DbObject *dbobj, GError **error);
+static gboolean prepare_dbo_server_operation (GdaMetaStoreClass *klass, GdaMetaStore *store, GdaServerProvider *prov,
+ DbObject *dbo, GError **error);
static gboolean
prepare_server_operations (GdaMetaStore *store, GError **error)
{
GSList *objects;
- GdaServerProvider *prov;
GdaMetaStoreClass *klass;
klass = (GdaMetaStoreClass *) G_OBJECT_GET_CLASS (store);
- prov = gda_connection_get_provider_obj (store->priv->cnc);
for (objects = klass->cpriv->db_objects; objects; objects = objects->next) {
DbObject *dbo = DB_OBJECT (objects->data);
- if (dbo->create_op) {
- g_object_unref (dbo->create_op);
- dbo->create_op = NULL;
- }
-
- switch (dbo->obj_type) {
- case GDA_SERVER_OPERATION_CREATE_TABLE:
- dbo->create_op = create_server_operation_for_table (klass->cpriv->provider_specifics,
- prov, store->priv->cnc, dbo, error);
- if (!dbo->create_op)
- return FALSE;
- break;
- case GDA_SERVER_OPERATION_CREATE_VIEW:
- dbo->create_op = create_server_operation_for_view (klass->cpriv->provider_specifics,
- prov, store->priv->cnc, dbo, error);
- if (!dbo->create_op)
- return FALSE;
- break;
- default:
- break;
- }
+ if (! prepare_dbo_server_operation (klass, store, gda_connection_get_provider_obj (store->priv->cnc),
+ dbo, error))
+ return FALSE;
}
return TRUE;
}
+static gboolean
+prepare_dbo_server_operation (GdaMetaStoreClass *klass, GdaMetaStore *store, GdaServerProvider *prov,
+ DbObject *dbo, GError **error)
+{
+ if (dbo->create_op) {
+ g_object_unref (dbo->create_op);
+ dbo->create_op = NULL;
+ }
+
+ switch (dbo->obj_type) {
+ case GDA_SERVER_OPERATION_CREATE_TABLE:
+ dbo->create_op = create_server_operation_for_table (klass->cpriv->provider_specifics,
+ prov, store->priv->cnc, dbo, error);
+ if (!dbo->create_op)
+ return FALSE;
+ break;
+ case GDA_SERVER_OPERATION_CREATE_VIEW:
+ dbo->create_op = create_server_operation_for_view (klass->cpriv->provider_specifics,
+ prov, store->priv->cnc, dbo, error);
+ if (!dbo->create_op)
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
static const gchar *
provider_specific_match (GHashTable *specific_hash, GdaServerProvider *prov, const gchar *expr, const gchar *path)
{
@@ -844,16 +919,19 @@
return NULL;
}
-static DbObject *create_table_object (GdaMetaStoreClass *klass, xmlNodePtr node, GError **error);
-static DbObject *create_view_object (GdaMetaStoreClass *klass, xmlNodePtr node, GError **error);
+static DbObject *create_table_object (GdaMetaStoreClass *klass, GdaMetaStore *store, xmlNodePtr node, GError **error);
+static DbObject *create_view_object (GdaMetaStoreClass *klass, GdaMetaStore *store, xmlNodePtr node, GError **error);
static GSList *reorder_db_objects (GSList *objects, GHashTable *hash);
static gboolean complement_db_objects (GSList *objects, GHashTable *hash, GError **error);
/*
- * Creates all DbObject structures and place them into klass->cpriv->db_objects
+ * Creates all DbObject structures and place them into klass->cpriv->db_objects or store->priv->p_db_objects
+ *
+ * If @store is %NULL, then all the DB objects created are attached to klass->cpriv->db_objects, otherwise
+ * they are placed in store->priv->p_db_objects
*/
static void
-create_db_objects (GdaMetaStoreClass *klass)
+create_db_objects (GdaMetaStoreClass *klass, GdaMetaStore *store)
{
xmlNodePtr node;
GError *lerror = NULL;
@@ -864,8 +942,10 @@
/* load information schema's structure XML file */
file = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, "information_schema.xml", NULL);
doc = xmlParseFile (file);
- if (!doc)
- g_error ("Missing or malformed file '%s', check your installation", file);
+ if (!doc) {
+ g_warning ("Missing or malformed file '%s', check your installation", file);
+ return;
+ }
node = xmlDocGetRootElement (doc);
if (!node || strcmp ((gchar *) node->name, "schema"))
@@ -873,7 +953,10 @@
g_free (file);
/* walk through the xmlDoc */
- klass->cpriv->db_objects = NULL;
+ if (store)
+ store->priv->p_db_objects = NULL;
+ else
+ klass->cpriv->db_objects = NULL;
for (node = node->children; node; node = node->next) {
/* <specifics> tag to allow for provider specific transformations */
if (!strcmp ((gchar *) node->name, "specifics")) {
@@ -920,7 +1003,7 @@
/* <table> tag for table creation */
else if (!strcmp ((gchar *) node->name, "table")) {
DbObject *dbo;
- dbo = create_table_object (klass, node, error);
+ dbo = create_table_object (klass, store, node, error);
if (!dbo)
g_error ("Information schema creation error: %s",
lerror && lerror->message ? lerror->message : "No detail");
@@ -928,7 +1011,7 @@
/* <view> tag for view creation */
else if (!strcmp ((gchar *) node->name, "view")) {
DbObject *dbo;
- dbo = create_view_object (klass, node, error);
+ dbo = create_view_object (klass, store, node, error);
if (!dbo)
g_error ("Information schema creation error: %s",
lerror && lerror->message ? lerror->message : "No detail");
@@ -936,10 +1019,18 @@
}
xmlFreeDoc (doc);
- klass->cpriv->db_objects = reorder_db_objects (klass->cpriv->db_objects, klass->cpriv->db_objects_hash);
- if (!complement_db_objects (klass->cpriv->db_objects, klass->cpriv->db_objects_hash, error))
- g_error ("Information schema structure error: %s",
- lerror && lerror->message ? lerror->message : "No detail");
+ if (store) {
+ store->priv->p_db_objects = reorder_db_objects (store->priv->p_db_objects, store->priv->p_db_objects_hash);
+ if (!complement_db_objects (store->priv->p_db_objects, store->priv->p_db_objects_hash, error))
+ g_error ("Information schema structure error: %s",
+ lerror && lerror->message ? lerror->message : "No detail");
+ }
+ else {
+ klass->cpriv->db_objects = reorder_db_objects (klass->cpriv->db_objects, klass->cpriv->db_objects_hash);
+ if (!complement_db_objects (klass->cpriv->db_objects, klass->cpriv->db_objects_hash, error))
+ g_error ("Information schema structure error: %s",
+ lerror && lerror->message ? lerror->message : "No detail");
+ }
}
/*
@@ -956,26 +1047,45 @@
return -1;
}
-static void compute_view_dependencies (GdaMetaStoreClass *klass, DbObject *view_dbobj, GdaSqlStatement *sqlst);
+static void compute_view_dependencies (GdaMetaStoreClass *klass, GdaMetaStore *store,
+ DbObject *view_dbobj, GdaSqlStatement *sqlst);
static DbObject *
-create_view_object (GdaMetaStoreClass *klass, xmlNodePtr node, GError **error)
+create_view_object (GdaMetaStoreClass *klass, GdaMetaStore *store, xmlNodePtr node, GError **error)
{
DbObject *dbobj;
xmlChar *view_name;
+ gchar *complete_obj_name;
+
view_name = xmlGetProp (node, BAD_CAST "name");
if (!view_name) {
g_set_error (error, 0, 0,
_("Missing view name from <view> node"));
goto onerror;
}
-
+
+ /* determine object's complete name */
+ if (store && store->priv->schema)
+ complete_obj_name = g_strdup_printf ("%s.%s", store->priv->schema, (gchar *) view_name);
+ else
+ complete_obj_name = g_strdup ((gchar *) view_name);
+
/* DbObject structure */
- dbobj = g_hash_table_lookup (klass->cpriv->db_objects_hash, view_name);
+ if (store)
+ dbobj = g_hash_table_lookup (store->priv->p_db_objects_hash, view_name);
+ else
+ dbobj = g_hash_table_lookup (klass->cpriv->db_objects_hash, view_name);
if (!dbobj) {
dbobj = g_new0 (DbObject, 1);
- klass->cpriv->db_objects = g_slist_prepend (klass->cpriv->db_objects, dbobj);
+ dbobj->store = store;
dbobj->obj_name = g_strdup ((gchar *) view_name);
- g_hash_table_insert (klass->cpriv->db_objects_hash, dbobj->obj_name, dbobj);
+ if (store) {
+ store->priv->p_db_objects = g_slist_prepend (store->priv->p_db_objects, dbobj);
+ g_hash_table_insert (store->priv->p_db_objects_hash, dbobj->obj_name, dbobj);
+ }
+ else {
+ klass->cpriv->db_objects = g_slist_prepend (klass->cpriv->db_objects, dbobj);
+ g_hash_table_insert (klass->cpriv->db_objects_hash, dbobj->obj_name, dbobj);
+ }
}
xmlFree (view_name);
dbobj->obj_type = GDA_SERVER_OPERATION_CREATE_VIEW;
@@ -1004,7 +1114,7 @@
if (remain) {
g_set_error (error, 0, 0,
_("View definition contains more than one statement (for view '%s')"),
- dbobj->obj_name);
+ complete_obj_name);
g_object_unref (stmt);
xmlFree (def);
goto onerror;
@@ -1016,12 +1126,12 @@
(gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_COMPOUND)) {
GdaSqlStatement *sqlst;
g_object_get (G_OBJECT (stmt), "structure", &sqlst, NULL);
- compute_view_dependencies (klass, dbobj, sqlst);
+ compute_view_dependencies (klass, store, dbobj, sqlst);
gda_sql_statement_free (sqlst);
g_object_unref (stmt);
#ifdef GDA_DEBUG_NO
- g_print ("View %s depends on: ", dbobj->obj_name);
+ g_print ("View %s depends on: ", complete_obj_name);
GSList *list;
for (list = dbobj->depend_list; list; list = list->next)
g_print ("%s ", DB_OBJECT (list->data)->obj_name);
@@ -1031,7 +1141,7 @@
else {
g_set_error (error, 0, 0,
_("View definition is not a selection statement (for view '%s')"),
- dbobj->obj_name);
+ complete_obj_name);
g_object_unref (stmt);
goto onerror;
}
@@ -1046,10 +1156,12 @@
static GdaSqlExpr *make_expr_EQUAL (GdaSqlAnyPart *parent, xmlChar *cname, xmlChar *type, GType ptype, gboolean nullok, gint index);
static GdaSqlExpr *make_expr_AND (GdaSqlAnyPart *parent, GdaSqlExpr *current);
static DbObject *
-create_table_object (GdaMetaStoreClass *klass, xmlNodePtr node, GError **error)
+create_table_object (GdaMetaStoreClass *klass, GdaMetaStore *store, xmlNodePtr node, GError **error)
{
DbObject *dbobj;
xmlChar *table_name;
+ gchar *complete_obj_name;
+
table_name = xmlGetProp (node, BAD_CAST "name");
if (!table_name) {
g_set_error (error, 0, 0,
@@ -1057,37 +1169,53 @@
return NULL;
}
+ /* determine object's complete name */
+ if (store && store->priv->schema)
+ complete_obj_name = g_strdup_printf ("%s.%s", store->priv->schema, (gchar *) table_name);
+ else
+ complete_obj_name = g_strdup ((gchar *) table_name);
+
/* DbObject structure */
- dbobj = g_hash_table_lookup (klass->cpriv->db_objects_hash, table_name);
+ if (store)
+ dbobj = g_hash_table_lookup (store->priv->p_db_objects_hash, table_name);
+ else
+ dbobj = g_hash_table_lookup (klass->cpriv->db_objects_hash, table_name);
if (!dbobj) {
dbobj = g_new0 (DbObject, 1);
- klass->cpriv->db_objects = g_slist_prepend (klass->cpriv->db_objects, dbobj);
+ dbobj->store = store;
dbobj->obj_name = g_strdup ((gchar *) table_name);
- g_hash_table_insert (klass->cpriv->db_objects_hash, dbobj->obj_name, dbobj);
+ if (store) {
+ store->priv->p_db_objects = g_slist_prepend (store->priv->p_db_objects, dbobj);
+ g_hash_table_insert (store->priv->p_db_objects_hash, dbobj->obj_name, dbobj);
+ }
+ else {
+ klass->cpriv->db_objects = g_slist_prepend (klass->cpriv->db_objects, dbobj);
+ g_hash_table_insert (klass->cpriv->db_objects_hash, dbobj->obj_name, dbobj);
+ }
}
xmlFree (table_name);
dbobj->obj_type = GDA_SERVER_OPERATION_CREATE_TABLE;
/* current_all */
gchar *sql;
- sql = g_strdup_printf ("SELECT * FROM %s", dbobj->obj_name);
+ sql = g_strdup_printf ("SELECT * FROM %s", complete_obj_name);
TABLE_INFO (dbobj)->current_all = compute_prepared_stmt (klass->cpriv->parser, sql);
g_free (sql);
if (!TABLE_INFO (dbobj)->current_all) {
g_set_error (error, 0, 0,
"Internal fatal error: could not create SELECT ALL statement (for table '%s')",
- dbobj->obj_name);
+ complete_obj_name);
goto onerror;
}
/* delete all */
- sql = g_strdup_printf ("DELETE FROM %s", dbobj->obj_name);
+ sql = g_strdup_printf ("DELETE FROM %s", complete_obj_name);
TABLE_INFO (dbobj)->delete_all = compute_prepared_stmt (klass->cpriv->parser, sql);
g_free (sql);
if (!TABLE_INFO (dbobj)->delete_all) {
g_set_error (error, 0, 0,
"Internal fatal error: could not create DELETE ALL statement (for table '%s')",
- dbobj->obj_name);
+ complete_obj_name);
goto onerror;
}
@@ -1103,13 +1231,13 @@
GDA_SQL_ANY_PART (dst)->type = GDA_SQL_ANY_STMT_DELETE;
ist->table = gda_sql_table_new (GDA_SQL_ANY_PART (ist));
- ist->table->table_name = g_strdup ((gchar *) dbobj->obj_name);
+ ist->table->table_name = g_strdup ((gchar *) complete_obj_name);
ust->table = gda_sql_table_new (GDA_SQL_ANY_PART (ust));
- ust->table->table_name = g_strdup ((gchar *) dbobj->obj_name);
+ ust->table->table_name = g_strdup ((gchar *) complete_obj_name);
dst->table = gda_sql_table_new (GDA_SQL_ANY_PART (dst));
- dst->table->table_name = g_strdup ((gchar *) dbobj->obj_name);
+ dst->table->table_name = g_strdup ((gchar *) complete_obj_name);
/* walk through the columns and Fkey nodes */
xmlNodePtr cnode;
@@ -1125,7 +1253,7 @@
continue;
cname = xmlGetProp (cnode, BAD_CAST "name");
if (!cname)
- g_error ("Missing column name (table=%s)", dbobj->obj_name);
+ g_error ("Missing column name (table=%s)", complete_obj_name);
xstr = xmlGetProp (cnode, BAD_CAST "pkey");
if (xstr) {
if ((*xstr == 't') || (*xstr == 'T'))
@@ -1246,18 +1374,30 @@
if (!ref_table) {
g_set_error (error, 0, 0,
_("Missing foreign key's referenced table name (for table '%s')"),
- dbobj->obj_name);
+ complete_obj_name);
goto onerror;
}
/* referenced DbObject */
DbObject *ref_obj;
- ref_obj = g_hash_table_lookup (klass->cpriv->db_objects_hash, ref_table);
+ if (store)
+ ref_obj = g_hash_table_lookup (store->priv->p_db_objects_hash, ref_table);
+ else
+ ref_obj = g_hash_table_lookup (klass->cpriv->db_objects_hash, ref_table);
if (!ref_obj) {
ref_obj = g_new0 (DbObject, 1);
- klass->cpriv->db_objects = g_slist_prepend (klass->cpriv->db_objects, ref_obj);
+ ref_obj->store = store;
ref_obj->obj_name = g_strdup ((gchar *) ref_table);
- g_hash_table_insert (klass->cpriv->db_objects_hash, ref_obj->obj_name, ref_obj);
+ if (store) {
+ store->priv->p_db_objects = g_slist_prepend (store->priv->p_db_objects,
+ ref_obj);
+ g_hash_table_insert (store->priv->p_db_objects_hash, ref_obj->obj_name,
+ ref_obj);
+ }
+ else {
+ klass->cpriv->db_objects = g_slist_prepend (klass->cpriv->db_objects, ref_obj);
+ g_hash_table_insert (klass->cpriv->db_objects_hash, ref_obj->obj_name, ref_obj);
+ }
}
xmlFree (ref_table);
dbobj->depend_list = g_slist_append (dbobj->depend_list, ref_obj);
@@ -1287,7 +1427,7 @@
if (!col) {
g_set_error (error, 0, 0,
_("Missing foreign key's column name (for table '%s')"),
- dbobj->obj_name);
+ complete_obj_name);
table_fkey_free (tfk);
goto onerror;
}
@@ -1298,7 +1438,7 @@
if (tfk->fk_cols_array [fkcolindex] < 0) {
g_set_error (error, 0, 0,
_("Column '%s' not found in table '%s'"), (gchar *) col,
- dbobj->obj_name);
+ complete_obj_name);
table_fkey_free (tfk);
goto onerror;
}
@@ -1335,7 +1475,7 @@
gda_sql_statement_free (st);
if (TABLE_INFO (dbobj)->pk_cols_nb == 0)
- g_error ("Missing key fields identification (table=%s)", dbobj->obj_name);
+ g_error ("Missing key fields identification (table=%s)", complete_obj_name);
#ifdef GDA_DEBUG_NO
/* debug */
@@ -1355,25 +1495,30 @@
GdaSet *params;
if (!gda_statement_get_parameters (TABLE_INFO (dbobj)->insert, &(TABLE_INFO (dbobj)->params), NULL))
g_error ("Internal fatal error: could not get INSERT statement's parameters (table=%s)",
- dbobj->obj_name);
+ complete_obj_name);
if (!gda_statement_get_parameters (TABLE_INFO (dbobj)->update, ¶ms, NULL))
g_error ("Internal fatal error: could not get UPDATE statement's parameters (table=%s)",
- dbobj->obj_name);
+ complete_obj_name);
gda_set_merge_with_set (TABLE_INFO (dbobj)->params, params);
g_object_unref (params);
if (!gda_statement_get_parameters (TABLE_INFO (dbobj)->delete, ¶ms, NULL))
g_error ("Internal fatal error: could not get DELETE statement's parameters (table=%s)",
- dbobj->obj_name);
+ complete_obj_name);
gda_set_merge_with_set (TABLE_INFO (dbobj)->params, params);
g_object_unref (params);
/* insert DbObject */
- g_hash_table_insert (klass->cpriv->db_objects_hash, dbobj->obj_name, dbobj);
+ if (store)
+ g_hash_table_insert (store->priv->p_db_objects_hash, dbobj->obj_name, dbobj);
+ else
+ g_hash_table_insert (klass->cpriv->db_objects_hash, dbobj->obj_name, dbobj);
+ g_free (complete_obj_name);
return dbobj;
onerror:
+ g_free (complete_obj_name);
db_object_free (dbobj);
return NULL;
}
@@ -1424,7 +1569,8 @@
static void
-compute_view_dependencies (GdaMetaStoreClass *klass, DbObject *view_dbobj, GdaSqlStatement *sqlst) {
+compute_view_dependencies (GdaMetaStoreClass *klass, GdaMetaStore *store,
+ DbObject *view_dbobj, GdaSqlStatement *sqlst) {
if (sqlst->stmt_type == GDA_SQL_STATEMENT_SELECT) {
GdaSqlStatementSelect *selst;
selst = (GdaSqlStatementSelect*) (sqlst->contents);
@@ -1434,13 +1580,26 @@
if (!t->table_name)
continue;
- DbObject *ref_obj;
- ref_obj = g_hash_table_lookup (klass->cpriv->db_objects_hash, t->table_name);
+ DbObject *ref_obj = NULL;
+ if (store)
+ ref_obj = g_hash_table_lookup (store->priv->p_db_objects_hash, t->table_name);
+ else
+ ref_obj = g_hash_table_lookup (klass->cpriv->db_objects_hash, t->table_name);
+
if (!ref_obj) {
ref_obj = g_new0 (DbObject, 1);
- klass->cpriv->db_objects = g_slist_prepend (klass->cpriv->db_objects, ref_obj);
+ ref_obj->store = store;
ref_obj->obj_name = g_strdup (t->table_name);
- g_hash_table_insert (klass->cpriv->db_objects_hash, ref_obj->obj_name, ref_obj);
+ if (store) {
+ store->priv->p_db_objects = g_slist_prepend (store->priv->p_db_objects,
+ ref_obj);
+ g_hash_table_insert (store->priv->p_db_objects_hash, ref_obj->obj_name,
+ ref_obj);
+ }
+ else {
+ klass->cpriv->db_objects = g_slist_prepend (klass->cpriv->db_objects, ref_obj);
+ g_hash_table_insert (klass->cpriv->db_objects_hash, ref_obj->obj_name, ref_obj);
+ }
}
view_dbobj->depend_list = g_slist_append (view_dbobj->depend_list, ref_obj);
}
@@ -1450,7 +1609,7 @@
GSList *list;
cst = (GdaSqlStatementCompound*) (sqlst->contents);
for (list = cst->stmt_list; list; list = list->next)
- compute_view_dependencies (klass, view_dbobj, (GdaSqlStatement*) list->data);
+ compute_view_dependencies (klass, store, view_dbobj, (GdaSqlStatement*) list->data);
}
else
g_assert_not_reached ();
@@ -2118,9 +2277,9 @@
&suggest_reports_error);
g_free (context.column_values);
if (suggest_reports_error) {
- /*g_print ("SUGGEST META UPDATE Returned FALSE: %s\n",
+ g_print ("SUGGEST META UPDATE Returned FALSE: %s\n",
suggest_reports_error && suggest_reports_error->message ?
- suggest_reports_error->message : "???");*/
+ suggest_reports_error->message : "???");
retval = FALSE;
if (error && !(*error))
g_propagate_error (error, suggest_reports_error);
@@ -2299,9 +2458,8 @@
/* fetch or create *out_table_infos */
DbObject *dbobj = g_hash_table_lookup (klass->cpriv->db_objects_hash, table_name);
if (!dbobj) {
- /* FIXME: allow for external definition of TableInfo structures for
- * other kind of data to be stored in meta store object */
- TO_IMPLEMENT;
+ g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_SCHEMA_OBJECT_NOT_FOUND_ERROR,
+ _("Unknown database object '%s'"), table_name);
return FALSE;
}
*out_table_infos = TABLE_INFO (dbobj);
@@ -2411,7 +2569,7 @@
g_return_val_if_fail (table_name && *table_name, FALSE);
klass = (GdaMetaStoreClass *) G_OBJECT_GET_CLASS (store);
- dbobj = g_hash_table_lookup (klass->cpriv->db_objects_hash, table_name);
+ dbobj = g_hash_table_lookup (store->priv->p_db_objects_hash, table_name);
if (!dbobj) {
g_warning ("Table '%s' is not known by the GdaMetaStore", table_name);
return NULL;
@@ -2435,7 +2593,7 @@
}
/**
- * gda_meta_store_schema_get_tables
+ * gda_meta_store_schema_get_all_tables
* @store: a #GdaMetaStore object
*
* Get an ordered list of the tables @store knows about. The tables are ordered in a way that tables dependencies
@@ -2446,7 +2604,7 @@
* but the strings present in the list must not be modified.
*/
GSList *
-gda_meta_store_schema_get_tables (GdaMetaStore *store)
+gda_meta_store_schema_get_all_tables (GdaMetaStore *store)
{
GSList *list, *ret;
GdaMetaStoreClass *klass;
@@ -2459,6 +2617,49 @@
if (dbobj->obj_type == GDA_SERVER_OPERATION_CREATE_TABLE)
ret = g_slist_prepend (ret, dbobj->obj_name);
}
+ for (ret = NULL, list = store->priv->p_db_objects; list; list = list->next) {
+ DbObject *dbobj = DB_OBJECT (list->data);
+ if (dbobj->obj_type == GDA_SERVER_OPERATION_CREATE_TABLE)
+ ret = g_slist_prepend (ret, dbobj->obj_name);
+ }
+
+ return g_slist_reverse (ret);
+}
+
+/**
+ * gda_meta_store_schema_get_depend_tables
+ * @store: a #GdaMetaStore object
+ * @table_name: the name of the table for which all the dependencies must be listed
+ *
+ *
+ * Get an ordered list of the tables @store knows about on which the @table_name table depends (recursively).
+ * The tables are ordered in a way that tables dependencies
+ * are respected: if table B has a foreign key on table A, then table A will be listed before table B in the returned
+ * list.
+ *
+ * Returns: a new list of tables names (as gchar*), the list must be freed when no longer needed,
+ * but the strings present in the list must not be modified.
+ */
+GSList *
+gda_meta_store_schema_get_depend_tables (GdaMetaStore *store, const gchar *table_name)
+{
+ GSList *list, *ret;
+ GdaMetaStoreClass *klass;
+ DbObject *dbo;
+
+ g_return_val_if_fail (GDA_IS_META_STORE (store), NULL);
+ g_return_val_if_fail (table_name && *table_name, NULL);
+
+ klass = (GdaMetaStoreClass *) G_OBJECT_GET_CLASS (store);
+ dbo = g_hash_table_lookup (store->priv->p_db_objects_hash, table_name);
+ if (!dbo)
+ return NULL;
+
+ for (ret = NULL, list = dbo->depend_list; list; list = list->next) {
+ DbObject *dbobj = DB_OBJECT (list->data);
+ if (dbobj->obj_type == GDA_SERVER_OPERATION_CREATE_TABLE)
+ ret = g_slist_prepend (ret, dbobj->obj_name);
+ }
return g_slist_reverse (ret);
}
@@ -2489,13 +2690,15 @@
/* create a GdaMetaStruct */
pstore = gda_connection_get_meta_store (store->priv->cnc);
- model = gda_meta_store_extract (pstore, "SELECT table_catalog, table_schema, table_name FROM _tables", error, NULL);
+ model = gda_meta_store_extract (pstore, "SELECT table_catalog, table_schema, table_name FROM _tables",
+ error, NULL);
if (!model)
return NULL;
mstruct = gda_meta_struct_new (GDA_META_STRUCT_FEATURE_ALL);
nrows = gda_data_model_get_n_rows (model);
for (i = 0; i < nrows; i++) {
+ /* FIXME: only take into account the database objects which have a corresponding DbObject */
if (!gda_meta_struct_complement (mstruct, pstore, GDA_META_DB_UNKNOWN,
gda_data_model_get_value_at (model, 0, i),
gda_data_model_get_value_at (model, 1, i),
@@ -2508,11 +2711,15 @@
g_object_unref (model);
/* complement the meta struct with some info about dependencies */
- GSList *list;
+ GSList *list, *all_db_obj_list;
GdaMetaStoreClass *klass;
klass = (GdaMetaStoreClass *) G_OBJECT_GET_CLASS (pstore);
- for (list = klass->cpriv->db_objects; list; list = list->next) {
+ all_db_obj_list = g_slist_copy (klass->cpriv->db_objects);
+ if (store->priv->p_db_objects)
+ all_db_obj_list = g_slist_concat (all_db_obj_list, g_slist_copy (store->priv->p_db_objects));
+
+ for (list = all_db_obj_list; list; list = list->next) {
DbObject *dbobj = DB_OBJECT (list->data);
if (dbobj->obj_type == GDA_SERVER_OPERATION_CREATE_TABLE) {
GdaMetaDbObject *mdbo;
@@ -2537,6 +2744,7 @@
}
}
}
+ g_slist_free (all_db_obj_list);
return mstruct;
}
@@ -2701,8 +2909,11 @@
GdaMetaStoreClass *klass;
DbObject *dbo = NULL;
GValue *value;
- GdaMetaStore *pstore;
- GdaMetaStruct *mstruct;
+ GdaMetaStore *pstore = NULL;
+ GdaMetaStruct *mstruct = NULL;
+ GError *lerror = NULL;
+
+ GSList *pre_p_db_objects;
g_return_val_if_fail (GDA_IS_META_STORE (store), FALSE);
g_return_val_if_fail (xml_description && *xml_description, FALSE);
@@ -2718,53 +2929,313 @@
klass = (GdaMetaStoreClass *) G_OBJECT_GET_CLASS (store);
- /* create DbObject structure from XML description */
- /* FIXME: create the DbObject but store it into @store->priv instead of klass->cpriv */
- if (!strcmp ((gchar *) node->name, "table")) {
- xmlChar *prop;
- prop = xmlGetProp (node, BAD_CAST "name");
- if (!prop)
- g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_SCHEMA_OBJECT_DESCR_ERROR,
- _("Missing custom database object name"));
- else if (*prop == '_')
- g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_SCHEMA_OBJECT_DESCR_ERROR,
- _("Custom database object names starting with a '_' are reserved for internal usage"));
- else
- dbo = create_table_object (klass, node, error);
+ /* check that object name does not start with '_' */
+ xmlChar *prop;
+ prop = xmlGetProp (node, BAD_CAST "name");
+ if (!prop) {
+ g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_SCHEMA_OBJECT_DESCR_ERROR,
+ _("Missing custom database object name"));
+ goto onerror;
}
- else if (!strcmp ((gchar *) node->name, "view")) {
- xmlChar *prop;
- prop = xmlGetProp (node, BAD_CAST "name");
- if (!prop)
- g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_SCHEMA_OBJECT_DESCR_ERROR,
- _("Missing custom database object name"));
- else if (*prop == '_')
- g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_SCHEMA_OBJECT_DESCR_ERROR,
- _("Custom database object names starting with a '_' are reserved for internal usage"));
- else
- dbo = create_view_object (klass, node, error);
+ else if (*prop == '_') {
+ g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_SCHEMA_OBJECT_DESCR_ERROR,
+ _("Custom database object names starting with a '_' are reserved for internal usage"));
+ goto onerror;
}
- xmlFreeDoc (doc);
+ /* keep a list of custom DB objects _before_ adding the new one(s) (more than
+ * one if there are dependencies) */
+ pre_p_db_objects = g_slist_copy (store->priv->p_db_objects);
+
+ /* create DbObject structure from XML description, stored in @store's custom db objects */
+ if (!strcmp ((gchar *) node->name, "table"))
+ dbo = create_table_object (klass, store, node, error);
+ else if (!strcmp ((gchar *) node->name, "view"))
+ dbo = create_view_object (klass, store, node, error);
if (!dbo)
- return FALSE;
+ goto onerror;
+ xmlFreeDoc (doc);
+ doc = NULL;
/* check for an already existing database object with the same name */
g_print ("Obj name: %s\n", dbo->obj_name);
- /* make sure the private connection's meta store is up to date */
- if (! gda_connection_update_meta_store (store->priv->cnc, NULL, error))
- return FALSE;
+ /* make sure the private connection's meta store is up to date about the requested object */
+ switch (dbo->obj_type) {
+ case GDA_SERVER_OPERATION_CREATE_TABLE:
+ case GDA_SERVER_OPERATION_CREATE_VIEW: {
+ GdaMetaContext context;
+ gboolean upd_ok;
+ memset (&context, 0, sizeof (GdaMetaContext));
+ context.table_name = "_tables";
+ context.size = 1;
+ context.column_names = g_new0 (gchar *, 3);
+ context.column_values = g_new0 (GValue *, 3);
+ context.column_names[0] = "table_name";
+ g_value_set_string ((context.column_values[0] = gda_value_new (G_TYPE_STRING)), dbo->obj_name);
+ upd_ok = gda_connection_update_meta_store (store->priv->cnc, &context, error);
+ if (!upd_ok)
+ goto onerror;
+ break;
+ }
+ default:
+ TO_IMPLEMENT;
+ }
/* create a GdaMetaStruct */
+ GdaMetaDbObject *eobj;
+ gboolean needs_creation = TRUE;
pstore = gda_connection_get_meta_store (store->priv->cnc);
mstruct = gda_meta_struct_new (GDA_META_STRUCT_FEATURE_ALL);
g_value_set_string ((value = gda_value_new (G_TYPE_STRING)), dbo->obj_name);
- if (!gda_meta_struct_complement (mstruct, pstore, GDA_META_DB_UNKNOWN,
- NULL, NULL, value, error))
- return FALSE;
+ if (!(eobj = gda_meta_struct_complement (mstruct, pstore, GDA_META_DB_UNKNOWN,
+ NULL, NULL, value, &lerror))) {
+ if (lerror && (lerror->domain == GDA_META_STRUCT_ERROR) &&
+ (lerror->code == GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR))
+ g_error_free (lerror);
+ else {
+ g_propagate_error (error, lerror);
+ goto onerror;
+ }
+ }
gda_value_free (value);
+ if (eobj) {
+ gboolean conflict = FALSE;
+
+ g_print ("Check Existing object's conformance...\n");
+ switch (eobj->obj_type) {
+ case GDA_META_DB_TABLE:
+ if (dbo->obj_type != GDA_SERVER_OPERATION_CREATE_TABLE)
+ conflict = TRUE;
+ else {
+ GdaMetaTable *mt = GDA_META_DB_OBJECT_GET_TABLE (eobj);
+ TableInfo *ti = TABLE_INFO (dbo);
+ if (g_slist_length (mt->columns) != g_slist_length (ti->columns))
+ conflict = TRUE;
+ }
+ break;
+ case GDA_META_DB_VIEW:
+ if (dbo->obj_type != GDA_SERVER_OPERATION_CREATE_VIEW)
+ conflict = TRUE;
+ else {
+ GdaMetaView *mv = GDA_META_DB_OBJECT_GET_VIEW (eobj);
+ ViewInfo *vi = VIEW_INFO (dbo);
+ if (!mv->view_def ||
+ !vi->view_def ||
+ strcmp (mv->view_def, vi->view_def))
+ conflict = TRUE;
+ }
+ break;
+ default:
+ TO_IMPLEMENT;
+ }
+
+ if (conflict) {
+ g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_SCHEMA_OBJECT_CONFLICT_ERROR,
+ _("Another object with the same name already exists"));
+ goto onerror;
+ }
+ needs_creation = FALSE;
+ }
+ g_object_unref (mstruct);
+ mstruct = NULL;
+
+ if (needs_creation) {
+ /* prepare the create operation */
+ GdaServerProvider *prov;
+ prov = gda_connection_get_provider_obj (store->priv->cnc);
+ if (! prepare_dbo_server_operation (klass, store, prov, dbo, error))
+ goto onerror;
+
+ /* actually create the object in database */
+ g_print ("Creating object: %s\n", dbo->obj_name);
+ if (dbo->create_op) {
+ if (!gda_server_provider_perform_operation (prov, store->priv->cnc, dbo->create_op, error))
+ goto onerror;
+ g_object_unref (dbo->create_op);
+ dbo->create_op = NULL;
+ }
+ }
+
return TRUE;
+
+ onerror:
+ if (doc)
+ xmlFreeDoc (doc);
+ if (dbo) {
+ GSList *current_objects, *list;
+ current_objects = g_slist_copy (store->priv->p_db_objects);
+ for (list = current_objects; list; list = list->next) {
+ dbo = DB_OBJECT (list->data);
+ if (!g_slist_find (pre_p_db_objects, dbo)) {
+ /* remove the DbObject */
+ store->priv->p_db_objects = g_slist_remove (store->priv->p_db_objects, dbo);
+ g_hash_table_remove (store->priv->p_db_objects_hash, dbo->obj_name);
+ db_object_free (dbo);
+ }
+ }
+ g_slist_free (current_objects);
+ }
+ g_slist_free (pre_p_db_objects);
+ if (pstore)
+ g_object_unref (pstore);
+ if (mstruct)
+ g_object_unref (mstruct);
+
+ return FALSE;
+}
+
+/**
+ * gda_meta_store_schema_remove_custom_object
+ * @store: a #GdaMetaStore object
+ * @obj_name: name of the custom object to remove
+ * @error: a place to store errors, or %NULL
+ *
+ * Removes the custom database object named @obj_name.
+ *
+ * Returns: TRUE if the custom object has sucessfully been removed
+ */
+gboolean
+gda_meta_store_schema_remove_custom_object (GdaMetaStore *store, const gchar *obj_name, GError **error)
+{
+ g_return_val_if_fail (GDA_IS_META_STORE (store), FALSE);
+ g_return_val_if_fail (obj_name && *obj_name, FALSE);
+
+ TO_IMPLEMENT;
+ return FALSE;
+}
+
+/*
+ * Returns: a list of new #GdaMetaContext structures, one for each dependency context->table_name has,
+ * or %NULL if there is no downstream context, or if an error occurred (check @error to make the difference).
+ *
+ * WARNING: each new GdaMetaContext structure is allocated, but:
+ * - the @table_name argument is not copied
+ * - if @size > 0 then @column_names and @column_values are allocated, but their contents is not!
+ */
+GSList *
+_gda_meta_store_schema_get_upstream_contexts (GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ DbObject *dbo;
+ GSList *list, *retlist = NULL;
+ TableInfo *tinfo;
+
+ /* find the associated DbObject */
+ dbo = g_hash_table_lookup (store->priv->p_db_objects_hash, context->table_name);
+ if (!dbo) {
+ g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_SCHEMA_OBJECT_NOT_FOUND_ERROR,
+ _("Unknown database object '%s'"), context->table_name);
+ return NULL;
+ }
+ if (dbo->obj_type != GDA_SERVER_OPERATION_CREATE_TABLE)
+ return NULL;
+
+ tinfo = TABLE_INFO (dbo);
+ if (!tinfo->fk_list)
+ /* this is not an error, just that there are no dependency */
+ return NULL;
+
+ /* Identify the TableFKey if @context permits it */
+ if (context->size > 0) {
+ for (list = tinfo->fk_list; list; list = list->next) {
+ TableFKey *tfk = (TableFKey*) list->data;
+ gint i, j, partial_parts = 0;
+ gint *cols_array;
+
+ cols_array = g_new (gint, tfk->cols_nb);
+ for (i = 0; i < tfk->cols_nb; i++) {
+ cols_array [i] = -1;
+ for (j = 0; j < context->size; j++) {
+ if (!strcmp (tfk->fk_names_array[i], context->column_names[j])) {
+ cols_array [i] = j;
+ partial_parts++;
+ break;
+ }
+ }
+ }
+ if (partial_parts > 0) {
+ GdaMetaContext *ct;
+ ct = g_new0 (GdaMetaContext, 1);
+ ct->table_name = tfk->depend_on->obj_name;
+ ct->size = partial_parts;
+ ct->column_names = g_new0 (gchar *, ct->size);
+ ct->column_values = g_new0 (GValue *, ct->size);
+ retlist = g_slist_prepend (retlist, ct);
+ for (j = 0, i = 0; i < tfk->cols_nb; i++) {
+ if (cols_array [i] >= 0) {
+ ct->column_names [j] = tfk->ref_pk_names_array [i];
+ ct->column_values [j] = context->column_values [cols_array [i]];
+ j++;
+ }
+ }
+ break;
+ }
+ else {
+ GdaMetaContext *ct;
+ ct = g_new0 (GdaMetaContext, 1);
+ ct->table_name = tfk->depend_on->obj_name;
+ ct->size = 0;
+ retlist = g_slist_prepend (retlist, ct);
+ }
+ g_free (cols_array);
+ }
+ }
+ else {
+ for (list = tinfo->fk_list; list; list = list->next) {
+ TableFKey *tfk = (TableFKey*) list->data;
+ GdaMetaContext *ct;
+ ct = g_new0 (GdaMetaContext, 1);
+ ct->table_name = tfk->depend_on->obj_name;
+ ct->size = 0;
+ retlist = g_slist_prepend (retlist, ct);
+ }
+ }
+ return g_slist_reverse (retlist);
+}
+
+/*
+ * Returns: a list of new #GdaMetaContext structures, one for each reverse dependency context->table_name has,
+ * or %NULL if there is no downstream context, or if an error occurred (check @error to make the difference).
+ *
+ * WARNING: each new GdaMetaContext structure is allocated, but:
+ * - the @table_name argument is not copied
+ * - if @size > 0 then @column_names and @column_values are allocated, but their contents is not!
+ */
+GSList *
+_gda_meta_store_schema_get_downstream_contexts (GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ DbObject *dbo;
+ GSList *list, *retlist = NULL;
+ TableInfo *tinfo;
+
+ /* find the associated DbObject */
+ dbo = g_hash_table_lookup (store->priv->p_db_objects_hash, context->table_name);
+ if (!dbo) {
+ g_set_error (error, GDA_META_STORE_ERROR, GDA_META_STORE_SCHEMA_OBJECT_NOT_FOUND_ERROR,
+ _("Unknown database object '%s'"), context->table_name);
+ return NULL;
+ }
+ if (dbo->obj_type != GDA_SERVER_OPERATION_CREATE_TABLE)
+ return NULL;
+
+ tinfo = TABLE_INFO (dbo);
+ if (!tinfo->reverse_fk_list)
+ /* this is not an error, just that there are no dependency */
+ return NULL;
+
+ for (list = tinfo->reverse_fk_list; list; list = list->next) {
+ TableFKey *tfk = (TableFKey*) list->data;
+ GdaMetaContext *ct;
+
+ /* REM: there may be duplicates, but we don't really care here (it'd take more ressources to get rid of
+ * them than it takes to put duplicates in a hash table */
+ ct = g_new0 (GdaMetaContext, 1);
+ ct->table_name = tfk->table_info->obj_name;
+ ct->size = 0;
+ retlist = g_slist_prepend (retlist, ct);
+ }
+
+ return g_slist_reverse (retlist);
}
Modified: trunk/libgda/gda-meta-store.h
==============================================================================
--- trunk/libgda/gda-meta-store.h (original)
+++ trunk/libgda/gda-meta-store.h Mon Mar 17 19:34:20 2008
@@ -41,10 +41,12 @@
GDA_META_STORE_INCORRECT_SCHEMA,
GDA_META_STORE_UNSUPPORTED_PROVIDER,
GDA_META_STORE_INTERNAL_ERROR,
+ GDA_META_STORE_META_CONTEXT_ERROR,
GDA_META_STORE_MODIFY_CONTENTS_ERROR,
GDA_META_STORE_EXTRACT_SQL_ERROR,
GDA_META_STORE_ATTRIBUTE_NOT_FOUND_ERROR,
GDA_META_STORE_ATTRIBUTE_ERROR,
+ GDA_META_STORE_SCHEMA_OBJECT_NOT_FOUND_ERROR,
GDA_META_STORE_SCHEMA_OBJECT_CONFLICT_ERROR,
GDA_META_STORE_SCHEMA_OBJECT_DESCR_ERROR
} GdaMetaStoreError;
@@ -105,18 +107,21 @@
GdaDataModel *new_data, GError **error);
GdaDataModel *gda_meta_store_create_modify_data_model (GdaMetaStore *store, const gchar *table_name);
-GdaMetaStruct *gda_meta_store_schema_get_structure (GdaMetaStore *store, GError **error);
-
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,
const gchar *att_value, GError **error);
-gboolean gda_meta_store_schema_add_custom_object (GdaMetaStore *store, const gchar *xml_description,
- GError **error);
+gboolean gda_meta_store_schema_add_custom_object (GdaMetaStore *store, const gchar *xml_description,
+ GError **error);
+gboolean gda_meta_store_schema_remove_custom_object (GdaMetaStore *store, const gchar *obj_name, GError **error);
+
+GSList *gda_meta_store_schema_get_all_tables (GdaMetaStore *store);
+GSList *gda_meta_store_schema_get_depend_tables (GdaMetaStore *store, const gchar *table_name);
+GdaMetaStruct *gda_meta_store_schema_get_structure (GdaMetaStore *store, GError **error);
-/* TO REMOVE */
-GSList *gda_meta_store_schema_get_tables (GdaMetaStore *store);
+GSList *_gda_meta_store_schema_get_upstream_contexts (GdaMetaStore *store, GdaMetaContext *context, GError **error);
+GSList *_gda_meta_store_schema_get_downstream_contexts (GdaMetaStore *store, GdaMetaContext *context, GError **error);
G_END_DECLS
Modified: trunk/libgda/gda-server-provider.c
==============================================================================
--- trunk/libgda/gda-server-provider.c (original)
+++ trunk/libgda/gda-server-provider.c Mon Mar 17 19:34:20 2008
@@ -416,7 +416,7 @@
GdaServerOperationType type,
GdaSet *options, GError **error)
{
- OpReq **op_req_table = NULL;
+ static OpReq **op_req_table = NULL;
if (! op_req_table) {
op_req_table = g_new0 (OpReq *, GDA_SERVER_OPERATION_NB);
Modified: trunk/libgda/gda-server-provider.h
==============================================================================
--- trunk/libgda/gda-server-provider.h (original)
+++ trunk/libgda/gda-server-provider.h Mon Mar 17 19:34:20 2008
@@ -96,6 +96,12 @@
gboolean (*constraints_ref) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **,
const GValue *table_catalog, const GValue *table_schema, const GValue *table_name,
const GValue *constraint_name);
+
+ /* _key_column_usage */
+ gboolean (*_key_columns) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **);
+ gboolean (*key_columns) (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **,
+ const GValue *table_catalog, const GValue *table_schema, const GValue *table_name,
+ const GValue *constraint_name);
} GdaServerProviderMeta;
typedef void (*GdaServerProviderAsyncCallback) (GdaServerProvider *provider, GdaConnection *cnc, guint task_id,
Modified: trunk/libgda/gda-statement.h
==============================================================================
--- trunk/libgda/gda-statement.h (original)
+++ trunk/libgda/gda-statement.h Mon Mar 17 19:34:20 2008
@@ -88,7 +88,7 @@
GdaStatement *gda_statement_deserialize (const gchar *str, GError **error);
gboolean gda_statement_get_parameters (GdaStatement *stmt, GdaSet **out_params, GError **error);
-#define gda_statement_to_sql(stmt,params,error) gda_statement_to_sql_extended ((stmt), NULL, (params), NULL, GDA_STATEMENT_SQL_PARAMS_SHORT, NULL, (error))
+#define gda_statement_to_sql(stmt,params,error) gda_statement_to_sql_extended ((stmt), NULL, (params), GDA_STATEMENT_SQL_PARAMS_SHORT, NULL, (error))
gchar *gda_statement_to_sql_extended (GdaStatement *stmt, GdaConnection *cnc,
GdaSet *params, GdaStatementSqlFlag flags,
GSList **params_used, GError **error);
Modified: trunk/libgda/gda-util.c
==============================================================================
--- trunk/libgda/gda-util.c (original)
+++ trunk/libgda/gda-util.c Mon Mar 17 19:34:20 2008
@@ -662,7 +662,7 @@
col_ids = g_new0 (gchar *, rnb_cols);
for (c = 0; c < rnb_cols; c++) {
GdaColumn *column;
- const gchar *id;
+ gchar *id;
column = gda_data_model_describe_column (model, rcols [c]);
g_object_get (G_OBJECT (column), "id", &id, NULL);
Modified: trunk/libgda/information_schema.xml
==============================================================================
--- trunk/libgda/information_schema.xml (original)
+++ trunk/libgda/information_schema.xml Mon Mar 17 19:34:20 2008
@@ -363,9 +363,9 @@
<column name="ref_table_name"/>
<column name="ref_constraint_name"/>
- <column name="match_option" nullok="TRUE"/>
- <column name="update_rule" nullok="TRUE"/>
- <column name="delete_rule" nullok="TRUE"/>
+ <column name="match_option" nullok="TRUE" descr="FULL, PARTIAL or NONE"/>
+ <column name="update_rule" nullok="TRUE" descr="CASCADE, SET NULL, SET DEFAULT, RESTRICT, NO ACTION or NONE"/>
+ <column name="delete_rule" nullok="TRUE" descr="CASCADE, SET NULL, SET DEFAULT, RESTRICT, NO ACTION or NONE"/>
<fkey ref_table="_table_constraints">
<part column="table_catalog"/>
<part column="table_schema"/>
Modified: trunk/libgda/sqlite/gda-sqlite-meta.c
==============================================================================
--- trunk/libgda/sqlite/gda-sqlite-meta.c (original)
+++ trunk/libgda/sqlite/gda-sqlite-meta.c Mon Mar 17 19:34:20 2008
@@ -40,7 +40,9 @@
*/
typedef enum {
I_PRAGMA_DATABASE_LIST,
- I_PRAGMA_TABLE_INFO
+ I_PRAGMA_TABLE_INFO,
+ I_PRAGMA_INDEX_LIST,
+ I_PRAGMA_FK_LIST
} InternalStatementItem;
@@ -48,8 +50,17 @@
* predefined statements' SQL
*/
static gchar *internal_sql[] = {
+ /* I_PRAGMA_DATABASE_LIST */
"PRAGMA database_list",
- "PRAGMA table_info (##tblname::string)"
+
+ /* I_PRAGMA_TABLE_INFO */
+ "PRAGMA table_info (##tblname::string)",
+
+ /* I_PRAGMA_INDEX_LIST */
+ "PRAGMA index_list (##tblname::string)",
+
+ /* I_PRAGMA_FK_LIST */
+ "PRAGMA foreign_key_list (##tblname::string)"
};
/*
@@ -68,6 +79,7 @@
static GValue *view_check_option;
static GValue *false_value;
static GValue *zero_value;
+static GValue *rule_value;
static GdaSet *pragma_set;
/*
@@ -94,14 +106,13 @@
}
}
- catalog_value = gda_value_new (G_TYPE_STRING);
- g_value_set_string (catalog_value, "main");
-
+ g_value_set_string ((catalog_value = gda_value_new (G_TYPE_STRING)), "main");
g_value_set_string ((table_type_value = gda_value_new (G_TYPE_STRING)), "BASE TABLE");
g_value_set_string ((view_type_value = gda_value_new (G_TYPE_STRING)), "VIEW");
g_value_set_string ((view_check_option = gda_value_new (G_TYPE_STRING)), "NONE");
g_value_set_boolean ((false_value = gda_value_new (G_TYPE_BOOLEAN)), FALSE);
g_value_set_int ((zero_value = gda_value_new (G_TYPE_INT)), 0);
+ g_value_set_string ((rule_value = gda_value_new (G_TYPE_STRING)), "NONE");
pragma_set = gda_set_new_inline (1, "tblname", G_TYPE_STRING, "");
}
@@ -418,7 +429,6 @@
if (pAutoinc)
g_value_set_string ((v5 = gda_value_new (G_TYPE_STRING)), "AUTO_INCREMENT");
g_value_set_int (v1, g_value_get_int (v1) + 1);
-
if (pzDataType) {
gchar *tmp = g_strdup (pzDataType);
@@ -467,6 +477,8 @@
return retval;
}
+
+
gboolean
_gda_sqlite_meta_columns (GdaServerProvider *prov, GdaConnection *cnc,
GdaMetaStore *store, GdaMetaContext *context, GError **error,
@@ -491,24 +503,486 @@
return retval;
}
+static gboolean
+fill_constraints_tab_model (GdaConnection *cnc, SqliteConnectionData *cdata, GdaDataModel *mod_model,
+ const GValue *p_table_schema, const GValue *p_table_name, const GValue *constraint_name_n,
+ GError **error)
+{
+ GdaDataModel *tmpmodel;
+ gboolean retval = TRUE;
+ gint nrows;
+ const gchar *schema_name;
+ gint i;
+
+ /*
+ * Setup pragma_set
+ */
+ schema_name = g_value_get_string (p_table_schema);
+ if (strcmp (schema_name, "main")) {
+ gchar *str;
+ str = g_strdup_printf ("%s.%s", schema_name, g_value_get_string (p_table_name));
+ gda_set_set_holder_value (pragma_set, "tblname", str);
+ g_free (str);
+ }
+ else
+ gda_set_set_holder_value (pragma_set, "tblname", g_value_get_string (p_table_name));
+
+
+ /*
+ * PRIMARY KEY
+ *
+ * SQLite only allows 1 primary key to be defined per table.
+ */
+ GType pk_col_types[] = {G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT,
+ G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_NONE};
+ gboolean has_pk = FALSE;
+
+ tmpmodel = gda_connection_statement_execute_select_full (cnc, internal_stmt[I_PRAGMA_TABLE_INFO], pragma_set,
+ GDA_STATEMENT_MODEL_RANDOM_ACCESS,
+ pk_col_types, error);
+ if (!tmpmodel)
+ return FALSE;
+
+ nrows = gda_data_model_get_n_rows (tmpmodel);
+ for (i = 0; i < nrows; i++) {
+ char const *pzDataType; /* Declared data type */
+ char const *pzCollSeq; /* Collation sequence name */
+ int pNotNull; /* True if NOT NULL constraint exists */
+ int pPrimaryKey; /* True if column part of PK */
+ int pAutoinc; /* True if column is auto-increment */
+ const gchar *this_table_name;
+ const gchar *this_col_name;
+ const GValue *this_col_pname;
+
+ this_col_pname = gda_data_model_get_value_at (tmpmodel, 1, i);
+ this_table_name = g_value_get_string (p_table_name);
+ g_assert (this_table_name);
+ if (!strcmp (this_table_name, "sqlite_sequence"))
+ continue; /* ignore that table */
+
+ this_col_name = g_value_get_string (this_col_pname);
+ if (sqlite3_table_column_metadata (cdata->connection, g_value_get_string (p_table_schema),
+ this_table_name, this_col_name,
+ &pzDataType, &pzCollSeq, &pNotNull, &pPrimaryKey, &pAutoinc)
+ != SQLITE_OK)
+ /* may fail because we have a view and not a table => use @tmpmodel to fetch info. */
+ pPrimaryKey = g_value_get_boolean (gda_data_model_get_value_at (tmpmodel, 5, i));
+
+ if (pPrimaryKey) {
+ has_pk = TRUE;
+ break;
+ }
+ }
+
+ if (has_pk) {
+ if (!constraint_name_n || ! strcmp (g_value_get_string (constraint_name_n), "primary_key")) {
+ GValue *v1, *v2;
+ g_value_set_string ((v1 = gda_value_new (G_TYPE_STRING)), "primary_key");
+ g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), "PRIMARY KEY");
+
+ if (! append_a_row (mod_model, error, 10,
+ FALSE, catalog_value, /* constraint_catalog */
+ FALSE, p_table_schema, /* constraint_schema */
+ TRUE, v1, /* constraint_name */
+ FALSE, catalog_value, /* table_catalog */
+ FALSE, p_table_schema, /* table_schema */
+ FALSE, p_table_name, /* table_name */
+ TRUE, v2, /* constraint_type */
+ FALSE, NULL, /* check_clause */
+ FALSE, NULL, /* is_deferrable */
+ FALSE, NULL /* initially_deferred */))
+ retval = FALSE;
+ }
+ }
+
+ g_object_unref (tmpmodel);
+ if (!retval)
+ return FALSE;
+
+ /*
+ * UNIQUE
+ */
+ GType unique_col_types[] = {G_TYPE_INT, G_TYPE_STRING, G_TYPE_INT, G_TYPE_NONE};
+
+ tmpmodel = gda_connection_statement_execute_select_full (cnc, internal_stmt[I_PRAGMA_INDEX_LIST], pragma_set,
+ GDA_STATEMENT_MODEL_RANDOM_ACCESS,
+ unique_col_types, error);
+ if (!tmpmodel)
+ return FALSE;
+
+ nrows = gda_data_model_get_n_rows (tmpmodel);
+ for (i = 0; i < nrows; i++) {
+ const GValue *cvalue;
+ GValue *v2;
+
+ cvalue = gda_data_model_get_value_at (tmpmodel, 2, i);
+ if (!g_value_get_int (cvalue))
+ continue;
+
+ cvalue = gda_data_model_get_value_at (tmpmodel, 1, i);
+ if (constraint_name_n && strcmp (g_value_get_string (constraint_name_n), g_value_get_string (cvalue)))
+ continue;
+
+ g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), "UNIQUE");
+
+ if (! append_a_row (mod_model, error, 10,
+ FALSE, catalog_value, /* constraint_catalog */
+ FALSE, p_table_schema, /* constraint_schema */
+ FALSE, cvalue, /* constraint_name */
+ FALSE, catalog_value, /* table_catalog */
+ FALSE, p_table_schema, /* table_schema */
+ FALSE, p_table_name, /* table_name */
+ TRUE, v2, /* constraint_type */
+ FALSE, NULL, /* check_clause */
+ FALSE, NULL, /* is_deferrable */
+ FALSE, NULL /* initially_deferred */))
+ retval = FALSE;
+ }
+ g_object_unref (tmpmodel);
+ if (!retval)
+ return FALSE;
+
+ /*
+ * FOREIGN KEYS
+ */
+ GType fk_col_types[] = {G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_NONE};
+ gchar *ref_table = NULL;
+ tmpmodel = gda_connection_statement_execute_select_full (cnc, internal_stmt[I_PRAGMA_FK_LIST], pragma_set,
+ GDA_STATEMENT_MODEL_RANDOM_ACCESS,
+ fk_col_types, error);
+ if (!tmpmodel)
+ return FALSE;
+
+ nrows = gda_data_model_get_n_rows (tmpmodel);
+ for (i = 0; i < nrows; i++) {
+ const GValue *cvalue;
+
+ cvalue = gda_data_model_get_value_at (tmpmodel, 2, i);
+ if (! ref_table || strcmp (ref_table, g_value_get_string (cvalue))) {
+ gchar *constname;
+ GValue *v1, *v2;
+
+ g_free (ref_table);
+ ref_table = g_strdup (g_value_get_string (cvalue));
+ constname = g_strdup_printf ("fk_%s", ref_table);
+ if (constraint_name_n && strcmp (g_value_get_string (constraint_name_n), constname)) {
+ g_free (constname);
+ continue;
+ }
+
+ g_value_take_string ((v1 = gda_value_new (G_TYPE_STRING)), constname);
+ g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), "FOREIGN KEY");
+
+ if (! append_a_row (mod_model, error, 10,
+ FALSE, catalog_value, /* constraint_catalog */
+ FALSE, p_table_schema, /* constraint_schema */
+ TRUE, v1, /* constraint_name */
+ FALSE, catalog_value, /* table_catalog */
+ FALSE, p_table_schema, /* table_schema */
+ FALSE, p_table_name, /* table_name */
+ TRUE, v2, /* constraint_type */
+ FALSE, NULL, /* check_clause */
+ FALSE, NULL, /* is_deferrable */
+ FALSE, NULL /* initially_deferred */))
+ retval = FALSE;
+ }
+ }
+ g_free (ref_table);
+ g_object_unref (tmpmodel);
+
+ /*
+ * CHECK constraint
+ * FIXME: how to get that information?
+ */
+
+ return retval;
+}
+
gboolean
_gda_sqlite_meta_constraints_tab (GdaServerProvider *prov, GdaConnection *cnc,
GdaMetaStore *store, GdaMetaContext *context, GError **error,
const GValue *table_catalog, const GValue *table_schema, const GValue *table_name,
const GValue *constraint_name_n)
{
- /* not implemented in SQLite */
- return TRUE;
+ gboolean retval = TRUE;
+ GdaDataModel *mod_model = NULL;
+ SqliteConnectionData *cdata;
+
+ cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
+ return FALSE;
+
+ mod_model = gda_meta_store_create_modify_data_model (store, context->table_name);
+ g_assert (mod_model);
+
+ retval = fill_constraints_tab_model (cnc, cdata, mod_model, table_schema, table_name, constraint_name_n, error);
+ if (retval)
+ retval = gda_meta_store_modify_with_context (store, context, mod_model, error);
+ g_object_unref (mod_model);
+
+ return retval;
+}
+
+static gboolean
+fill_constraints_ref_model (GdaConnection *cnc, SqliteConnectionData *cdata, GdaDataModel *mod_model,
+ const GValue *p_table_schema, const GValue *p_table_name, const GValue *constraint_name,
+ GError **error)
+{
+ GdaDataModel *tmpmodel;
+ gboolean retval = TRUE;
+ gint nrows;
+ const gchar *schema_name;
+ gint i;
+
+ /*
+ * Setup pragma_set
+ */
+ schema_name = g_value_get_string (p_table_schema);
+ if (strcmp (schema_name, "main")) {
+ gchar *str;
+ str = g_strdup_printf ("%s.%s", schema_name, g_value_get_string (p_table_name));
+ gda_set_set_holder_value (pragma_set, "tblname", str);
+ g_free (str);
+ }
+ else
+ gda_set_set_holder_value (pragma_set, "tblname", g_value_get_string (p_table_name));
+
+ GType fk_col_types[] = {G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_NONE};
+ gchar *ref_table = NULL;
+ tmpmodel = gda_connection_statement_execute_select_full (cnc, internal_stmt[I_PRAGMA_FK_LIST], pragma_set,
+ GDA_STATEMENT_MODEL_RANDOM_ACCESS,
+ fk_col_types, error);
+ if (!tmpmodel)
+ return FALSE;
+
+ nrows = gda_data_model_get_n_rows (tmpmodel);
+ for (i = 0; i < nrows; i++) {
+ const GValue *cvalue;
+
+ cvalue = gda_data_model_get_value_at (tmpmodel, 2, i);
+ if (! ref_table || strcmp (ref_table, g_value_get_string (cvalue))) {
+ gchar *constname;
+ GValue *v2, *v3, *v4;
+
+ g_free (ref_table);
+ ref_table = g_strdup (g_value_get_string (cvalue));
+ constname = g_strdup_printf ("fk_%s", ref_table);
+ if (strcmp (g_value_get_string (constraint_name), constname)) {
+ g_free (constname);
+ continue;
+ }
+
+ g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), "FOREIGN KEY");
+ g_value_set_string ((v3 = gda_value_new (G_TYPE_STRING)), ref_table);
+ g_value_set_string ((v4 = gda_value_new (G_TYPE_STRING)), "primary_key");
+
+ if (! append_a_row (mod_model, error, 11,
+ FALSE, catalog_value, /* table_catalog */
+ FALSE, p_table_schema, /* table_schema */
+ FALSE, p_table_name, /* table_name */
+ FALSE, constraint_name, /* constraint_name */
+ FALSE, catalog_value, /* ref_table_catalog */
+ FALSE, p_table_schema, /* ref_table_schema */
+ TRUE, v3, /* ref_table_name */
+ TRUE, v4, /* ref_constraint_name */
+ FALSE, NULL, /* match_option */
+ FALSE, rule_value, /* update_rule */
+ FALSE, rule_value /* delete_rule */))
+ retval = FALSE;
+ }
+ }
+ g_free (ref_table);
+ g_object_unref (tmpmodel);
+
+ return retval;
}
+
gboolean
_gda_sqlite_meta_constraints_ref (GdaServerProvider *prov, GdaConnection *cnc,
GdaMetaStore *store, GdaMetaContext *context, GError **error,
const GValue *table_catalog, const GValue *table_schema, const GValue *table_name,
const GValue *constraint_name)
{
- /* not implemented in SQLite */
- return TRUE;
+ gboolean retval = TRUE;
+ GdaDataModel *mod_model = NULL;
+ SqliteConnectionData *cdata;
+
+ cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
+ return FALSE;
+
+ mod_model = gda_meta_store_create_modify_data_model (store, context->table_name);
+ g_assert (mod_model);
+
+ retval = fill_constraints_ref_model (cnc, cdata, mod_model, table_schema, table_name, constraint_name, error);
+ if (retval)
+ retval = gda_meta_store_modify_with_context (store, context, mod_model, error);
+ g_object_unref (mod_model);
+
+ return retval;
+}
+
+static gboolean
+fill_key_columns_model (GdaConnection *cnc, SqliteConnectionData *cdata, GdaDataModel *mod_model,
+ const GValue *p_table_schema, const GValue *p_table_name, const GValue *constraint_name,
+ GError **error)
+{
+ GdaDataModel *tmpmodel;
+ gboolean retval = TRUE;
+ gint nrows;
+ const gchar *schema_name, *const_name;
+ gint i;
+
+ /*
+ * Setup pragma_set
+ */
+ schema_name = g_value_get_string (p_table_schema);
+ if (strcmp (schema_name, "main")) {
+ gchar *str;
+ str = g_strdup_printf ("%s.%s", schema_name, g_value_get_string (p_table_name));
+ gda_set_set_holder_value (pragma_set, "tblname", str);
+ g_free (str);
+ }
+ else
+ gda_set_set_holder_value (pragma_set, "tblname", g_value_get_string (p_table_name));
+
+ const_name = g_value_get_string (constraint_name);
+ if (!strcmp (const_name, "primary_key")) {
+ /*
+ * PRIMARY KEY columns
+ */
+ GType pk_col_types[] = {G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT,
+ G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_NONE};
+ gint ord_pos = 1;
+ tmpmodel = gda_connection_statement_execute_select_full (cnc, internal_stmt[I_PRAGMA_TABLE_INFO], pragma_set,
+ GDA_STATEMENT_MODEL_RANDOM_ACCESS,
+ pk_col_types, error);
+ if (!tmpmodel)
+ return FALSE;
+
+ nrows = gda_data_model_get_n_rows (tmpmodel);
+ for (i = 0; i < nrows; i++) {
+ char const *pzDataType; /* Declared data type */
+ char const *pzCollSeq; /* Collation sequence name */
+ int pNotNull; /* True if NOT NULL constraint exists */
+ int pPrimaryKey; /* True if column part of PK */
+ int pAutoinc; /* True if column is auto-increment */
+ const gchar *this_table_name;
+ const gchar *this_col_name;
+ const GValue *this_col_pname;
+ GValue *v1;
+
+ this_col_pname = gda_data_model_get_value_at (tmpmodel, 1, i);
+ this_table_name = g_value_get_string (p_table_name);
+ g_assert (this_table_name);
+ if (!strcmp (this_table_name, "sqlite_sequence"))
+ continue; /* ignore that table */
+
+ this_col_name = g_value_get_string (this_col_pname);
+ if (sqlite3_table_column_metadata (cdata->connection, g_value_get_string (p_table_schema),
+ this_table_name, this_col_name,
+ &pzDataType, &pzCollSeq, &pNotNull, &pPrimaryKey, &pAutoinc)
+ != SQLITE_OK)
+ /* may fail because we have a view and not a table => use @tmpmodel to fetch info. */
+ pPrimaryKey = g_value_get_boolean (gda_data_model_get_value_at (tmpmodel, 5, i));
+ if (pPrimaryKey) {
+ g_value_set_int ((v1 = gda_value_new (G_TYPE_INT)), ord_pos++);
+ if (! append_a_row (mod_model, error, 6,
+ FALSE, catalog_value, /* table_catalog */
+ FALSE, p_table_schema, /* table_schema */
+ FALSE, p_table_name, /* table_name */
+ FALSE, constraint_name, /* constraint_name */
+ FALSE, gda_data_model_get_value_at (tmpmodel, 1, i), /* column_name */
+ TRUE, v1 /* ordinal_position */)) {
+ retval = FALSE;
+ break;
+ }
+ }
+ }
+ g_object_unref (tmpmodel);
+ }
+ else if ((*const_name == 'f') && (const_name[1] == 'k') && (const_name[2] == '_')) {
+ /*
+ * FOREIGN key columns
+ */
+ GType fk_col_types[] = {G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_NONE};
+ gchar *ref_table = NULL;
+ gint ord_pos;
+ tmpmodel = gda_connection_statement_execute_select_full (cnc, internal_stmt[I_PRAGMA_FK_LIST], pragma_set,
+ GDA_STATEMENT_MODEL_RANDOM_ACCESS,
+ fk_col_types, error);
+ if (!tmpmodel)
+ return FALSE;
+
+ nrows = gda_data_model_get_n_rows (tmpmodel);
+ for (i = 0; i < nrows; i++) {
+ const GValue *cvalue;
+ GValue *v1;
+
+ cvalue = gda_data_model_get_value_at (tmpmodel, 2, i);
+ if (! ref_table || strcmp (ref_table, g_value_get_string (cvalue))) {
+ gchar *constname;
+
+ g_free (ref_table);
+ ref_table = g_strdup (g_value_get_string (cvalue));
+ constname = g_strdup_printf ("fk_%s", ref_table);
+ if (strcmp (g_value_get_string (constraint_name), constname)) {
+ g_free (constname);
+ g_free (ref_table);
+ ref_table = NULL;
+ continue;
+ }
+ ord_pos = 1;
+ }
+
+ g_value_set_int ((v1 = gda_value_new (G_TYPE_INT)), ord_pos++);
+ if (! append_a_row (mod_model, error, 6,
+ FALSE, catalog_value, /* table_catalog */
+ FALSE, p_table_schema, /* table_schema */
+ FALSE, p_table_name, /* table_name */
+ FALSE, constraint_name, /* constraint_name */
+ FALSE, gda_data_model_get_value_at (tmpmodel, 3, i), /* column_name */
+ TRUE, v1 /* ordinal_position */))
+ retval = FALSE;
+ }
+
+ g_free (ref_table);
+ g_object_unref (tmpmodel);
+ }
+ else {
+ /*
+ * UNIQUE columns
+ */
+ TO_IMPLEMENT;
+ }
+
+ return retval;
+}
+
+gboolean
+_gda_sqlite_meta_key_columns (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *table_catalog, const GValue *table_schema, const GValue *table_name,
+ const GValue *constraint_name)
+{
+ gboolean retval = TRUE;
+ GdaDataModel *mod_model = NULL;
+ SqliteConnectionData *cdata;
+
+ cdata = (SqliteConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
+ return FALSE;
+
+ mod_model = gda_meta_store_create_modify_data_model (store, context->table_name);
+ g_assert (mod_model);
+
+ retval = fill_key_columns_model (cnc, cdata, mod_model, table_schema, table_name, constraint_name, error);
+ if (retval)
+ retval = gda_meta_store_modify_with_context (store, context, mod_model, error);
+ g_object_unref (mod_model);
+
+ return retval;
}
Modified: trunk/libgda/sqlite/gda-sqlite-meta.h
==============================================================================
--- trunk/libgda/sqlite/gda-sqlite-meta.h (original)
+++ trunk/libgda/sqlite/gda-sqlite-meta.h Mon Mar 17 19:34:20 2008
@@ -43,6 +43,9 @@
gboolean _gda_sqlite_meta_constraints_ref (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **,
const GValue *table_catalog, const GValue *table_schema, const GValue *table_name,
const GValue *constraint_name);
+gboolean _gda_sqlite_meta_key_columns (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **,
+ const GValue *table_catalog, const GValue *table_schema, const GValue *table_name,
+ const GValue *constraint_name);
G_END_DECLS
#endif
Modified: trunk/libgda/sqlite/gda-sqlite-provider.c
==============================================================================
--- trunk/libgda/sqlite/gda-sqlite-provider.c (original)
+++ trunk/libgda/sqlite/gda-sqlite-provider.c Mon Mar 17 19:34:20 2008
@@ -147,7 +147,7 @@
/*
* Prepared internal statements
*/
-GdaStatement **internal_stmt;
+static GdaStatement **internal_stmt;
typedef enum {
INTERNAL_PRAGMA_INDEX_LIST,
@@ -234,6 +234,7 @@
provider_class->meta_funcs.columns = _gda_sqlite_meta_columns;
provider_class->meta_funcs.constraints_tab = _gda_sqlite_meta_constraints_tab;
provider_class->meta_funcs.constraints_ref = _gda_sqlite_meta_constraints_ref;
+ provider_class->meta_funcs.key_columns = _gda_sqlite_meta_key_columns;
}
static void
Modified: trunk/po/POTFILES.skip
==============================================================================
--- trunk/po/POTFILES.skip (original)
+++ trunk/po/POTFILES.skip Mon Mar 17 19:34:20 2008
@@ -1,7 +1,4 @@
-libgda/sql-parser/delimiter.c
-libgda/sql-parser/parser.c
libgda/sqlite/sqlite-src/sqlite3.c
-providers/postgres/parser.c
providers/skel-implementation/capi/capi_specs_create_table.xml.in
providers/skel-implementation/capi/capi_specs_dsn.xml.in
providers/skel-implementation/capi/gda-capi-blob-op.c
Modified: trunk/providers/postgres/gda-postgres-meta.c
==============================================================================
--- trunk/providers/postgres/gda-postgres-meta.c (original)
+++ trunk/providers/postgres/gda-postgres-meta.c Mon Mar 17 19:34:20 2008
@@ -50,7 +50,8 @@
I_STMT_COLUMNS_OF_TABLE,
I_STMT_TABLES_CONSTRAINTS,
I_STMT_TABLES_CONSTRAINT_NAMED,
- I_STMT_REF_CONSTRAINTS
+ I_STMT_REF_CONSTRAINTS,
+ I_STMT_KEY_COLUMN_USAGE
} InternalStatementItem;
@@ -92,7 +93,10 @@
"SELECT constraint_catalog, constraint_schema, constraint_name, table_catalog, table_schema, table_name, constraint_type, NULL, CASE WHEN is_deferrable = 'YES' THEN TRUE ELSE FALSE END, CASE WHEN initially_deferred = 'YES' THEN TRUE ELSE FALSE END FROM information_schema.table_constraints WHERE table_catalog = ##cat::string AND table_schema = ##schema::string AND table_name = ##name::string AND constraint_name = ##name2::string",
/* I_STMT_REF_CONSTRAINTS */
- " SELECT current_database(), nt.nspname, t.relname, c.conname, current_database(), nref.nspname, ref.relname, pkc.conname, CASE c.confmatchtype WHEN 'f'::\"char\" THEN 'FULL'::text WHEN 'p'::\"char\" THEN 'PARTIAL'::text WHEN 'u'::\"char\" THEN 'NONE'::text ELSE NULL::text END AS match_option, CASE c.confupdtype WHEN 'c'::\"char\" THEN 'CASCADE'::text WHEN 'n'::\"char\" THEN 'SET NULL'::text WHEN 'd'::\"char\" THEN 'SET DEFAULT'::text WHEN 'r'::\"char\" THEN 'RESTRICT'::text WHEN 'a'::\"char\" THEN 'NO ACTION'::text ELSE NULL::text END AS update_rule, CASE c.confdeltype WHEN 'c'::\"char\" THEN 'CASCADE'::text WHEN 'n'::\"char\" THEN 'SET NULL'::text WHEN 'd'::\"char\" THEN 'SET DEFAULT'::text WHEN 'r'::\"char\" THEN 'RESTRICT'::text WHEN 'a'::\"char\" THEN 'NO ACTION'::text ELSE NULL::text END AS delete_rule FROM pg_constraint c INNER JOIN pg_class t ON (c.conrelid=t.oid) INNER JOIN pg_namespace nt ON (nt.oid=t.relnamespace) INNER JOIN pg_class ref ON (c.confrelid=ref.oid)
INNER JOIN pg_namespace nref ON (nref.oid=ref.relnamespace) INNER JOIN pg_constraint pkc ON (c.confrelid = pkc.conrelid AND information_schema._pg_keysequal(c.confkey, pkc.conkey)) WHERE c.contype = 'f' AND current_database() = ##cat::string AND nt.nspname = ##schema::string AND t.relname = ##name::string AND c.conname = ##name2::string"
+ "SELECT current_database(), nt.nspname, t.relname, c.conname, current_database(), nref.nspname, ref.relname, pkc.conname, CASE c.confmatchtype WHEN 'f'::\"char\" THEN 'FULL'::text WHEN 'p'::\"char\" THEN 'PARTIAL'::text WHEN 'u'::\"char\" THEN 'NONE'::text ELSE NULL::text END AS match_option, CASE c.confupdtype WHEN 'c'::\"char\" THEN 'CASCADE'::text WHEN 'n'::\"char\" THEN 'SET NULL'::text WHEN 'd'::\"char\" THEN 'SET DEFAULT'::text WHEN 'r'::\"char\" THEN 'RESTRICT'::text WHEN 'a'::\"char\" THEN 'NO ACTION'::text ELSE NULL::text END AS update_rule, CASE c.confdeltype WHEN 'c'::\"char\" THEN 'CASCADE'::text WHEN 'n'::\"char\" THEN 'SET NULL'::text WHEN 'd'::\"char\" THEN 'SET DEFAULT'::text WHEN 'r'::\"char\" THEN 'RESTRICT'::text WHEN 'a'::\"char\" THEN 'NO ACTION'::text ELSE NULL::text END AS delete_rule FROM pg_constraint c INNER JOIN pg_class t ON (c.conrelid=t.oid) INNER JOIN pg_namespace nt ON (nt.oid=t.relnamespace) INNER JOIN pg_class ref ON (c.confrelid=ref.oid) I
NNER JOIN pg_namespace nref ON (nref.oid=ref.relnamespace) INNER JOIN pg_constraint pkc ON (c.confrelid = pkc.conrelid AND information_schema._pg_keysequal(c.confkey, pkc.conkey)) WHERE c.contype = 'f' AND current_database() = ##cat::string AND nt.nspname = ##schema::string AND t.relname = ##name::string AND c.conname = ##name2::string",
+
+ /* I_STMT_KEY_COLUMN_USAGE */
+ "SELECT table_catalog, table_schema, table_name, constraint_name, column_name, ordinal_position FROM information_schema.key_column_usage WHERE table_catalog = ##cat::string AND table_schema = ##schema::string AND table_name = ##name::string AND constraint_name = ##name2::string"
};
/*
@@ -422,3 +426,37 @@
return retval;
}
+gboolean
+_gda_postgres_meta_key_columns (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *table_catalog, const GValue *table_schema, const GValue *table_name,
+ const GValue *constraint_name)
+{
+ GdaDataModel *model;
+ gboolean retval = TRUE;
+ PostgresConnectionData *cdata;
+
+ cdata = (PostgresConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
+ return FALSE;
+
+ gda_holder_set_value (gda_set_get_holder (i_set, "cat"), table_catalog);
+ gda_holder_set_value (gda_set_get_holder (i_set, "schema"), table_schema);
+ gda_holder_set_value (gda_set_get_holder (i_set, "name"), table_name);
+ gda_holder_set_value (gda_set_get_holder (i_set, "name2"), constraint_name);
+ model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_KEY_COLUMN_USAGE], i_set,
+ error);
+ if (!model)
+ return FALSE;
+
+
+ /* modify meta store */
+ if (retval)
+ 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;
+}
Modified: trunk/providers/postgres/gda-postgres-meta.h
==============================================================================
--- trunk/providers/postgres/gda-postgres-meta.h (original)
+++ trunk/providers/postgres/gda-postgres-meta.h Mon Mar 17 19:34:20 2008
@@ -43,7 +43,9 @@
gboolean _gda_postgres_meta_constraints_ref (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **,
const GValue *table_catalog, const GValue *table_schema, const GValue *table_name,
const GValue *constraint_name);
-
+gboolean _gda_postgres_meta_key_columns (GdaServerProvider *, GdaConnection *, GdaMetaStore *, GdaMetaContext *, GError **,
+ const GValue *table_catalog, const GValue *table_schema, const GValue *table_name,
+ const GValue *constraint_name);
G_END_DECLS
Modified: trunk/providers/postgres/gda-postgres-provider.c
==============================================================================
--- trunk/providers/postgres/gda-postgres-provider.c (original)
+++ trunk/providers/postgres/gda-postgres-provider.c Mon Mar 17 19:34:20 2008
@@ -192,6 +192,7 @@
provider_class->meta_funcs.columns = _gda_postgres_meta_columns;
provider_class->meta_funcs.constraints_tab = _gda_postgres_meta_constraints_tab;
provider_class->meta_funcs.constraints_ref = _gda_postgres_meta_constraints_ref;
+ provider_class->meta_funcs.key_columns = _gda_postgres_meta_key_columns;
}
static void
Modified: trunk/tests/providers/prov-test-common.c
==============================================================================
--- trunk/tests/providers/prov-test-common.c (original)
+++ trunk/tests/providers/prov-test-common.c Mon Mar 17 19:34:20 2008
@@ -91,7 +91,7 @@
/* dump all tables */
store = gda_connection_get_meta_store (cnc);
- tables = gda_meta_store_schema_get_tables (store);
+ tables = gda_meta_store_schema_get_all_tables (store);
ntables = g_slist_length (tables);
dump1 = g_new0 (gchar *, ntables + 1);
Modified: trunk/tools/command-exec.c
==============================================================================
--- trunk/tools/command-exec.c (original)
+++ trunk/tools/command-exec.c Mon Mar 17 19:34:20 2008
@@ -716,75 +716,161 @@
res->u.model = model;
return res;
}
+ else if (nb_objects == 0) {
+ g_set_error (error, 0, 0, _("No object found"));
+ return NULL;
+ }
+ /*
+ * Information about a single object
+ */
res = g_new0 (GdaInternalCommandResult, 1);
res->type = GDA_INTERNAL_COMMAND_RESULT_MULTIPLE;
res->u.multiple_results = NULL;
+ GdaMetaDbObject *dbo;
for (dbo_list = mstruct->db_objects; dbo_list; dbo_list = dbo_list->next) {
- GdaMetaDbObject *dbo = GDA_META_DB_OBJECT (dbo_list->data);
- GdaInternalCommandResult *subres;
-
- switch (dbo->obj_type) {
- case GDA_META_DB_UNKNOWN:
+ dbo = GDA_META_DB_OBJECT (dbo_list->data);
+ if (dbo->obj_type == GDA_META_DB_UNKNOWN)
+ dbo = NULL;
+ else
break;
- case GDA_META_DB_VIEW:
- case GDA_META_DB_TABLE: {
- GdaMetaTable *mt = GDA_META_DB_OBJECT_GET_TABLE (dbo);
- GSList *list;
-
- model = gda_data_model_array_new (4);
- gda_data_model_set_column_title (model, 0, _("Column"));
- gda_data_model_set_column_title (model, 1, _("Type"));
- gda_data_model_set_column_title (model, 2, _("Nullable"));
- gda_data_model_set_column_title (model, 3, _("Default"));
- if (dbo->obj_type == GDA_META_DB_VIEW)
- g_object_set_data_full (G_OBJECT (model), "name",
- g_strdup_printf (_("List of columns for view '%s'"),
- dbo->obj_short_name), g_free);
- else
- g_object_set_data_full (G_OBJECT (model), "name",
- g_strdup_printf (_("List of columns for table '%s'"),
- dbo->obj_short_name), g_free);
- for (list = mt->columns; list; list = list->next) {
- GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data);
- GList *values = NULL;
- GValue *val;
-
- g_value_set_string ((val = gda_value_new (G_TYPE_STRING)), tcol->column_name);
- values = g_list_append (values, val);
- g_value_set_string ((val = gda_value_new (G_TYPE_STRING)), tcol->column_type);
- values = g_list_append (values, val);
- g_value_set_string ((val = gda_value_new (G_TYPE_STRING)), tcol->nullok ? _("yes") : _("no"));
- values = g_list_append (values, val);
- g_value_set_string ((val = gda_value_new (G_TYPE_STRING)), tcol->default_value);
- values = g_list_append (values, val);
- gda_data_model_append_values (model, values, NULL);
- g_list_foreach (values, (GFunc) gda_value_free, NULL);
- g_list_free (values);
- }
+ }
+ g_assert (dbo);
+
+ if ((dbo->obj_type == GDA_META_DB_VIEW) || (dbo->obj_type == GDA_META_DB_TABLE)) {
+ GdaInternalCommandResult *subres;
+ GdaMetaTable *mt = GDA_META_DB_OBJECT_GET_TABLE (dbo);
+ GSList *list;
+ model = gda_data_model_array_new (4);
+ gda_data_model_set_column_title (model, 0, _("Column"));
+ gda_data_model_set_column_title (model, 1, _("Type"));
+ gda_data_model_set_column_title (model, 2, _("Nullable"));
+ gda_data_model_set_column_title (model, 3, _("Default"));
+ if (dbo->obj_type == GDA_META_DB_VIEW)
+ g_object_set_data_full (G_OBJECT (model), "name",
+ g_strdup_printf (_("List of columns for view '%s'"),
+ dbo->obj_short_name), g_free);
+ else
+ g_object_set_data_full (G_OBJECT (model), "name",
+ g_strdup_printf (_("List of columns for table '%s'"),
+ dbo->obj_short_name), g_free);
+ for (list = mt->columns; list; list = list->next) {
+ GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data);
+ GList *values = NULL;
+ GValue *val;
+
+ g_value_set_string ((val = gda_value_new (G_TYPE_STRING)), tcol->column_name);
+ values = g_list_append (values, val);
+ g_value_set_string ((val = gda_value_new (G_TYPE_STRING)), tcol->column_type);
+ values = g_list_append (values, val);
+ g_value_set_string ((val = gda_value_new (G_TYPE_STRING)), tcol->nullok ? _("yes") : _("no"));
+ values = g_list_append (values, val);
+ g_value_set_string ((val = gda_value_new (G_TYPE_STRING)), tcol->default_value);
+ values = g_list_append (values, val);
+ gda_data_model_append_values (model, values, NULL);
+ g_list_foreach (values, (GFunc) gda_value_free, NULL);
+ g_list_free (values);
+ }
+
+ subres = g_new0 (GdaInternalCommandResult, 1);
+ subres->type = GDA_INTERNAL_COMMAND_RESULT_DATA_MODEL;
+ subres->u.model = model;
+ res->u.multiple_results = g_slist_append (res->u.multiple_results, subres);
+
+ if (dbo->obj_type == GDA_META_DB_VIEW) {
+ /* VIEW specific */
+ GdaMetaView *mv = GDA_META_DB_OBJECT_GET_VIEW (dbo);
+
subres = g_new0 (GdaInternalCommandResult, 1);
- subres->type = GDA_INTERNAL_COMMAND_RESULT_DATA_MODEL;
- subres->u.model = model;
+ subres->type = GDA_INTERNAL_COMMAND_RESULT_TXT;
+ subres->u.txt = g_string_new ("");
+ g_string_append_printf (subres->u.txt, _("View definition: %s"), mv->view_def);
res->u.multiple_results = g_slist_append (res->u.multiple_results, subres);
-
- if (dbo->obj_type == GDA_META_DB_VIEW) {
- GdaMetaView *mv = GDA_META_DB_OBJECT_GET_VIEW (dbo);
-
- subres = g_new0 (GdaInternalCommandResult, 1);
- subres->type = GDA_INTERNAL_COMMAND_RESULT_TXT;
- subres->u.txt = g_string_new ("");
- g_string_append_printf (subres->u.txt, _("View definition: %s"), mv->view_def);
- res->u.multiple_results = g_slist_append (res->u.multiple_results, subres);
- }
- break;
}
- default:
- TO_IMPLEMENT;
- break;
+ else {
+ /* TABLE specific */
+ GValue *catalog, *schema, *name;
+ gint i, nrows;
+ const gchar *sql = "SELECT constraint_type, constraint_name "
+ "FROM _table_constraints WHERE table_catalog = ##tc::string "
+ "AND table_schema = ##ts::string AND table_name = ##tname::string "
+ "ORDER BY constraint_type, constraint_name";
+
+ g_value_set_string ((catalog = gda_value_new (G_TYPE_STRING)), dbo->obj_catalog);
+ g_value_set_string ((schema = gda_value_new (G_TYPE_STRING)), dbo->obj_schema);
+ g_value_set_string ((name = gda_value_new (G_TYPE_STRING)), dbo->obj_name);
+ model = gda_meta_store_extract (gda_connection_get_meta_store (cnc), sql, error,
+ "tc", catalog, "ts", schema, "tname", name, NULL);
+ nrows = gda_data_model_get_n_rows (model);
+ for (i = 0; i < nrows; i++) {
+ GString *string = NULL;
+ const GValue *cvalue;
+ const gchar *str;
+
+ cvalue = gda_data_model_get_value_at (model, 0, i);
+ str = g_value_get_string (cvalue);
+ if (*str == 'P') {
+ /* primary key */
+ GdaDataModel *cols;
+ cvalue = gda_data_model_get_value_at (model, 1, i);
+ string = g_string_new ("Primary key ");
+ g_string_append_printf (string, "'%s'", g_value_get_string (cvalue));
+ str = "SELECT column_name, ordinal_position "
+ "FROM _key_column_usage WHERE table_catalog = ##tc::string "
+ "AND table_schema = ##ts::string AND table_name = ##tname::string AND "
+ "constraint_name = ##cname::string "
+ "ORDER BY ordinal_position";
+
+ cols = gda_meta_store_extract (gda_connection_get_meta_store (cnc), str, error,
+ "tc", catalog, "ts", schema, "tname", name, "cname", cvalue,
+ NULL);
+ if (cols) {
+ gint j, cnrows;
+ cnrows = gda_data_model_get_n_rows (cols);
+ for (j = 0; j < cnrows; j++) {
+ if (j == 0)
+ g_string_append (string, ": ");
+ else
+ g_string_append (string, ", ");
+ g_string_append (string,
+ g_value_get_string (gda_data_model_get_value_at (cols, 0, j)));
+ }
+ g_object_unref (cols);
+ }
+ }
+ else if (*str == 'F') {
+ /* foreign key */
+ cvalue = gda_data_model_get_value_at (model, 1, i);
+ string = g_string_new ("Foreign key ");
+ g_string_append_printf (string, "'%s'", g_value_get_string (cvalue));
+ }
+ else if (*str == 'U') {
+ /* Unique constraint */
+ cvalue = gda_data_model_get_value_at (model, 1, i);
+ string = g_string_new ("Unique ");
+ g_string_append_printf (string, "'%s'", g_value_get_string (cvalue));
+ }
+
+ if (string) {
+ subres = g_new0 (GdaInternalCommandResult, 1);
+ subres->type = GDA_INTERNAL_COMMAND_RESULT_TXT;
+ subres->u.txt = string;
+ res->u.multiple_results = g_slist_append (res->u.multiple_results, subres);
+ }
+ }
+
+ gda_value_free (catalog);
+ gda_value_free (schema);
+ gda_value_free (name);
+
+ g_object_unref (model);
+ return res;
}
}
+ else
+ TO_IMPLEMENT;
g_object_unref (mstruct);
return res;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]