1 /*
2  * Copyright (C) 2008 - 2010 Murray Cumming <murrayc@murrayc.com>
3  * Copyright (C) 2008 - 2012 Vivien Malerba <malerba@gnome-db.org>
4  * Copyright (C) 2009 Bas Driessen <bas.driessen@xobas.com>
5  * Copyright (C) 2010 David King <davidk@openismus.com>
6  * Copyright (C) 2010 Jonh Wendell <jwendell@gnome.org>
7  * Copyright (C) 2012 Daniel Espinosa <despinosa@src.gnome.org>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22  * Boston, MA  02110-1301, USA.
23  */
24 
25 #include <string.h>
26 #include <glib/gi18n-lib.h>
27 #include <libgda/gda-meta-struct.h>
28 #include <libgda/gda-util.h>
29 #include <sql-parser/gda-sql-parser.h>
30 #include <sql-parser/gda-sql-statement.h>
31 #include <sql-parser/gda-statement-struct-util.h>
32 #include <libgda/gda-attributes-manager.h>
33 #include <libgda/gda-debug-macros.h>
34 
35 /*
36  * Main static functions
37  */
38 static void gda_meta_struct_class_init (GdaMetaStructClass *klass);
39 static void gda_meta_struct_init (GdaMetaStruct *mstruct);
40 static void gda_meta_struct_dispose (GObject *object);
41 static void gda_meta_struct_finalize (GObject *object);
42 
43 static void gda_meta_struct_set_property (GObject *object,
44                                          guint param_id,
45                                          const GValue *value,
46                                          GParamSpec *pspec);
47 static void gda_meta_struct_get_property (GObject *object,
48                                          guint param_id,
49                                          GValue *value,
50                                          GParamSpec *pspec);
51 
52 
53 static void meta_store_changed_cb (GdaMetaStore *store, GSList *changes, GdaMetaStruct *mstruct);
54 static void meta_store_reset_cb (GdaMetaStore *store, GdaMetaStruct *mstruct);
55 
56 struct _GdaMetaStructPrivate {
57 	GdaMetaStore *store;
58 	GSList       *db_objects; /* list of GdaMetaDbObject structures */
59 	GHashTable   *index; /* key = [catalog].[schema].[name], value = a GdaMetaDbObject. Note: catalog, schema and name
60 			      * are case sensitive (and don't have any double quote around them) */
61 	guint         features;
62 };
63 
64 static GdaMetaDbObject *_meta_struct_get_db_object (GdaMetaStruct *mstruct,
65 						    const GValue *catalog, const GValue *schema, const GValue *name);
66 
67 static void gda_meta_db_object_free (GdaMetaDbObject *dbo);
68 static void gda_meta_db_object_free_contents (GdaMetaDbObject *dbo);
69 static void gda_meta_table_free_contents (GdaMetaTable *table);
70 static void gda_meta_view_free_contents (GdaMetaView *view);
71 static void gda_meta_table_column_free (GdaMetaTableColumn *tcol);
72 static void gda_meta_table_foreign_key_free (GdaMetaTableForeignKey *tfk);
73 
74 /* get a pointer to the parents to be able to call their destructor */
75 static GObjectClass  *parent_class = NULL;
76 static GdaAttributesManager *att_mgr;
77 
78 /* properties */
79 enum {
80         PROP_0,
81 	PROP_STORE,
82         PROP_FEATURES
83 };
84 
85 /* module error */
gda_meta_struct_error_quark(void)86 GQuark gda_meta_struct_error_quark (void) {
87 	static GQuark quark;
88 	if (!quark)
89 		quark = g_quark_from_static_string ("gda_meta_struct_error");
90 	return quark;
91 }
92 
93 GType
gda_meta_struct_get_type(void)94 gda_meta_struct_get_type (void) {
95 	static GType type = 0;
96 
97 	if (G_UNLIKELY (type == 0)) {
98 		static GMutex registering;
99 		static const GTypeInfo info = {
100 			sizeof (GdaMetaStructClass),
101 			(GBaseInitFunc) NULL,
102 			(GBaseFinalizeFunc) NULL,
103 			(GClassInitFunc) gda_meta_struct_class_init,
104 			NULL,
105 			NULL,
106 			sizeof (GdaMetaStruct),
107 			0,
108 			(GInstanceInitFunc) gda_meta_struct_init,
109 			0
110 		};
111 
112 		g_mutex_lock (&registering);
113 		if (type == 0)
114 			type = g_type_register_static (G_TYPE_OBJECT, "GdaMetaStruct", &info, 0);
115 		g_mutex_unlock (&registering);
116 	}
117 	return type;
118 }
119 
120 
121 static void
gda_meta_struct_class_init(GdaMetaStructClass * klass)122 gda_meta_struct_class_init (GdaMetaStructClass *klass) {
123 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
124 
125 	parent_class = g_type_class_peek_parent (klass);
126 
127 	/* Properties */
128         object_class->set_property = gda_meta_struct_set_property;
129         object_class->get_property = gda_meta_struct_get_property;
130 	g_object_class_install_property (object_class, PROP_STORE,
131 					 /* To translators: GdaMetaStore is an object holding meta data information
132 					  * which will be used as an information source */
133 					 g_param_spec_object ("meta-store", NULL,
134 							      _ ("GdaMetaStore object to fetch information from"),
135 							      GDA_TYPE_META_STORE,
136 							      (G_PARAM_WRITABLE | G_PARAM_READABLE |
137 							       G_PARAM_CONSTRUCT_ONLY)));
138         g_object_class_install_property (object_class, PROP_FEATURES,
139 					 /* To translators: The GdaMetaStruct object computes lists of tables, views,
140 					  * and some other information, the "Features to compute" allows one to avoid
141 					  * computing some features which won't be used */
142 					 g_param_spec_uint ("features", _ ("Features to compute"), NULL,
143 							    GDA_META_STRUCT_FEATURE_NONE, G_MAXINT,
144 							    GDA_META_STRUCT_FEATURE_ALL,
145 							    (G_PARAM_WRITABLE | G_PARAM_READABLE |
146 							     G_PARAM_CONSTRUCT_ONLY)));
147 
148 	/* virtual methods */
149 	object_class->dispose = gda_meta_struct_dispose;
150 	object_class->finalize = gda_meta_struct_finalize;
151 
152 	/* extra */
153 	att_mgr = gda_attributes_manager_new (FALSE, NULL, NULL);
154 }
155 
156 
157 static void
gda_meta_struct_init(GdaMetaStruct * mstruct)158 gda_meta_struct_init (GdaMetaStruct *mstruct) {
159 	mstruct->priv = g_new0 (GdaMetaStructPrivate, 1);
160 	mstruct->priv->store = NULL;
161 	mstruct->priv->db_objects = NULL;
162 	mstruct->priv->index = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
163 }
164 
165 
166 /**
167  * gda_meta_struct_new:
168  * @store: a #GdaMetaStore from which the new #GdaMetaStruct object will fetch information
169  * @features: the kind of extra information the new #GdaMetaStruct object will compute
170  *
171  * Creates a new #GdaMetaStruct object. The @features specifies the extra features which will also be computed:
172  * the more features, the more time it takes to run. Features such as table's columns, each column's attributes, etc
173  * are not optional and will always be computed.
174  *
175  * Returns: (transfer full): the newly created #GdaMetaStruct object
176  */
177 GdaMetaStruct *
gda_meta_struct_new(GdaMetaStore * store,GdaMetaStructFeature features)178 gda_meta_struct_new (GdaMetaStore *store, GdaMetaStructFeature features)
179 {
180 	g_return_val_if_fail (GDA_IS_META_STORE (store), NULL);
181 	return (GdaMetaStruct*) g_object_new (GDA_TYPE_META_STRUCT, "meta-store", store, "features", features, NULL);
182 }
183 
184 static void
gda_meta_struct_dispose(GObject * object)185 gda_meta_struct_dispose (GObject *object) {
186 	GdaMetaStruct *mstruct;
187 
188 	g_return_if_fail (object != NULL);
189 	g_return_if_fail (GDA_IS_META_STRUCT (object));
190 
191 	mstruct = GDA_META_STRUCT (object);
192 	if (mstruct->priv->store) {
193 		g_signal_handlers_disconnect_by_func (G_OBJECT (mstruct->priv->store),
194 						      G_CALLBACK (meta_store_changed_cb), mstruct);
195 		g_signal_handlers_disconnect_by_func (G_OBJECT (mstruct->priv->store),
196 						      G_CALLBACK (meta_store_reset_cb), mstruct);
197 		g_object_ref (mstruct->priv->store);
198 		mstruct->priv->store = NULL;
199 	}
200 
201 	/* parent class */
202 	parent_class->finalize (object);
203 }
204 
205 static void
gda_meta_struct_finalize(GObject * object)206 gda_meta_struct_finalize (GObject *object) {
207 	GdaMetaStruct *mstruct;
208 
209 	g_return_if_fail (object != NULL);
210 	g_return_if_fail (GDA_IS_META_STRUCT (object));
211 
212 	mstruct = GDA_META_STRUCT (object);
213 	if (mstruct->priv) {
214 		g_slist_foreach (mstruct->priv->db_objects, (GFunc) gda_meta_db_object_free, NULL);
215 		g_slist_free (mstruct->priv->db_objects);
216 		g_hash_table_destroy (mstruct->priv->index);
217 		g_free (mstruct->priv);
218 		mstruct->priv = NULL;
219 	}
220 
221 	/* parent class */
222 	parent_class->finalize (object);
223 }
224 
225 static void
gda_meta_struct_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)226 gda_meta_struct_set_property (GObject *object,
227 			      guint param_id,
228 			      const GValue *value,
229 			      GParamSpec *pspec)
230 {
231         GdaMetaStruct *mstruct;
232 
233         mstruct = GDA_META_STRUCT (object);
234         if (mstruct->priv) {
235                 switch (param_id) {
236 		case PROP_STORE:
237 			mstruct->priv->store = g_value_get_object (value);
238 			if (mstruct->priv->store) {
239 				g_object_ref (mstruct->priv->store);
240 				g_signal_connect (G_OBJECT (mstruct->priv->store), "meta-changed",
241 						  G_CALLBACK (meta_store_changed_cb), mstruct);
242 				g_signal_connect (G_OBJECT (mstruct->priv->store), "meta-reset",
243 						  G_CALLBACK (meta_store_reset_cb), mstruct);
244 			}
245 			break;
246 		case PROP_FEATURES:
247 			mstruct->priv->features = g_value_get_uint (value);
248 			break;
249 		default:
250 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
251 			break;
252 		}
253 	}
254 }
255 
256 static void
gda_meta_struct_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)257 gda_meta_struct_get_property (GObject *object,
258 			      guint param_id,
259 			      GValue *value,
260 			      GParamSpec *pspec)
261 {
262         GdaMetaStruct *mstruct;
263         mstruct = GDA_META_STRUCT (object);
264 
265         if (mstruct->priv) {
266                 switch (param_id) {
267 		case PROP_STORE:
268 			g_value_set_object (value, mstruct->priv->store);
269 			break;
270 		case PROP_FEATURES:
271 			g_value_set_uint (value, mstruct->priv->features);
272 			break;
273 		default:
274 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
275 			break;
276 		}
277 	}
278 }
279 
280 static void
meta_store_changed_cb(GdaMetaStore * store,G_GNUC_UNUSED GSList * changes,GdaMetaStruct * mstruct)281 meta_store_changed_cb (GdaMetaStore *store, G_GNUC_UNUSED GSList *changes, GdaMetaStruct *mstruct)
282 {
283 	/* for now we mark ALL the db objects as outdated */
284 	meta_store_reset_cb (store, mstruct);
285 }
286 
287 static void
meta_store_reset_cb(G_GNUC_UNUSED GdaMetaStore * store,GdaMetaStruct * mstruct)288 meta_store_reset_cb (G_GNUC_UNUSED GdaMetaStore *store, GdaMetaStruct *mstruct)
289 {
290 	/* mark ALL the db objects as outdated */
291 	GSList *list;
292 	for (list = mstruct->priv->db_objects; list; list = list->next)
293 		GDA_META_DB_OBJECT (list->data)->outdated = TRUE;
294 }
295 
296 
297 static void
compute_view_dependencies(GdaMetaStruct * mstruct,GdaMetaDbObject * view_dbobj,GdaSqlStatement * sqlst)298 compute_view_dependencies (GdaMetaStruct *mstruct, GdaMetaDbObject *view_dbobj, GdaSqlStatement *sqlst)
299 {
300 	if (sqlst->stmt_type == GDA_SQL_STATEMENT_SELECT) {
301 		GdaSqlStatementSelect *selst;
302 		selst = (GdaSqlStatementSelect*) (sqlst->contents);
303 		GSList *targets = NULL;
304 		if (selst->from)
305 			targets = selst->from->targets;
306 		for (; targets; targets = targets->next) {
307 			GdaSqlSelectTarget *t = (GdaSqlSelectTarget *) targets->data;
308 			GValue *catalog, *schema, *name;
309 			GdaMetaDbObject *ref_obj, *tmp_obj;
310 			GdaMetaStruct *m2;
311 			GValue *vname;
312 
313 			if (!t->table_name)
314 				continue;
315 
316 			m2 = gda_meta_struct_new (mstruct->priv->store, GDA_META_STRUCT_FEATURE_NONE);
317 			g_value_set_string ((vname = gda_value_new (G_TYPE_STRING)), t->table_name);
318 			if (! (tmp_obj = gda_meta_struct_complement (m2,
319 								     GDA_META_DB_TABLE, NULL, NULL, vname, NULL)))
320 				tmp_obj = gda_meta_struct_complement (m2,
321 								      GDA_META_DB_VIEW, NULL, NULL, vname, NULL);
322 			gda_value_free (vname);
323 
324 			if (!tmp_obj) {
325 				/* could not find dependency */
326 				g_object_unref (m2);
327 				continue;
328 			}
329 
330 			/* the dependency exists, and is identified by tmp_obj->obj_catalog, tmp_obj->obj_schema
331 			 * and tmp_obj->obj_name */
332 			g_value_set_string ((catalog = gda_value_new (G_TYPE_STRING)), tmp_obj->obj_catalog);
333 			g_value_set_string ((schema = gda_value_new (G_TYPE_STRING)), tmp_obj->obj_schema);
334 			g_value_set_string ((name = gda_value_new (G_TYPE_STRING)), tmp_obj->obj_name);
335 			ref_obj = _meta_struct_get_db_object (mstruct, catalog, schema, name);
336 			if (!ref_obj) {
337 				gchar *str;
338 				ref_obj = g_new0 (GdaMetaDbObject, 1);
339 				ref_obj->obj_type = GDA_META_DB_UNKNOWN;
340 				ref_obj->obj_catalog = g_strdup (tmp_obj->obj_catalog);
341 				ref_obj->obj_schema = g_strdup (tmp_obj->obj_schema);
342 				ref_obj->obj_name = g_strdup (tmp_obj->obj_name);
343 
344 				mstruct->priv->db_objects = g_slist_append (mstruct->priv->db_objects, ref_obj);
345 				str = g_strdup_printf ("%s.%s.%s", tmp_obj->obj_catalog,
346 						       tmp_obj->obj_schema, tmp_obj->obj_name);
347 				g_hash_table_insert (mstruct->priv->index, str, ref_obj);
348 			}
349 			g_object_unref (m2);
350 			g_assert (ref_obj);
351 			gda_value_free (catalog);
352 			gda_value_free (schema);
353 			gda_value_free (name);
354 
355 			view_dbobj->depend_list = g_slist_append (view_dbobj->depend_list, ref_obj);
356 		}
357 	}
358 	else if (sqlst->stmt_type == GDA_SQL_STATEMENT_COMPOUND) {
359 		GdaSqlStatementCompound *cst;
360 		GSList *list;
361 		cst = (GdaSqlStatementCompound*) (sqlst->contents);
362 		for (list = cst->stmt_list; list; list = list->next)
363 			compute_view_dependencies (mstruct, view_dbobj, (GdaSqlStatement*) list->data);
364 	}
365 	else
366 		g_assert_not_reached ();
367 }
368 
369 static GdaMetaDbObject * _meta_struct_complement (GdaMetaStruct *mstruct, GdaMetaDbObjectType type,
370 						  const GValue *icatalog, const GValue *ischema, const GValue *iname,
371 						  const GValue *short_name, const GValue *full_name,
372 						  const GValue *owner, GError **error);
373 static gboolean determine_db_object_from_schema_and_name (GdaMetaStruct *mstruct,
374 							  GdaMetaDbObjectType *int_out_type, GValue **out_catalog,
375 							  GValue **out_short_name, GValue **out_full_name,
376 							  GValue **out_owner, const GValue *schema, const GValue *name);
377 static gboolean determine_db_object_from_short_name (GdaMetaStruct *mstruct,
378 						     GdaMetaDbObjectType *int_out_type, GValue **out_catalog,
379 						     GValue **out_schema, GValue **out_name, GValue **out_short_name,
380 						     GValue **out_full_name, GValue **out_owner, const GValue *name);
381 static gboolean determine_db_object_from_missing_type (GdaMetaStruct *mstruct,
382 						       GdaMetaDbObjectType *out_type, GValue **out_short_name,
383 						       GValue **out_full_name, GValue **out_owner, const GValue *catalog,
384 						       const GValue *schema, const GValue *name);
385 static gchar *array_type_to_sql (GdaMetaStore *store, const GValue *specific_name);
386 static gchar *
get_user_obj_name(const GValue * catalog,const GValue * schema,const GValue * name)387 get_user_obj_name (const GValue *catalog, const GValue *schema, const GValue *name)
388 {
389 	GString *string = NULL;
390 	gchar *ret;
391 	if (catalog && (G_VALUE_TYPE (catalog) != GDA_TYPE_NULL))
392 		string = g_string_new (g_value_get_string (catalog));
393 	if (schema && (G_VALUE_TYPE (schema) != GDA_TYPE_NULL)) {
394 		if (string) {
395 			g_string_append_c (string, '.');
396 			g_string_append (string, g_value_get_string (schema));
397 		}
398 		else
399 			string = g_string_new (g_value_get_string (schema));
400 	}
401 	if (name && (G_VALUE_TYPE (name) != GDA_TYPE_NULL)) {
402 		if (string) {
403 			g_string_append_c (string, '.');
404 			g_string_append (string, g_value_get_string (name));
405 		}
406 		else
407 			string = g_string_new (g_value_get_string (name));
408 	}
409 	ret = string->str;
410 	g_string_free (string, FALSE);
411 	return ret;
412 }
413 
414 static gchar *
prepare_sql_identifier_for_compare(gchar * str)415 prepare_sql_identifier_for_compare (gchar *str)
416 {
417 	if (!str || (*str == '"'))
418 		return str;
419 	else {
420 		gchar *ptr;
421 		for (ptr = str; *ptr; ptr++)
422 			*ptr = g_ascii_tolower (*ptr);
423 		return str;
424 	}
425 }
426 
427 /**
428  * gda_meta_struct_complement:
429  * @mstruct: a #GdaMetaStruct object
430  * @type: the type of object to add (which can be GDA_META_DB_UNKNOWN)
431  * @catalog: (allow-none): the catalog the object belongs to (as a G_TYPE_STRING GValue), or %NULL
432  * @schema: (allow-none): the schema the object belongs to (as a G_TYPE_STRING GValue), or %NULL
433  * @name: the object's name (as a G_TYPE_STRING GValue), not %NULL
434  * @error: (allow-none): a place to store errors, or %NULL
435  *
436  * Creates a new #GdaMetaDbObject structure in @mstruct to represent the database object (of type @type)
437  * which can be uniquely identified as @catalog.@schema.@name.
438  *
439  * If @catalog is not %NULL, then @schema should not be %NULL.
440  *
441  * If both @catalog and @schema are %NULL, then the database object will be the one which is
442  * "visible" by default (that is which can be accessed only by its short @name name).
443  *
444  * If @catalog is %NULL and @schema is not %NULL, then the database object will be the one which
445  * can be accessed by its @schema.@name name.
446  *
447  * Important note: @catalog, @schema and @name will be used using the following convention:
448  * <itemizedlist>
449  *   <listitem><para>be surrounded by double quotes for a case sensitive search</para></listitem>
450  *   <listitem><para>otherwise for case insensitive search</para></listitem>
451  * </itemizedlist>
452  *
453  * For more information, see the <link linkend="information_schema:sql_identifiers">
454  * meta data section about SQL identifiers</link>.
455  *
456  * Returns: (transfer none): the #GdaMetaDbObject corresponding to the database object if no error occurred, or %NULL
457  */
458 GdaMetaDbObject *
gda_meta_struct_complement(GdaMetaStruct * mstruct,GdaMetaDbObjectType type,const GValue * catalog,const GValue * schema,const GValue * name,GError ** error)459 gda_meta_struct_complement (GdaMetaStruct *mstruct, GdaMetaDbObjectType type,
460 			    const GValue *catalog, const GValue *schema, const GValue *name,
461 			    GError **error)
462 {
463 	GdaMetaDbObject *dbo = NULL;
464 	GdaMetaDbObjectType real_type = type;
465 	GValue *short_name = NULL, *full_name=NULL, *owner=NULL;
466 	GValue *icatalog = NULL, *ischema = NULL, *iname = NULL; /* GValue with identifiers ready to be compared */
467 
468 	/* checks */
469 	g_return_val_if_fail (mstruct->priv->store, NULL);
470 	g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), NULL);
471 	g_return_val_if_fail (name && (G_VALUE_TYPE (name) == G_TYPE_STRING), NULL);
472 	if (catalog && (gda_value_is_null (catalog) || !g_value_get_string (catalog)))
473 		catalog = NULL;
474 	if (schema && (gda_value_is_null (schema) || !g_value_get_string (schema)))
475 		schema = NULL;
476 	g_return_val_if_fail (!catalog || (catalog && schema), NULL);
477 	g_return_val_if_fail (!catalog || (G_VALUE_TYPE (catalog) == G_TYPE_STRING), NULL);
478 	g_return_val_if_fail (!schema || (G_VALUE_TYPE (schema) == G_TYPE_STRING), NULL);
479 
480 	/* create ready to compare strings for catalog, schema and name */
481 	gchar *schema_s, *name_s;
482 	if (_split_identifier_string (g_value_dup_string (name), &schema_s, &name_s)) {
483 		g_value_take_string ((iname = gda_value_new (G_TYPE_STRING)), prepare_sql_identifier_for_compare (name_s));
484 		if (schema_s)
485 			g_value_take_string ((ischema = gda_value_new (G_TYPE_STRING)), prepare_sql_identifier_for_compare (schema_s));
486 	}
487 	else
488 		g_value_take_string ((iname = gda_value_new (G_TYPE_STRING)),
489 				     prepare_sql_identifier_for_compare (g_value_dup_string (name)));
490 	if (catalog)
491 		g_value_take_string ((icatalog = gda_value_new (G_TYPE_STRING)),
492 				     prepare_sql_identifier_for_compare (g_value_dup_string (catalog)));
493 	if (schema && !ischema)
494 		g_value_take_string ((ischema = gda_value_new (G_TYPE_STRING)),
495 				     prepare_sql_identifier_for_compare (g_value_dup_string (schema)));
496 
497 	if (!icatalog) {
498 		if (ischema) {
499 			g_return_val_if_fail (ischema && (G_VALUE_TYPE (ischema) == G_TYPE_STRING), NULL);
500 			if (! determine_db_object_from_schema_and_name (mstruct, &real_type, &icatalog,
501 									&short_name, &full_name, &owner,
502 									ischema, iname)) {
503 				gchar *tmp;
504 				tmp = get_user_obj_name (catalog, schema, name);
505 				g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR,
506 					     _("Could not find object named '%s'"), tmp);
507 				g_free (tmp);
508 				gda_value_free (ischema);
509 				gda_value_free (iname);
510 				return NULL;
511 			}
512 		}
513 		else {
514 			GValue *real_name = NULL;
515 			if (! determine_db_object_from_short_name (mstruct, &real_type, &icatalog,
516 								   &ischema, &real_name,
517 								   &short_name, &full_name, &owner, iname)) {
518 				gchar *tmp;
519 				tmp = get_user_obj_name (catalog, schema, name);
520 				g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR,
521 					     _("Could not find object named '%s'"), tmp);
522 				g_free (tmp);
523 				gda_value_free (iname);
524 				return NULL;
525 			}
526 			if (real_name) {
527 				gda_value_free (iname);
528 				iname = real_name;
529 			}
530 		}
531 	}
532 	else if (type == GDA_META_DB_UNKNOWN) {
533 		if (! determine_db_object_from_missing_type (mstruct, &real_type, &short_name, &full_name, &owner,
534 							     icatalog, ischema, iname)) {
535 			gchar *tmp;
536 			tmp = get_user_obj_name (catalog, schema, name);
537 			g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR,
538 				     _("Could not find object named '%s'"), tmp);
539 			g_free (tmp);
540 			gda_value_free (icatalog);
541 			gda_value_free (ischema);
542 			gda_value_free (iname);
543 			return NULL;
544 		}
545 	}
546 	type = real_type;
547 	dbo = _meta_struct_complement (mstruct, type, icatalog, ischema, iname, short_name, full_name, owner, error);
548 
549 	gda_value_free (icatalog);
550 	gda_value_free (ischema);
551 	gda_value_free (iname);
552 
553 	if (short_name)	gda_value_free (short_name);
554 	if (full_name)	gda_value_free (full_name);
555 	if (owner) gda_value_free (owner);
556 	return dbo;
557 }
558 
559 static GdaMetaForeignKeyPolicy
policy_string_to_value(const gchar * string)560 policy_string_to_value (const gchar *string)
561 {
562 	if (!string)
563 		return GDA_META_FOREIGN_KEY_UNKNOWN;
564 	if (*string == 'C')
565 		return GDA_META_FOREIGN_KEY_CASCADE;
566 	else if (*string == 'R')
567 		return GDA_META_FOREIGN_KEY_RESTRICT;
568 	else if (*string == 'N') {
569 		if (!strcmp (string + 1, "ONE"))
570 			return GDA_META_FOREIGN_KEY_NONE;
571 		else
572 			return GDA_META_FOREIGN_KEY_NO_ACTION;
573 	}
574 	else if (*string == 'S') {
575 		if (!strcmp (string + 1, "ET NULL"))
576 			return GDA_META_FOREIGN_KEY_SET_NULL;
577 		else
578 			return GDA_META_FOREIGN_KEY_SET_DEFAULT;
579 	}
580 	return GDA_META_FOREIGN_KEY_UNKNOWN;
581 }
582 
583 /*
584  * Find if there is already a declared foreign for @dbo to @ref_dbo using the columns
585  * listed in @columns
586  *
587  * @columns contains 4 columns, with no NULL value, and with nrows>0
588  *  - @dbo's column name (string)
589  *  - @dbo's column name ordinal position (int)
590  *  - @ref_dbo's column name (string)
591  *  - @ref_dbo's column name ordinal position (int)
592  */
593 static GdaMetaTableForeignKey *
find_real_foreign_key(GdaMetaTable * table,GdaMetaDbObject * ref_dbo,GdaDataModel * columns)594 find_real_foreign_key (GdaMetaTable *table, GdaMetaDbObject *ref_dbo, GdaDataModel *columns)
595 {
596 	GSList *list;
597 	gint nrows = -1;
598 	for (list = table->fk_list; list; list = list->next) {
599 		GdaMetaTableForeignKey *fk = (GdaMetaTableForeignKey*) list->data;
600 		gint i;
601 		gboolean *mapping;
602 		if (fk->depend_on != ref_dbo)
603 			continue;
604 
605 		if (nrows == -1)
606 			nrows = gda_data_model_get_n_rows (columns);
607 
608 		if (nrows != fk->cols_nb)
609 			continue;
610 
611 		mapping = g_new0 (gboolean, nrows);
612 		for (i = 0; i < nrows; i++) {
613 			const GValue *cvalues[4];
614 			const gchar *fk_colname, *ref_colname;
615 			gint fk_pos, ref_pos;
616 			gint j;
617 			for (j = 0; j < 4; j++) {
618 				cvalues[j] = gda_data_model_get_value_at (columns, j, i, NULL);
619 				if (!cvalues[j]) {
620 					g_free (mapping);
621 					goto out;
622 				}
623 			}
624 			fk_colname = g_value_get_string (cvalues[0]);
625 			fk_pos = g_value_get_int (cvalues[1]);
626 			ref_colname = g_value_get_string (cvalues[2]);
627 			ref_pos = g_value_get_int (cvalues[3]);
628 			if (!fk_colname || !*fk_colname ||
629 			    !ref_colname || !*ref_colname) {
630 				g_free (mapping);
631 				goto out;
632 			}
633 
634 			for (j = 0; j < nrows; j++) {
635 				if (mapping [j]) /* row already mapped? */
636 					continue;
637 				if ((fk_pos == fk->fk_cols_array[j]) &&
638 				    (ref_pos == fk->ref_pk_cols_array[j]) &&
639 				    !strcmp (fk_colname, fk->fk_names_array[j]) &&
640 				    !strcmp (ref_colname, fk->ref_pk_names_array[j])) {
641 					mapping [j] = TRUE;
642 					break;
643 				}
644 			}
645 			if (j == nrows)
646 				/* i'th row has not been mapped */
647 				break;
648 		}
649 		g_free (mapping);
650 		if (i == nrows)
651 			/* all the rows have been mapped */
652 			return fk;
653 		else
654 			continue;
655 	}
656  out:
657 	return NULL;
658 }
659 
660 static gboolean
add_declared_foreign_keys(GdaMetaStruct * mstruct,GdaMetaTable * mt,GError ** error)661 add_declared_foreign_keys (GdaMetaStruct *mstruct, GdaMetaTable *mt, GError **error)
662 {
663 	const gchar *sql1 = "SELECT DISTINCT constraint_name, ref_table_catalog, ref_table_schema, ref_table_name FROM __declared_fk WHERE table_catalog = ##tc::string AND table_schema = ##ts::string AND table_name = ##tname::string ORDER BY constraint_name, ref_table_catalog, ref_table_schema, ref_table_name";
664 	const gchar *sql2 = "select de.column_name, c.ordinal_position, de.ref_column_name, rc.ordinal_position FROM __declared_fk de LEFT JOIN _columns c ON (de.table_catalog=c.table_catalog AND de.table_schema=c.table_schema AND de.table_name=c.table_name AND de.column_name=c.column_name) LEFT JOIN _columns rc ON (de.ref_table_catalog=rc.table_catalog AND de.ref_table_schema=rc.table_schema AND de.ref_table_name=rc.table_name AND de.ref_column_name=rc.column_name) WHERE de.constraint_name=##cname::string AND de.table_catalog=##tc::string AND de.table_schema=##ts::string AND de.table_name=##tname::string";
665 	GdaDataModel *model, *cmodel = NULL;
666 	gint i, nrows;
667 	GValue *v1, *v2, *v3;
668 	GdaMetaDbObject *dbo;
669 
670 	dbo = (GdaMetaDbObject*) mt;
671 	g_value_set_string ((v1 = gda_value_new (G_TYPE_STRING)), dbo->obj_catalog);
672 	g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), dbo->obj_schema);
673 	g_value_set_string ((v3 = gda_value_new (G_TYPE_STRING)), dbo->obj_name);
674 	model = gda_meta_store_extract (mstruct->priv->store, sql1,
675 					error, "tc", v1, "ts", v2, "tname", v3, NULL);
676 	if (!model)
677 		goto onerror;
678 
679 	nrows = gda_data_model_get_n_rows (model);
680 	for (i = 0; i < nrows; i++) {
681 		GdaMetaDbObject *ref_dbo = NULL;
682 		GdaMetaTableForeignKey *tfk = NULL;
683 		const GValue *fk_catalog, *fk_schema, *fk_tname, *fk_name;
684 		gboolean ignore = FALSE;
685 
686 		fk_name = gda_data_model_get_value_at (model, 0, i, error);
687 		if (!fk_name) goto onerror;
688 		fk_catalog = gda_data_model_get_value_at (model, 1, i, error);
689 		if (!fk_catalog) goto onerror;
690 		fk_schema = gda_data_model_get_value_at (model, 2, i, error);
691 		if (!fk_schema) goto onerror;
692 		fk_tname = gda_data_model_get_value_at (model, 3, i, error);
693 		if (!fk_tname) goto onerror;
694 
695 		/* get columns */
696 		cmodel = gda_meta_store_extract (mstruct->priv->store, sql2,
697 						 error, "tc", v1, "ts", v2, "tname", v3,
698 						 "cname", fk_name, NULL);
699 		if (!cmodel)
700 			goto onerror;
701 
702 		/* create new FK structure */
703 		tfk = g_new0 (GdaMetaTableForeignKey, 1);
704 		tfk->meta_table = dbo;
705 		tfk->declared = TRUE;
706 		tfk->fk_name = g_value_dup_string (fk_name);
707 		tfk->on_update_policy = GDA_META_FOREIGN_KEY_NONE;
708 		tfk->on_delete_policy = GDA_META_FOREIGN_KEY_NONE;
709 
710 		/* ignore if some columns are not found in the schema
711 		 * (maybe wrong or outdated FK decl) */
712 		gint j, cnrows;
713 		cnrows = gda_data_model_get_n_rows (cmodel);
714 		if (cnrows == 0)
715 			ignore = TRUE;
716 		else {
717 			tfk->cols_nb = cnrows;
718 			tfk->fk_cols_array = g_new0 (gint, cnrows);
719 			tfk->fk_names_array = g_new0 (gchar *, cnrows);
720 			tfk->ref_pk_cols_array = g_new0 (gint, cnrows);
721 			tfk->ref_pk_names_array = g_new0 (gchar *, cnrows);
722 		}
723 		for (j = 0; j < cnrows; j++) {
724 			const GValue *ov;
725 			ov = gda_data_model_get_value_at (cmodel, 0, j, error);
726 			if (!ov) goto onerror;
727 			if (G_VALUE_TYPE (ov) != G_TYPE_STRING) {
728 				ignore = TRUE;
729 				break;
730 			}
731 			tfk->fk_names_array [j] = g_value_dup_string (ov);
732 
733 			ov = gda_data_model_get_value_at (cmodel, 1, j, error);
734 			if (!ov) goto onerror;
735 			if (G_VALUE_TYPE (ov) != G_TYPE_INT) {
736 				ignore = TRUE;
737 				break;
738 			}
739 			tfk->fk_cols_array [j] = g_value_get_int (ov);
740 
741 			ov = gda_data_model_get_value_at (cmodel, 2, j, error);
742 			if (!ov) goto onerror;
743 			if (G_VALUE_TYPE (ov) != G_TYPE_STRING) {
744 				ignore = TRUE;
745 				break;
746 			}
747 			tfk->ref_pk_names_array [j] = g_value_dup_string (ov);
748 
749 			ov = gda_data_model_get_value_at (cmodel, 3, j, error);
750 			if (!ov) goto onerror;
751 			if (G_VALUE_TYPE (ov) != G_TYPE_INT) {
752 				ignore = TRUE;
753 				break;
754 			}
755 			tfk->ref_pk_cols_array [j] = g_value_get_int (ov);
756 		}
757 
758 		/* ignore if there is already an implemented FK */
759 		if (! ignore) {
760 			ref_dbo = _meta_struct_get_db_object (mstruct, fk_catalog,
761 							      fk_schema, fk_tname);
762 			if (ref_dbo && find_real_foreign_key (mt, ref_dbo, cmodel))
763 				ignore = TRUE;
764 		}
765 		if (ignore) {
766 			/* ignore this FK end move on to the next one */
767 			if (tfk)
768 				gda_meta_table_foreign_key_free (tfk);
769 			continue;
770 		}
771 
772 		tfk->depend_on = ref_dbo;
773 		if (!tfk->depend_on) {
774 			gchar *str;
775 			tfk->depend_on = g_new0 (GdaMetaDbObject, 1);
776 			tfk->depend_on->obj_type = GDA_META_DB_UNKNOWN;
777 			tfk->depend_on->obj_catalog = g_strdup (g_value_get_string (fk_catalog));
778 			tfk->depend_on->obj_schema = g_strdup (g_value_get_string (fk_schema));
779 			tfk->depend_on->obj_name = g_strdup (g_value_get_string (fk_tname));
780 			mstruct->priv->db_objects = g_slist_append (mstruct->priv->db_objects, tfk->depend_on);
781 			str = g_strdup_printf ("%s.%s.%s", g_value_get_string (fk_catalog),
782 					       g_value_get_string (fk_schema),
783 					       g_value_get_string (fk_tname));
784 			g_hash_table_insert (mstruct->priv->index, str, tfk->depend_on);
785 		}
786 		else if (tfk->depend_on->obj_type == GDA_META_DB_TABLE) {
787 			GdaMetaTable *dot = GDA_META_TABLE (tfk->depend_on);
788 			dot->reverse_fk_list = g_slist_prepend (dot->reverse_fk_list, tfk);
789 		}
790 
791 		dbo->depend_list = g_slist_append (dbo->depend_list, tfk->depend_on);
792 		mt->fk_list = g_slist_prepend (mt->fk_list, tfk);
793 	}
794 	g_object_unref (model);
795 	if (cmodel)
796 		g_object_unref (cmodel);
797 
798 	gda_value_free (v1);
799 	gda_value_free (v2);
800 	gda_value_free (v3);
801 
802 	return TRUE;
803 
804  onerror:
805 	if (model)
806 		g_object_unref (model);
807 	if (cmodel)
808 		g_object_unref (cmodel);
809 	gda_value_free (v1);
810 	gda_value_free (v2);
811 	gda_value_free (v3);
812 
813 	return FALSE;
814 }
815 
816 static GdaMetaDbObject *
_meta_struct_complement(GdaMetaStruct * mstruct,GdaMetaDbObjectType type,const GValue * icatalog,const GValue * ischema,const GValue * iname,const GValue * short_name,const GValue * full_name,const GValue * owner,GError ** error)817 _meta_struct_complement (GdaMetaStruct *mstruct, GdaMetaDbObjectType type,
818 			 const GValue *icatalog, const GValue *ischema, const GValue *iname,
819 			 const GValue *short_name, const GValue *full_name, const GValue *owner, GError **error)
820 {
821 	/* at this point icatalog, ischema and iname are NOT NULL */
822 	GdaMetaDbObject *dbo = NULL;
823 	const GValue *cvalue;
824 
825 	/* create new GdaMetaDbObject or get already existing one */
826 	dbo = _meta_struct_get_db_object (mstruct, icatalog, ischema, iname);
827 	if (!dbo) {
828 		dbo = g_new0 (GdaMetaDbObject, 1);
829 		dbo->obj_catalog = g_strdup (g_value_get_string (icatalog));
830 		dbo->obj_schema = g_strdup (g_value_get_string (ischema));
831 		dbo->obj_name = g_strdup (g_value_get_string (iname));
832 		if (short_name)
833 			dbo->obj_short_name = g_strdup (g_value_get_string (short_name));
834 		if (full_name)
835 			dbo->obj_full_name = g_strdup (g_value_get_string (full_name));
836 		if (owner && !gda_value_is_null (owner))
837 			dbo->obj_owner = g_strdup (g_value_get_string (owner));
838 	}
839 	else if (dbo->obj_type == type)
840 		return dbo; /* nothing to do */
841 	else if (dbo->obj_type != GDA_META_DB_UNKNOWN) {
842 		/* DB Object already exists, return an error */
843 		g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_DUPLICATE_OBJECT_ERROR,
844 			     _("Object %s.%s.%s already exists in GdaMetaStruct and has a different object type"),
845 			     g_value_get_string (icatalog), g_value_get_string (ischema),
846 			     g_value_get_string (iname));
847 		dbo = NULL;
848 		goto onerror;
849 	}
850 	dbo->obj_type = type;
851 
852 	switch (type) {
853 	case GDA_META_DB_VIEW: {
854 		gchar *sql = "SELECT view_definition, is_updatable, table_short_name, table_full_name, table_owner "
855 			"FROM _views NATURAL JOIN _tables "
856 			"WHERE table_catalog = ##tc::string "
857 			"AND table_schema = ##ts::string AND table_name = ##tname::string";
858 		GdaDataModel *model;
859 		gint nrows;
860 		GdaMetaView *mv;
861 
862 		model = gda_meta_store_extract (mstruct->priv->store, sql,
863 						error, "tc", icatalog, "ts", ischema, "tname", iname, NULL);
864 		if (!model)
865 			goto onerror;
866 		nrows = gda_data_model_get_n_rows (model);
867 		if (nrows < 1) {
868 			g_object_unref (model);
869 			g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR,
870 				     _("View %s.%s.%s not found in meta store object"),
871 				     g_value_get_string (icatalog), g_value_get_string (ischema),
872 				     g_value_get_string (iname));
873 			goto onerror;
874 		}
875 
876 		if (!dbo->obj_short_name) {
877 			cvalue = gda_data_model_get_value_at (model, 2, 0, error);
878 			if (!cvalue) goto onerror;
879 			dbo->obj_short_name = g_value_dup_string (cvalue);
880 		}
881 		if (!dbo->obj_full_name) {
882 			cvalue = gda_data_model_get_value_at (model, 3, 0, error);
883 			if (!cvalue) goto onerror;
884 			dbo->obj_full_name = g_value_dup_string (cvalue);
885 		}
886 		if (!dbo->obj_owner) {
887 			cvalue = gda_data_model_get_value_at (model, 4, 0, error);
888 			if (!cvalue) goto onerror;
889 			if (!gda_value_is_null (cvalue))
890 				dbo->obj_owner = g_value_dup_string (cvalue);
891 		}
892 
893 		mv = GDA_META_VIEW (dbo);
894 		cvalue = gda_data_model_get_value_at (model, 0, 0, error);
895 		if (!cvalue) goto onerror;
896 		if (G_VALUE_TYPE (cvalue) != GDA_TYPE_NULL)
897 			mv->view_def = g_value_dup_string (cvalue);
898 		else
899 			mv->view_def = g_strdup ("");
900 
901 		cvalue = gda_data_model_get_value_at (model, 1, 0, error);
902 		if (!cvalue) goto onerror;
903 		if (G_VALUE_TYPE (cvalue) != GDA_TYPE_NULL)
904 			mv->is_updatable = g_value_get_boolean (cvalue);
905 		else
906 			mv->is_updatable = FALSE;
907 
908 		/* view's dependencies, from its definition */
909 		if ((mstruct->priv->features & GDA_META_STRUCT_FEATURE_VIEW_DEPENDENCIES) &&
910 		    mv->view_def && *mv->view_def) {
911 			static GdaSqlParser *parser = NULL;
912 			GdaStatement *stmt;
913 			const gchar *remain;
914 			if (!parser)
915 				parser = gda_sql_parser_new ();
916 			stmt = gda_sql_parser_parse_string (parser, mv->view_def, &remain, NULL);
917 			if (stmt &&
918 			    ((gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT) ||
919 			     (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_COMPOUND))) {
920 				GdaSqlStatement *sqlst;
921 				g_object_get (G_OBJECT (stmt), "structure", &sqlst, NULL);
922 				compute_view_dependencies (mstruct, dbo, sqlst);
923 				gda_sql_statement_free (sqlst);
924 				g_object_unref (stmt);
925 
926 #ifdef GDA_DEBUG_NO
927 				g_print ("View %s depends on: ", dbo->obj_name);
928 				GSList *list;
929 				for (list = dbo->depend_list; list; list = list->next)
930 					g_print ("%s ", GDA_META_DB_OBJECT (list->data)->obj_name);
931 				g_print ("\n");
932 #endif
933 			}
934 		}
935 	}
936 	case GDA_META_DB_TABLE: {
937 		/* columns */
938 		gchar *sql = "SELECT c.column_name, c.data_type, c.gtype, c.is_nullable, t.table_short_name, t.table_full_name, c.column_default, t.table_owner, c.array_spec, c.extra, c.column_comments, coalesce (c.character_maximum_length, c.character_octet_length) FROM _tables as t LEFT NATURAL JOIN _columns as c WHERE table_catalog = ##tc::string AND table_schema = ##ts::string AND table_name = ##tname::string ORDER BY ordinal_position";
939 		GdaMetaTable *mt;
940 		GdaDataModel *model;
941 		gint i, nrows;
942 
943 		model = gda_meta_store_extract (mstruct->priv->store, sql,
944 						error, "tc", icatalog, "ts", ischema, "tname", iname, NULL);
945 		if (!model)
946 			goto onerror;
947 
948 		nrows = gda_data_model_get_n_rows (model);
949 		if (nrows < 1) {
950 			g_object_unref (model);
951 			g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR,
952 				     _("Table %s.%s.%s not found (or missing columns information)"),
953 				     g_value_get_string (icatalog), g_value_get_string (ischema),
954 				     g_value_get_string (iname));
955 			goto onerror;
956 		}
957 		if (!dbo->obj_short_name) {
958 			cvalue = gda_data_model_get_value_at (model, 4, 0, error);
959 			if (!cvalue) goto onerror;
960 			dbo->obj_short_name = g_value_dup_string (cvalue);
961 		}
962 		if (!dbo->obj_full_name) {
963 			cvalue = gda_data_model_get_value_at (model, 5, 0, error);
964 			if (!cvalue) goto onerror;
965 			dbo->obj_full_name = g_value_dup_string (cvalue);
966 		}
967 		if (!dbo->obj_owner) {
968 			cvalue = gda_data_model_get_value_at (model, 7, 0, error);
969 			if (!cvalue) goto onerror;
970 			if (!gda_value_is_null (cvalue))
971 				dbo->obj_owner = g_value_dup_string (cvalue);
972 		}
973 
974 		cvalue = gda_data_model_get_value_at (model, 0, 0, error);
975 		if (cvalue && (G_VALUE_TYPE (cvalue) == GDA_TYPE_NULL)) {
976 			if (type == GDA_META_DB_VIEW) {
977 				/* we don't have the list of columns for the view.
978 				 * This can sometimes happen in SQLite */
979 				nrows = 0;
980 			}
981 		}
982 		mt = GDA_META_TABLE (dbo);
983 		for (i = 0; i < nrows; i++) {
984 			GdaMetaTableColumn *tcol;
985 			const gchar *cstr = NULL;
986 			gint len = -1;
987 			tcol = g_new0 (GdaMetaTableColumn, 1); /* Note: tcol->pkey is not determined here */
988 			mt->columns = g_slist_prepend (mt->columns, tcol);
989 
990 			cvalue = gda_data_model_get_value_at (model, 0, i, error);
991 			if (!cvalue) goto onerror;
992 			tcol->column_name = g_value_dup_string (cvalue);
993 
994 			cvalue = gda_data_model_get_value_at (model, 1, i, error);
995 			if (!cvalue) goto onerror;
996 			if (!gda_value_is_null (cvalue))
997 				cstr = g_value_get_string (cvalue);
998 
999 			cvalue = gda_data_model_get_value_at (model, 11, i, error);
1000 			if (!cvalue) goto onerror;
1001 			if (!gda_value_is_null (cvalue))
1002 				len = g_value_get_int (cvalue);
1003 
1004 			if (cstr && *cstr) {
1005 				if (len >= 0)
1006 					tcol->column_type = g_strdup_printf ("%s (%d)", cstr, len);
1007 				else
1008 					tcol->column_type = g_strdup (cstr);
1009 			}
1010 			else {
1011 				cvalue = gda_data_model_get_value_at (model, 8, i, error);
1012 				if (!cvalue) goto onerror;
1013 				tcol->column_type = array_type_to_sql (mstruct->priv->store, cvalue);
1014 				if (!tcol->column_type)
1015 					goto onerror;
1016 			}
1017 
1018 			cvalue = gda_data_model_get_value_at (model, 2, i, error);
1019 			if (!cvalue) goto onerror;
1020 			tcol->gtype = gda_g_type_from_string (g_value_get_string (cvalue));
1021 			if (tcol->gtype == G_TYPE_INVALID)
1022 				tcol->gtype = GDA_TYPE_NULL;
1023 
1024 			cvalue = gda_data_model_get_value_at (model, 3, i, error);
1025 			if (!cvalue) goto onerror;
1026 			tcol->nullok = g_value_get_boolean (cvalue);
1027 
1028 			cvalue = gda_data_model_get_value_at (model, 6, i, error);
1029 			if (!cvalue) goto onerror;
1030 			if (!gda_value_is_null (cvalue))
1031 				tcol->default_value = g_value_dup_string (cvalue);
1032 
1033 			cvalue = gda_data_model_get_value_at (model, 9, i, error);
1034 			if (!cvalue) goto onerror;
1035 			if (!gda_value_is_null (cvalue)) {
1036 				gchar **array, *tmp;
1037 				gint ai;
1038 				GValue *true_value;
1039 
1040 				g_value_set_boolean ((true_value = gda_value_new (G_TYPE_BOOLEAN)), TRUE);
1041 				cstr = g_value_get_string (cvalue);
1042 				array = g_strsplit (cstr, ",", 0);
1043 				for (ai = 0; array [ai]; ai++) {
1044 					tmp = g_strstrip (array [ai]);
1045 					if (!strcmp (tmp, GDA_EXTRA_AUTO_INCREMENT))
1046 						gda_attributes_manager_set (att_mgr, tcol, GDA_ATTRIBUTE_AUTO_INCREMENT,
1047 									    true_value);
1048 					else
1049 						g_message ("Unknown EXTRA attribute '%s', please report this bug to "
1050 							   "http://bugzilla.gnome.org/ for the \"libgda\" product.", tmp);
1051 				}
1052 				gda_value_free (true_value);
1053 				g_strfreev (array);
1054 			}
1055 
1056 			cvalue = gda_data_model_get_value_at (model, 10, i, error);
1057 			if (!cvalue) goto onerror;
1058 			if (!gda_value_is_null (cvalue))
1059 				gda_attributes_manager_set (att_mgr, tcol, GDA_ATTRIBUTE_DESCRIPTION,
1060 							    cvalue);
1061 
1062 		}
1063 		mt->columns = g_slist_reverse (mt->columns);
1064 		g_object_unref (model);
1065 
1066 		/* primary key */
1067 		sql = "SELECT constraint_name FROM _table_constraints WHERE constraint_type='PRIMARY KEY' AND table_catalog = ##tc::string AND table_schema = ##ts::string AND table_name = ##tname::string";
1068 		model = gda_meta_store_extract (mstruct->priv->store, sql,
1069 						error, "tc", icatalog, "ts", ischema, "tname", iname, NULL);
1070 		if (!model)
1071 			goto onerror;
1072 
1073 		nrows = gda_data_model_get_n_rows (model);
1074 		if (nrows >= 1) {
1075 			GdaDataModel *pkmodel;
1076 			sql = "SELECT column_name FROM _key_column_usage WHERE table_catalog = ##cc::string AND table_schema = ##cs::string AND table_name = ##tname::string AND constraint_name = ##cname::string ORDER BY ordinal_position";
1077 			cvalue = gda_data_model_get_value_at (model, 0, 0, error);
1078 			if (!cvalue) goto onerror;
1079 			pkmodel = gda_meta_store_extract (mstruct->priv->store, sql, error,
1080 							  "cc", icatalog,
1081 							  "cs", ischema,
1082 							  "tname", iname,
1083 							  "cname", cvalue, NULL);
1084 			if (!pkmodel) {
1085 				g_object_unref (model);
1086 				goto onerror;
1087 			}
1088 			nrows = gda_data_model_get_n_rows (pkmodel);
1089 			mt->pk_cols_nb = nrows;
1090 			mt->pk_cols_array = g_new0 (gint, mt->pk_cols_nb);
1091 			for (i = 0; i < nrows; i++) {
1092 				GdaMetaTableColumn *tcol;
1093 				cvalue = gda_data_model_get_value_at (pkmodel, 0, i, error);
1094 				if (!cvalue) goto onerror;
1095 				tcol = gda_meta_struct_get_table_column (mstruct, mt, cvalue);
1096 				if (!tcol) {
1097 					mt->pk_cols_array [i] = -1;
1098 					g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_INCOHERENCE_ERROR,
1099 						     _("Internal GdaMetaStore error: column %s not found"),
1100 						     g_value_get_string (cvalue));
1101 					goto onerror;
1102 				}
1103 				else {
1104 					mt->pk_cols_array [i] = g_slist_index (mt->columns, tcol);
1105 					tcol->pkey = TRUE;
1106 				}
1107 			}
1108 
1109 			g_object_unref (pkmodel);
1110 		}
1111 		g_object_unref (model);
1112 
1113 		/* foreign keys */
1114 		if (mstruct->priv->features & GDA_META_STRUCT_FEATURE_FOREIGN_KEYS) {
1115 			sql = "SELECT ref_table_catalog, ref_table_schema, ref_table_name, constraint_name, ref_constraint_name, update_rule, delete_rule, constraint_name FROM _referential_constraints WHERE table_catalog = ##tc::string AND table_schema = ##ts::string AND table_name = ##tname::string";
1116 			model = gda_meta_store_extract (mstruct->priv->store, sql, error,
1117 							"tc", icatalog,
1118 							"ts", ischema,
1119 							"tname", iname, NULL);
1120 			if (!model)
1121 				goto onerror;
1122 
1123 			nrows = gda_data_model_get_n_rows (model);
1124 			for (i = 0; i < nrows; i++) {
1125 				GdaMetaTableForeignKey *tfk = NULL;
1126 				const GValue *fk_catalog, *fk_schema, *fk_tname, *fk_name;
1127 				const GValue *upd_policy, *del_policy;
1128 
1129 				GdaDataModel *fk_cols = NULL;
1130 				GdaDataModel *ref_pk_cols = NULL;
1131 
1132 				fk_catalog = gda_data_model_get_value_at (model, 0, i, error);
1133 				if (!fk_catalog) goto onfkerror;
1134 				fk_schema = gda_data_model_get_value_at (model, 1, i, error);
1135 				if (!fk_schema) goto onfkerror;
1136 				fk_tname = gda_data_model_get_value_at (model, 2, i, error);
1137 				if (!fk_tname) goto onfkerror;
1138 				upd_policy = gda_data_model_get_value_at (model, 5, i, error);
1139 				if (!upd_policy) goto onfkerror;
1140 				del_policy = gda_data_model_get_value_at (model, 6, i, error);
1141 				if (!del_policy) goto onfkerror;
1142 				fk_name = gda_data_model_get_value_at (model, 7, i, error);
1143 				if (!fk_name) goto onfkerror;
1144 
1145 				tfk = g_new0 (GdaMetaTableForeignKey, 1);
1146 				tfk->meta_table = dbo;
1147 				tfk->fk_name = g_value_dup_string (fk_name);
1148 				tfk->depend_on = _meta_struct_get_db_object (mstruct, fk_catalog, fk_schema, fk_tname);
1149 				if (!tfk->depend_on) {
1150 					gchar *str;
1151 					tfk->depend_on = g_new0 (GdaMetaDbObject, 1);
1152 					tfk->depend_on->obj_type = GDA_META_DB_UNKNOWN;
1153 					tfk->depend_on->obj_catalog = g_strdup (g_value_get_string (fk_catalog));
1154 					tfk->depend_on->obj_schema = g_strdup (g_value_get_string (fk_schema));
1155 					tfk->depend_on->obj_name = g_strdup (g_value_get_string (fk_tname));
1156 					mstruct->priv->db_objects = g_slist_append (mstruct->priv->db_objects, tfk->depend_on);
1157 					str = g_strdup_printf ("%s.%s.%s", g_value_get_string (fk_catalog),
1158 							       g_value_get_string (fk_schema),
1159 							       g_value_get_string (fk_tname));
1160 					g_hash_table_insert (mstruct->priv->index, str, tfk->depend_on);
1161 				}
1162 				else if (tfk->depend_on->obj_type == GDA_META_DB_TABLE) {
1163 					GdaMetaTable *dot = GDA_META_TABLE (tfk->depend_on);
1164 					dot->reverse_fk_list = g_slist_prepend (dot->reverse_fk_list, tfk);
1165 				}
1166 				dbo->depend_list = g_slist_append (dbo->depend_list, tfk->depend_on);
1167 
1168 				if (G_VALUE_TYPE (upd_policy) == G_TYPE_STRING)
1169 					tfk->on_update_policy = policy_string_to_value (g_value_get_string (upd_policy));
1170 				else
1171 					tfk->on_update_policy = GDA_META_FOREIGN_KEY_UNKNOWN;
1172 
1173 				if (G_VALUE_TYPE (upd_policy) == G_TYPE_STRING)
1174 					tfk->on_delete_policy = policy_string_to_value (g_value_get_string (del_policy));
1175 				else
1176 					tfk->on_delete_policy = GDA_META_FOREIGN_KEY_UNKNOWN;
1177 
1178 				tfk->declared = FALSE;
1179 
1180 				/* FIXME: compute @cols_nb, and all the @*_array members (ref_pk_cols_array must be
1181 				 * initialized with -1 values everywhere */
1182 				sql = "SELECT k.column_name, c.ordinal_position FROM _key_column_usage k INNER JOIN _columns c ON (c.table_catalog = k.table_catalog AND c.table_schema = k.table_schema AND c.table_name=k.table_name AND c.column_name=k.column_name) WHERE k.table_catalog = ##tc::string AND k.table_schema = ##ts::string AND k.table_name = ##tname::string AND k.constraint_name = ##cname::string ORDER BY k.ordinal_position";
1183 				gboolean fkerror = FALSE;
1184 				cvalue = gda_data_model_get_value_at (model, 3, i, error);
1185 				if (!cvalue) goto onfkerror;
1186 				fk_cols = gda_meta_store_extract (mstruct->priv->store, sql, error,
1187 								  "tc", icatalog,
1188 								  "ts", ischema,
1189 								  "tname", iname,
1190 								  "cname", cvalue, NULL);
1191 				/*g_print ("tname=%s cvalue=%s\n", gda_value_stringify (iname),
1192 				  gda_value_stringify (cvalue));*/
1193 
1194 				cvalue = gda_data_model_get_value_at (model, 4, i, error);
1195 				if (!cvalue) goto onfkerror;
1196 				ref_pk_cols = gda_meta_store_extract (mstruct->priv->store, sql, error,
1197 								      "tc", fk_catalog,
1198 								      "ts", fk_schema,
1199 								      "tname", fk_tname,
1200 								      "cname", cvalue, NULL);
1201 				/*g_print ("tname=%s cvalue=%s\n", gda_value_stringify (fk_tname),
1202 				  gda_value_stringify (cvalue));*/
1203 
1204 				if (fk_cols && ref_pk_cols) {
1205 					gint fk_nrows, ref_pk_nrows;
1206 					fk_nrows = gda_data_model_get_n_rows (fk_cols);
1207 					ref_pk_nrows = gda_data_model_get_n_rows (ref_pk_cols);
1208 					if (fk_nrows != ref_pk_nrows) {
1209 						/*gda_data_model_dump (fk_cols, stdout);
1210 						  gda_data_model_dump (ref_pk_cols, stdout);*/
1211 						if (ref_pk_nrows > 0)
1212 							fkerror = TRUE;
1213 						else {
1214 							/* not an error, only the referenced table is not present
1215 							 * in the meta store, which is possible if the meta
1216 							 * store was only partially updated */
1217 						}
1218 					}
1219 					else {
1220 						gint n;
1221 						tfk->cols_nb = fk_nrows;
1222 						tfk->fk_cols_array = g_new0 (gint, fk_nrows);
1223 						tfk->fk_names_array = g_new0 (gchar *, fk_nrows);
1224 						tfk->ref_pk_cols_array = g_new0 (gint, fk_nrows);
1225 						tfk->ref_pk_names_array = g_new0 (gchar *, fk_nrows);
1226 						for (n = 0; n < fk_nrows; n++) {
1227 							const GValue *cv;
1228 							cv = gda_data_model_get_value_at (fk_cols, 1, n, error);
1229 							if (!cv) goto onfkerror;
1230 							tfk->fk_cols_array [n] = g_value_get_int (cv);
1231 
1232 							cv = gda_data_model_get_value_at (fk_cols, 0, n, error);
1233 							if (!cv) goto onfkerror;
1234 							tfk->fk_names_array [n] = g_value_dup_string (cv);
1235 
1236 							cv = gda_data_model_get_value_at (ref_pk_cols, 1, n, error);
1237 							if (!cv) goto onfkerror;
1238 							tfk->ref_pk_cols_array [n] = g_value_get_int (cv);
1239 
1240 							cv = gda_data_model_get_value_at (ref_pk_cols, 0, n, error);
1241 							if (!cv) goto onfkerror;
1242 							tfk->ref_pk_names_array [n] = g_value_dup_string (cv);
1243 						}
1244 					}
1245 				}
1246 				else
1247 					fkerror = TRUE;
1248 
1249 				if (fkerror) {
1250 					g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_INCOHERENCE_ERROR,
1251 						     _("Meta data incoherence in foreign key constraint for table %s.%s.%s "
1252 						       "referencing table %s.%s.%s"),
1253 						     g_value_get_string (icatalog),
1254 						     g_value_get_string (ischema),
1255 						     g_value_get_string (iname),
1256 						     g_value_get_string (fk_catalog),
1257 						     g_value_get_string (fk_schema),
1258 						     g_value_get_string (fk_tname));
1259 					goto onfkerror;
1260 				}
1261 				if (fk_cols)
1262 					g_object_unref (fk_cols);
1263 				if (ref_pk_cols)
1264 					g_object_unref (ref_pk_cols);
1265 
1266 				mt->fk_list = g_slist_prepend (mt->fk_list, tfk);
1267 				continue;
1268 
1269 			onfkerror:
1270 				if (fk_cols)
1271 					g_object_unref (fk_cols);
1272 				if (ref_pk_cols)
1273 					g_object_unref (ref_pk_cols);
1274 				if (tfk)
1275 					mt->fk_list = g_slist_prepend (mt->fk_list, tfk);
1276 				goto onerror;
1277 			}
1278 			mt->fk_list = g_slist_reverse (mt->fk_list);
1279 			g_object_unref (model);
1280 			/* Note: mt->reverse_fk_list is not determined here */
1281 
1282 			add_declared_foreign_keys (mstruct, mt, NULL);
1283 		}
1284 
1285 		break;
1286 	}
1287 	default:
1288 		TO_IMPLEMENT;
1289 	}
1290 
1291 	if (dbo && !g_slist_find (mstruct->priv->db_objects, dbo)) {
1292 		gchar *str;
1293 		mstruct->priv->db_objects = g_slist_append (mstruct->priv->db_objects, dbo);
1294 		str = g_strdup_printf ("%s.%s.%s", g_value_get_string (icatalog),
1295 				       g_value_get_string (ischema),
1296 				       g_value_get_string (iname));
1297 		g_hash_table_insert (mstruct->priv->index, str, dbo);
1298 	}
1299 	if (dbo && (dbo->obj_type == GDA_META_DB_TABLE) &&
1300 	    (mstruct->priv->features & GDA_META_STRUCT_FEATURE_FOREIGN_KEYS)) {
1301 		/* compute GdaMetaTableForeignKey's @ref_pk_cols_array arrays and GdaMetaTable' @reverse_fk_list lists*/
1302 		GSList *list;
1303 		for (list = mstruct->priv->db_objects; list; list = list->next) {
1304 			GdaMetaDbObject *tmpdbo;
1305 			tmpdbo = GDA_META_DB_OBJECT (list->data);
1306 			if (tmpdbo->obj_type != GDA_META_DB_TABLE)
1307 				continue;
1308 
1309 			GdaMetaTable *mt = GDA_META_TABLE (tmpdbo);
1310 			GSList *klist;
1311 			for (klist = mt->fk_list; klist; klist = klist->next) {
1312 				GdaMetaTableForeignKey *tfk = GDA_META_TABLE_FOREIGN_KEY (klist->data);
1313 				GdaMetaTable *ref_mt = GDA_META_TABLE (tfk->depend_on);
1314 				gint i;
1315 
1316 				if (tfk->depend_on != dbo)
1317 					continue;
1318 
1319 				for (i = 0; i < tfk->cols_nb; i++) {
1320 					gint col;
1321 					GdaMetaTableColumn *r_tcol;
1322 					GValue *r_val;
1323 
1324 					if (tfk->ref_pk_cols_array[i] != -1) /* already correctly set */
1325 						continue;
1326 
1327 					if (tfk->depend_on->obj_type != GDA_META_DB_TABLE)
1328 						continue; /* can't be set now */
1329 
1330 					g_value_set_string ((r_val = gda_value_new (G_TYPE_STRING)), tfk->ref_pk_names_array[i]);
1331 					r_tcol = gda_meta_struct_get_table_column (mstruct, ref_mt, r_val);
1332 					gda_value_free (r_val);
1333 					col = g_slist_index (ref_mt->columns, r_tcol);
1334 					if (!r_tcol || (col < 0)) {
1335 						g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_INCOHERENCE_ERROR,
1336 							     _("Foreign key column '%s' not found in table '%s'"),
1337 							     tfk->ref_pk_names_array[i], tfk->depend_on->obj_name);
1338 						dbo = NULL;
1339 						goto onerror;
1340 					}
1341 					tfk->ref_pk_cols_array[i] = col;
1342 				}
1343 
1344 				GDA_META_TABLE (dbo)->reverse_fk_list = g_slist_append (GDA_META_TABLE (dbo)->reverse_fk_list,
1345 											tfk);
1346 			}
1347 		}
1348 	}
1349 	return dbo;
1350 
1351  onerror:
1352 	if (dbo)
1353 		dbo->obj_type = GDA_META_DB_UNKNOWN;
1354 
1355 	return NULL;
1356 }
1357 
1358 static gchar *
array_type_to_sql(GdaMetaStore * store,const GValue * specific_name)1359 array_type_to_sql (GdaMetaStore *store, const GValue *specific_name)
1360 {
1361 	gchar *str;
1362 	GdaDataModel *model;
1363 	gint nrows;
1364 	const GValue *cvalue;
1365 
1366 	if (!specific_name || gda_value_is_null (specific_name))
1367 		return g_strdup ("[]");
1368 
1369 	model = gda_meta_store_extract (store, 	"SELECT data_type, array_spec FROM _element_types WHERE specific_name = ##name::string",
1370 					NULL, "name", specific_name, NULL);
1371 	if (!model)
1372 		return g_strdup ("[]");
1373 	nrows = gda_data_model_get_n_rows (model);
1374 	if (nrows != 1) {
1375 		g_object_unref (model);
1376 		return g_strdup ("[]");
1377 	}
1378 
1379 	cvalue = gda_data_model_get_value_at (model, 0, 0, NULL);
1380 	if (!cvalue)
1381 		return NULL;
1382 	if (gda_value_is_null (cvalue) || !g_value_get_string (cvalue)) {
1383 		/* use array_spec */
1384 		gchar *str2;
1385 		cvalue = gda_data_model_get_value_at (model, 1, 0, NULL);
1386 		if (!cvalue)
1387 			return NULL;
1388 		str2 = array_type_to_sql (store, cvalue);
1389 		str = g_strdup_printf ("%s[]", str2);
1390 		g_free (str2);
1391 	}
1392 	else {
1393 		cvalue = gda_data_model_get_value_at (model, 0, 0, NULL);
1394 		if (!cvalue)
1395 			return NULL;
1396 		str = g_strdup_printf ("%s[]", g_value_get_string (cvalue));
1397 	}
1398 	g_object_unref (model);
1399 	return str;
1400 }
1401 
1402 
1403 /**
1404  * gda_meta_struct_complement_schema:
1405  * @mstruct: a #GdaMetaStruct object
1406  * @catalog: (allow-none): name of a catalog, or %NULL
1407  * @schema: (allow-none): name of a schema, or %NULL
1408  * @error: (allow-none): a place to store errors, or %NULL
1409  *
1410  * This method is similar to gda_meta_struct_complement() but creates #GdaMetaDbObject for all the
1411  * database object which are in the @schema schema (and in the @catalog catalog).
1412  * If @catalog is %NULL, then any catalog will be used, and
1413  * if @schema is %NULL then any schema will be used (if @schema is %NULL then catalog must also be %NULL).
1414  *
1415  * Please refer to gda_meta_struct_complement() form more information.
1416  *
1417  * Returns: TRUE if no error occurred
1418  */
1419 gboolean
gda_meta_struct_complement_schema(GdaMetaStruct * mstruct,const GValue * catalog,const GValue * schema,GError ** error)1420 gda_meta_struct_complement_schema (GdaMetaStruct *mstruct, const GValue *catalog, const GValue *schema,
1421 				   GError **error)
1422 {
1423 	GdaDataModel *tables_model = NULL, *views_model = NULL;
1424 	gint i, nrows, k;
1425 	const GValue *cvalues[6];
1426 
1427 	/* schema and catalog are known */
1428 	const gchar *sql1 = "SELECT table_name "
1429 		"FROM _tables WHERE table_short_name, table_full_name, table_owner, table_catalog = ##cat::string AND table_schema = ##schema::string "
1430 		"AND table_type LIKE '%TABLE%' "
1431 		"ORDER BY table_schema, table_name";
1432 	const gchar *sql2 = "SELECT table_short_name, table_full_name, table_owner, table_name "
1433 		"FROM _tables WHERE table_catalog = ##cat::string AND table_schema = ##schema::string "
1434 		"AND table_type LIKE '%VIEW%' "
1435 		"ORDER BY table_schema, table_name";
1436 
1437 	/* schema is known, catalog unknown */
1438 	const gchar *sql3 = "SELECT table_short_name, table_full_name, table_owner, table_name, table_catalog, table_schema "
1439 		"FROM _tables WHERE table_schema = ##schema::string AND table_type LIKE '%TABLE%' "
1440 		"ORDER BY table_schema, table_name";
1441 	const gchar *sql4 = "SELECT table_short_name, table_full_name, table_owner, table_name, table_catalog, table_schema "
1442 		"FROM _tables WHERE table_schema = ##schema::string AND table_type LIKE '%VIEW%' "
1443 		"ORDER BY table_schema, table_name";
1444 
1445 	/* schema and catalog are unknown */
1446 	const gchar *sql5 = "SELECT table_short_name, table_full_name, table_owner, table_name, table_catalog, table_schema "
1447 		"FROM _tables WHERE table_type LIKE '%TABLE%' "
1448 		"ORDER BY table_schema, table_name";
1449 	const gchar *sql6 = "SELECT table_short_name, table_full_name, table_owner, table_name, table_catalog, table_schema "
1450 		"FROM _tables WHERE table_type LIKE '%VIEW%' "
1451 		"ORDER BY table_schema, table_name";
1452 
1453 	g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), FALSE);
1454 	g_return_val_if_fail (mstruct->priv->store, FALSE);
1455 	g_return_val_if_fail (!catalog || (catalog && schema), FALSE);
1456 	g_return_val_if_fail (!catalog || (G_VALUE_TYPE (catalog) == G_TYPE_STRING), FALSE);
1457 	g_return_val_if_fail (!schema || (G_VALUE_TYPE (schema) == G_TYPE_STRING), FALSE);
1458 
1459 	if (schema) {
1460 		if (catalog) {
1461 			tables_model = gda_meta_store_extract (mstruct->priv->store, sql1, error,
1462 							       "cat", catalog, "schema", schema, NULL);
1463 			if (tables_model)
1464 				views_model = gda_meta_store_extract (mstruct->priv->store, sql2, error,
1465 								      "cat", catalog, "schema", schema, NULL);
1466 		}
1467 		else {
1468 			tables_model = gda_meta_store_extract (mstruct->priv->store, sql3,
1469 							       error, "schema", schema, NULL);
1470 			if (tables_model)
1471 				views_model = gda_meta_store_extract (mstruct->priv->store, sql4,
1472 								      error, "schema", schema, NULL);
1473 		}
1474 	}
1475 	else {
1476 		tables_model = gda_meta_store_extract (mstruct->priv->store, sql5, error, NULL);
1477 		if (tables_model)
1478 			views_model = gda_meta_store_extract (mstruct->priv->store, sql6, error, NULL);
1479 	}
1480 
1481 	if (!tables_model || !views_model)
1482 		return FALSE;
1483 
1484 	/* tables */
1485 	nrows = gda_data_model_get_n_rows (tables_model);
1486 	for (i = 0; i < nrows; i++) {
1487 		for (k = 0; k <= 5; k++) {
1488 			cvalues [k] = gda_data_model_get_value_at (tables_model, k, i, error);
1489 			if (!cvalues [k]) {
1490 				g_object_unref (tables_model);
1491 				g_object_unref (views_model);
1492 				return FALSE;
1493 			}
1494 		}
1495 		if (!_meta_struct_complement (mstruct, GDA_META_DB_TABLE,
1496 					      catalog ? catalog : cvalues [4],
1497 					      schema ? schema : cvalues [5],
1498 					      cvalues [3],
1499 					      cvalues [0],
1500 					      cvalues [1],
1501 					      cvalues [2], error)) {
1502 			g_object_unref (tables_model);
1503 			g_object_unref (views_model);
1504 			return FALSE;
1505 		}
1506 	}
1507 	g_object_unref (tables_model);
1508 
1509 	/* views */
1510 	nrows = gda_data_model_get_n_rows (views_model);
1511 	for (i = 0; i < nrows; i++) {
1512 		for (k = 0; k <= 5; k++) {
1513 			cvalues [k] = gda_data_model_get_value_at (views_model, k, i, error);
1514 			if (!cvalues [k]) {
1515 				g_object_unref (views_model);
1516 				return FALSE;
1517 			}
1518 		}
1519 		if (!_meta_struct_complement (mstruct, GDA_META_DB_VIEW,
1520 					      catalog ? catalog : cvalues [4],
1521 					      schema ? schema : cvalues [5],
1522 					      cvalues [3],
1523 					      cvalues [0],
1524 					      cvalues [1],
1525 					      cvalues [2], error)) {
1526 			g_object_unref (views_model);
1527 			return FALSE;
1528 		}
1529 	}
1530 	g_object_unref (views_model);
1531 
1532 	return TRUE;
1533 }
1534 
1535 static gboolean
real_gda_meta_struct_complement_all(GdaMetaStruct * mstruct,gboolean default_only,GError ** error)1536 real_gda_meta_struct_complement_all (GdaMetaStruct *mstruct, gboolean default_only, GError **error)
1537 {
1538 	GdaDataModel *model;
1539 	gint i, nrows, k;
1540 	const GValue *cvalues[6];
1541 	const gchar *sql1 = "SELECT table_catalog, table_schema, table_name, table_short_name, table_full_name, table_owner "
1542 		"FROM _tables WHERE table_short_name = table_name AND table_type LIKE '%TABLE%' "
1543 		"ORDER BY table_schema, table_name";
1544 	const gchar *sql2 = "SELECT table_catalog, table_schema, table_name, table_short_name, table_full_name, table_owner "
1545 		"FROM _tables WHERE table_short_name = table_name AND table_type='VIEW' "
1546 		"ORDER BY table_schema, table_name";
1547 	const gchar *sql3 = "SELECT table_catalog, table_schema, table_name, table_short_name, table_full_name, table_owner "
1548 		"FROM _tables WHERE table_type LIKE '%TABLE%' "
1549 		"ORDER BY table_schema, table_name";
1550 	const gchar *sql4 = "SELECT table_catalog, table_schema, table_name, table_short_name, table_full_name, table_owner "
1551 		"FROM _tables WHERE table_type='VIEW' "
1552 		"ORDER BY table_schema, table_name";
1553 
1554 	g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), FALSE);
1555 	g_return_val_if_fail (mstruct->priv->store, FALSE);
1556 
1557 	/* tables */
1558 	model = gda_meta_store_extract (mstruct->priv->store, default_only ? sql1 : sql3, error, NULL);
1559 	if (!model)
1560 		return FALSE;
1561 	nrows = gda_data_model_get_n_rows (model);
1562 	for (i = 0; i < nrows; i++) {
1563 		for (k = 0; k <= 5; k++) {
1564 			cvalues [k] = gda_data_model_get_value_at (model, k, i, error);
1565 			if (!cvalues [k]) {
1566 				g_object_unref (model);
1567 				return FALSE;
1568 			}
1569 		}
1570 		if (!_meta_struct_complement (mstruct, GDA_META_DB_TABLE,
1571 					      cvalues [0], cvalues [1],
1572 					      cvalues [2], cvalues [3],
1573 					      cvalues [4], cvalues [5], error)) {
1574 			g_object_unref (model);
1575 			return FALSE;
1576 		}
1577 	}
1578 	g_object_unref (model);
1579 
1580 	/* views */
1581 	model = gda_meta_store_extract (mstruct->priv->store, default_only ? sql2 : sql4, error, NULL);
1582 	if (!model)
1583 		return FALSE;
1584 	nrows = gda_data_model_get_n_rows (model);
1585 	for (i = 0; i < nrows; i++) {
1586 		for (k = 0; k <= 5; k++) {
1587 			cvalues [k] = gda_data_model_get_value_at (model, k, i, error);
1588 			if (!cvalues [k]) {
1589 				g_object_unref (model);
1590 				return FALSE;
1591 			}
1592 		}
1593 		if (!_meta_struct_complement (mstruct, GDA_META_DB_VIEW,
1594 					      cvalues [0], cvalues [1],
1595 					      cvalues [2], cvalues [3],
1596 					      cvalues [4], cvalues [5], error)) {
1597 			g_object_unref (model);
1598 			return FALSE;
1599 		}
1600 	}
1601 	g_object_unref (model);
1602 	return TRUE;
1603 }
1604 
1605 /**
1606  * gda_meta_struct_complement_default:
1607  * @mstruct: a #GdaMetaStruct object
1608  * @error: (allow-none): a place to store errors, or %NULL
1609  *
1610  * This method is similar to gda_meta_struct_complement() and gda_meta_struct_complement_all()
1611  * but creates #GdaMetaDbObject for all the
1612  * database object which are usable using only their short name (that is which do not need to be prefixed by
1613  * the schema in which they are to be used).
1614  *
1615  * Please refer to gda_meta_struct_complement() form more information.
1616  *
1617  * Returns: TRUE if no error occurred
1618  */
1619 gboolean
gda_meta_struct_complement_default(GdaMetaStruct * mstruct,GError ** error)1620 gda_meta_struct_complement_default (GdaMetaStruct *mstruct, GError **error)
1621 {
1622 	return real_gda_meta_struct_complement_all (mstruct, TRUE, error);
1623 }
1624 
1625 /**
1626  * gda_meta_struct_complement_all:
1627  * @mstruct: a #GdaMetaStruct object
1628  * @error: (allow-none): a place to store errors, or %NULL
1629  *
1630  * This method is similar to gda_meta_struct_complement() and gda_meta_struct_complement_default()
1631  * but creates #GdaMetaDbObject for all the database object.
1632  *
1633  * Please refer to gda_meta_struct_complement() form more information.
1634  *
1635  * Returns: TRUE if no error occurred
1636  */
1637 gboolean
gda_meta_struct_complement_all(GdaMetaStruct * mstruct,GError ** error)1638 gda_meta_struct_complement_all (GdaMetaStruct *mstruct, GError **error)
1639 {
1640 	return real_gda_meta_struct_complement_all (mstruct, FALSE, error);
1641 }
1642 
1643 /**
1644  * gda_meta_struct_complement_depend:
1645  * @mstruct: a #GdaMetaStruct object
1646  * @dbo: a #GdaMetaDbObject part of @mstruct
1647  * @error: (allow-none): a place to store errors, or %NULL
1648  *
1649  * This method is similar to gda_meta_struct_complement() but creates #GdaMetaDbObject for all the dependencies
1650  * of @dbo.
1651  *
1652  * Please refer to gda_meta_struct_complement() form more information.
1653  *
1654  * Returns: TRUE if no error occurred
1655  */
1656 gboolean
gda_meta_struct_complement_depend(GdaMetaStruct * mstruct,GdaMetaDbObject * dbo,GError ** error)1657 gda_meta_struct_complement_depend (GdaMetaStruct *mstruct, GdaMetaDbObject *dbo,
1658 				   GError **error)
1659 {
1660 	GSList *list;
1661 
1662 	g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), FALSE);
1663 	g_return_val_if_fail (mstruct->priv->store, FALSE);
1664 	g_return_val_if_fail (dbo, FALSE);
1665 	g_return_val_if_fail (g_slist_find (mstruct->priv->db_objects, dbo), FALSE);
1666 
1667 	for (list = dbo->depend_list; list; list = list->next) {
1668 		GdaMetaDbObject *dep_dbo = GDA_META_DB_OBJECT (list->data);
1669 		if (dep_dbo->obj_type != GDA_META_DB_UNKNOWN)
1670 			continue;
1671 
1672 		GValue *cat = NULL, *schema = NULL, *name = NULL;
1673 		GdaMetaDbObject *tmpobj;
1674 		g_return_val_if_fail (dep_dbo->obj_name, FALSE);
1675 		if (dep_dbo->obj_catalog)
1676 			g_value_take_string ((cat = gda_value_new (G_TYPE_STRING)),
1677 					     g_strdup_printf ("\"%s\"", dep_dbo->obj_catalog));
1678 		if (dep_dbo->obj_schema)
1679 			g_value_take_string ((schema = gda_value_new (G_TYPE_STRING)),
1680 					     g_strdup_printf ("\"%s\"", dep_dbo->obj_schema));
1681 		g_value_take_string ((name = gda_value_new (G_TYPE_STRING)),
1682 				     g_strdup_printf ("\"%s\"", dep_dbo->obj_name));
1683 		tmpobj = gda_meta_struct_complement (mstruct, GDA_META_DB_UNKNOWN, cat, schema, name, error);
1684 		if (cat) gda_value_free (cat);
1685 		if (schema) gda_value_free (schema);
1686 		gda_value_free (name);
1687 		if (!tmpobj)
1688 			return FALSE;
1689 	}
1690 	return TRUE;
1691 }
1692 
1693 
1694 /*
1695  * Makes a list of all the GdaMetaDbObject structures listed in @objects
1696  * which are not present in @ordered_list and for which no dependency is in @ordered_list
1697  */
1698 static GSList *
build_pass(GSList * objects,GSList * ordered_list)1699 build_pass (GSList *objects, GSList *ordered_list)
1700 {
1701 	GSList *retlist = NULL, *list;
1702 
1703 	for (list = objects; list; list = list->next) {
1704 		gboolean has_dep = FALSE;
1705 		GSList *dep_list;
1706 		if (g_slist_find (ordered_list, list->data))
1707 			continue;
1708 		for (dep_list = GDA_META_DB_OBJECT (list->data)->depend_list; dep_list; dep_list = dep_list->next) {
1709 			if (!g_slist_find (ordered_list, dep_list->data)) {
1710 				has_dep = TRUE;
1711 				break;
1712 			}
1713 		}
1714 		if (has_dep)
1715 			continue;
1716 		retlist = g_slist_prepend (retlist, list->data);
1717 	}
1718 
1719 #ifdef GDA_DEBUG_NO
1720 	g_print (">> PASS\n");
1721 	for (list = retlist; list; list = list->next)
1722 		g_print ("--> %s\n", GDA_META_DB_OBJECT (list->data)->obj_name);
1723 	g_print ("<<\n");
1724 #endif
1725 
1726 	return retlist;
1727 }
1728 
1729 static gint
db_object_sort_func(GdaMetaDbObject * dbo1,GdaMetaDbObject * dbo2)1730 db_object_sort_func (GdaMetaDbObject *dbo1, GdaMetaDbObject *dbo2)
1731 {
1732 	gint retval = 0;
1733 	if (dbo1->obj_schema && dbo2->obj_schema) {
1734 		retval = strcmp (dbo1->obj_schema, dbo2->obj_schema);
1735 		if (retval)
1736 			return retval;
1737 	}
1738 	else if (dbo1->obj_schema)
1739 		return 1;
1740 	else if (dbo2->obj_schema)
1741 		return -1;
1742 
1743 	if (dbo1->obj_name && dbo2->obj_name)
1744 		return strcmp (dbo1->obj_name, dbo2->obj_name);
1745 	else if (dbo1->obj_name)
1746 		return 1;
1747 	else if (dbo2->obj_name)
1748 		return -1;
1749 	return 0;
1750 }
1751 
1752 /**
1753  * gda_meta_struct_sort_db_objects:
1754  * @mstruct: a #GdaMetaStruct object
1755  * @sort_type: the kind of sorting requested
1756  * @error: (allow-none): a place to store errors, or %NULL
1757  *
1758  * Reorders the list of database objects within @mstruct in a way specified by @sort_type.
1759  *
1760  * Returns: TRUE if no error occurred
1761  */
1762 gboolean
gda_meta_struct_sort_db_objects(GdaMetaStruct * mstruct,GdaMetaSortType sort_type,G_GNUC_UNUSED GError ** error)1763 gda_meta_struct_sort_db_objects (GdaMetaStruct *mstruct, GdaMetaSortType sort_type,
1764 				 G_GNUC_UNUSED GError **error)
1765 {
1766 	GSList *pass_list;
1767 	GSList *ordered_list = NULL;
1768 
1769 	g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), FALSE);
1770 
1771 	switch (sort_type) {
1772 	case GDA_META_SORT_ALHAPETICAL:
1773 		mstruct->priv->db_objects = g_slist_sort (mstruct->priv->db_objects, (GCompareFunc) db_object_sort_func);
1774 		ordered_list = mstruct->priv->db_objects;
1775 		break;
1776 	case GDA_META_SORT_DEPENDENCIES:
1777 		g_return_val_if_fail (mstruct, FALSE);
1778 		for (pass_list = build_pass (mstruct->priv->db_objects, ordered_list);
1779 		     pass_list;
1780 		     pass_list = build_pass (mstruct->priv->db_objects, ordered_list))
1781 			ordered_list = g_slist_concat (ordered_list, pass_list);
1782 		g_slist_free (mstruct->priv->db_objects);
1783 		mstruct->priv->db_objects = ordered_list;
1784 		break;
1785 	default:
1786 		TO_IMPLEMENT;
1787 		break;
1788 	}
1789 
1790 #ifdef GDA_DEBUG_NO
1791 	GSList *list;
1792 	for (list = ordered_list; list; list = list->next)
1793 		g_print ("--> %s\n", GDA_META_DB_OBJECT (list->data)->obj_name);
1794 #endif
1795 	return TRUE;
1796 }
1797 
1798 /*
1799  * Same as gda_meta_struct_get_db_object except that @catalog, @schema and @name are ready to be
1800  * compared (no need to double quote)
1801  */
1802 static GdaMetaDbObject *
_meta_struct_get_db_object(GdaMetaStruct * mstruct,const GValue * catalog,const GValue * schema,const GValue * name)1803 _meta_struct_get_db_object (GdaMetaStruct *mstruct, const GValue *catalog, const GValue *schema, const GValue *name)
1804 {
1805 	gchar *key;
1806 	GdaMetaDbObject *dbo;
1807 
1808 	if (catalog && schema) {
1809 		g_return_val_if_fail (G_VALUE_TYPE (catalog) == G_TYPE_STRING, NULL);
1810 		g_return_val_if_fail (G_VALUE_TYPE (schema) == G_TYPE_STRING, NULL);
1811 
1812 		key = g_strdup_printf ("%s.%s.%s", g_value_get_string (catalog), g_value_get_string (schema),
1813 				       g_value_get_string (name));
1814 		dbo = g_hash_table_lookup (mstruct->priv->index, key);
1815 		g_free (key);
1816 		return dbo;
1817 	}
1818 	else {
1819 		/* walk through all the objects, and pick the ones with a matching name */
1820 		GSList *list;
1821 		GSList *matching = NULL;
1822 		const gchar *obj_name = g_value_get_string (name);
1823 		const gchar *obj_schema = NULL, *obj_catalog = NULL;
1824 		if (catalog) {
1825 			g_return_val_if_fail (G_VALUE_TYPE (catalog) == G_TYPE_STRING, NULL);
1826 			obj_catalog = g_value_get_string (catalog);
1827 		}
1828 		if (schema) {
1829 			g_return_val_if_fail (G_VALUE_TYPE (schema) == G_TYPE_STRING, NULL);
1830 			obj_schema = g_value_get_string (schema);
1831 		}
1832 
1833 		for (list = mstruct->priv->db_objects; list; list = list->next) {
1834 			GdaMetaDbObject *dbo;
1835 			dbo = GDA_META_DB_OBJECT (list->data);
1836 			if (gda_identifier_equal (dbo->obj_name, obj_name) &&
1837 			    (!obj_schema || gda_identifier_equal (dbo->obj_schema, obj_schema)) &&
1838 			    (!obj_catalog || gda_identifier_equal (dbo->obj_catalog, obj_catalog)))
1839 				matching = g_slist_prepend (matching, dbo);
1840 		}
1841 
1842 		if (matching && !matching->next) {
1843 			GdaMetaDbObject *dbo = GDA_META_DB_OBJECT (matching->data);
1844 			g_slist_free (matching);
1845 			return dbo;
1846 		}
1847 		else {
1848 			/* none or more than one found => return NULL */
1849 			if (matching)
1850 				g_slist_free (matching);
1851 			return NULL;
1852 		}
1853 	}
1854 }
1855 
1856 /**
1857  * gda_meta_struct_get_all_db_objects:
1858  * @mstruct: a #GdaMetaStruct object
1859  *
1860  * Get a list of all the #GdaMetaDbObject structures representing database objects in @mstruct. Note that
1861  * no #GdaMetaDbObject structure must not be modified.
1862  *
1863  * Returns: (transfer container) (element-type Gda.MetaDbObject): a new #GSList list of pointers to
1864  * #GdaMetaDbObject structures which must be destroyed after usage using g_slist_free(). The individual
1865  * #GdaMetaDbObject must not be modified.
1866  */
1867 GSList *
gda_meta_struct_get_all_db_objects(GdaMetaStruct * mstruct)1868 gda_meta_struct_get_all_db_objects (GdaMetaStruct *mstruct)
1869 {
1870 	g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), NULL);
1871 	if (mstruct->priv->db_objects)
1872 		return g_slist_copy (mstruct->priv->db_objects);
1873 	else
1874 		return NULL;
1875 }
1876 
1877 /**
1878  * gda_meta_struct_get_db_object:
1879  * @mstruct: a #GdaMetaStruct object
1880  * @catalog: (allow-none): the catalog the object belongs to (as a G_TYPE_STRING GValue), or %NULL
1881  * @schema: (allow-none): the schema the object belongs to (as a G_TYPE_STRING GValue), or %NULL
1882  * @name: the object's name (as a G_TYPE_STRING GValue), not %NULL
1883  *
1884  * Tries to locate the #GdaMetaDbObject structure representing the database object named after
1885  * @catalog, @schema and @name.
1886  *
1887  * If one or both of @catalog and @schema are %NULL, and more than one database object matches the name, then
1888  * the return value is also %NULL.
1889  *
1890  * Returns: (transfer none): the #GdaMetaDbObject or %NULL if not found
1891  */
1892 GdaMetaDbObject *
gda_meta_struct_get_db_object(GdaMetaStruct * mstruct,const GValue * catalog,const GValue * schema,const GValue * name)1893 gda_meta_struct_get_db_object (GdaMetaStruct *mstruct, const GValue *catalog, const GValue *schema, const GValue *name)
1894 {
1895 	GdaMetaDbObject *dbo;
1896 	GValue *icatalog = NULL, *ischema = NULL, *iname = NULL; /* GValue with identifiers ready to be compared */
1897 
1898 	g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), NULL);
1899 	g_return_val_if_fail (name && (G_VALUE_TYPE (name) == G_TYPE_STRING), NULL);
1900 	g_return_val_if_fail (!catalog || (catalog && schema), NULL);
1901 	g_return_val_if_fail (!catalog || (G_VALUE_TYPE (catalog) == G_TYPE_STRING), NULL);
1902 	g_return_val_if_fail (!schema || (G_VALUE_TYPE (schema) == G_TYPE_STRING), NULL);
1903 
1904 	/* prepare identifiers */
1905 	g_value_take_string ((iname = gda_value_new (G_TYPE_STRING)), prepare_sql_identifier_for_compare (g_value_dup_string (name)));
1906 	if (catalog)
1907 		g_value_take_string ((icatalog = gda_value_new (G_TYPE_STRING)),
1908 				     prepare_sql_identifier_for_compare (g_value_dup_string (catalog)));
1909 	if (schema)
1910 		g_value_take_string ((ischema = gda_value_new (G_TYPE_STRING)),
1911 				     prepare_sql_identifier_for_compare (g_value_dup_string (schema)));
1912 
1913 	dbo = _meta_struct_get_db_object (mstruct, icatalog, ischema, iname);
1914 	if (icatalog) gda_value_free (icatalog);
1915 	if (ischema) gda_value_free (ischema);
1916 	gda_value_free (iname);
1917 
1918 	return dbo;
1919 }
1920 
1921 /**
1922  * gda_meta_struct_get_table_column: (skip)
1923  * @mstruct: a #GdaMetaStruct object
1924  * @table: the #GdaMetaTable structure to find the column for
1925  * @col_name: the name of the column to find (as a G_TYPE_STRING GValue)
1926  *
1927  * Tries to find the #GdaMetaTableColumn representing the column named @col_name in @table.
1928  *
1929  * Returns: (transfer none): the #GdaMetaTableColumn or %NULL if not found
1930  */
1931 GdaMetaTableColumn *
gda_meta_struct_get_table_column(GdaMetaStruct * mstruct,GdaMetaTable * table,const GValue * col_name)1932 gda_meta_struct_get_table_column (GdaMetaStruct *mstruct, GdaMetaTable *table, const GValue *col_name)
1933 {
1934 	GSList *list;
1935 	const gchar *cname;
1936 
1937 	g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), NULL);
1938 	g_return_val_if_fail (table, NULL);
1939 	g_return_val_if_fail (col_name && (G_VALUE_TYPE (col_name) == G_TYPE_STRING), NULL);
1940 	cname = g_value_get_string (col_name);
1941 
1942 	for (list = table->columns; list; list = list->next) {
1943 		GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data);
1944 		if (gda_identifier_equal (tcol->column_name, cname))
1945 			return tcol;
1946 	}
1947 	return NULL;
1948 }
1949 
1950 /**
1951  * gda_meta_struct_dump_as_graph:
1952  * @mstruct: a #GdaMetaStruct object
1953  * @info: informs what kind of information to show in the resulting graph
1954  * @error: (allow-none): a place to store errors, or %NULL
1955  *
1956  * Creates a new graph (in the GraphViz syntax) representation of @mstruct.
1957  *
1958  * Returns: (transfer full): a new string, or %NULL if an error occurred.
1959  */
1960 gchar *
gda_meta_struct_dump_as_graph(GdaMetaStruct * mstruct,GdaMetaGraphInfo info,G_GNUC_UNUSED GError ** error)1961 gda_meta_struct_dump_as_graph (GdaMetaStruct *mstruct, GdaMetaGraphInfo info, G_GNUC_UNUSED GError **error)
1962 {
1963 	GString *string;
1964 	gchar *result;
1965 
1966 	g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), NULL);
1967 
1968 	string = g_string_new ("digraph G {\nrankdir = BT;\nnode [shape = plaintext];\n");
1969 	GSList *dbo_list;
1970 	for (dbo_list = mstruct->priv->db_objects; dbo_list; dbo_list = dbo_list->next) {
1971 		gchar *objname, *fullname;
1972 		GdaMetaDbObject *dbo = GDA_META_DB_OBJECT (dbo_list->data);
1973 		GSList *list;
1974 		gboolean use_html = (info & GDA_META_GRAPH_COLUMNS) ? TRUE : FALSE;
1975 
1976 		/* obj human readable name, and full name */
1977 		fullname = g_strdup_printf ("%s.%s.%s", dbo->obj_catalog, dbo->obj_schema, dbo->obj_name);
1978 		if (dbo->obj_short_name)
1979 			objname = g_strdup (dbo->obj_short_name);
1980 		else if (dbo->obj_schema)
1981 			objname = g_strdup_printf ("%s.%s", dbo->obj_schema, dbo->obj_name);
1982 		else
1983 			objname = g_strdup (dbo->obj_name);
1984 
1985 		/* node */
1986 		switch (dbo->obj_type) {
1987 		case GDA_META_DB_UNKNOWN:
1988 			break;
1989 		case GDA_META_DB_TABLE:
1990 			if (use_html) {
1991 				g_string_append_printf (string, "\"%s\" [label=<<TABLE BORDER=\"1\" CELLBORDER=\"0\" CELLSPACING=\"0\">", fullname);
1992 				g_string_append_printf (string, "<TR><TD COLSPAN=\"2\" BGCOLOR=\"grey\" BORDER=\"1\">%s</TD></TR>", objname);
1993 			}
1994 			else
1995 				g_string_append_printf (string, "\"%s\" [ shape = box label = \"%s\" ]", fullname, objname);
1996 			break;
1997 		case GDA_META_DB_VIEW:
1998 			if (use_html) {
1999 				g_string_append_printf (string, "\"%s\" [label=<<TABLE BORDER=\"1\" CELLBORDER=\"0\" CELLSPACING=\"0\">", fullname);
2000 				g_string_append_printf (string, "<TR><TD BGCOLOR=\"yellow\" BORDER=\"1\">%s</TD></TR>", objname);
2001 			}
2002 			else
2003 				g_string_append_printf (string, "\"%s\" [ shape = ellipse, label = \"%s\" ]", fullname, objname);
2004 			break;
2005 		default:
2006 			TO_IMPLEMENT;
2007 			g_string_append_printf (string, "\"%s\" [ shape = note label = \"%s\" ]", fullname, objname);
2008 			break;
2009 		}
2010 
2011 		/* columns, only for tables */
2012 		if (dbo->obj_type == GDA_META_DB_TABLE) {
2013 			GdaMetaTable *mt = GDA_META_TABLE (dbo);
2014 			GSList *depend_dbo_list = NULL;
2015 			if (info & GDA_META_GRAPH_COLUMNS) {
2016 				for (list = mt->columns; list; list = list->next) {
2017 					GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data);
2018 					GString *extra = g_string_new ("");
2019 					if (tcol->pkey)
2020 						g_string_append_printf (extra, "key");
2021 					g_string_append_printf (string, "<TR><TD ALIGN=\"left\">%s</TD><TD ALIGN=\"right\">%s</TD></TR>",
2022 								tcol->column_name, extra->str);
2023 					g_string_free (extra, TRUE);
2024 				}
2025 			}
2026 			if (use_html)
2027 				g_string_append (string, "</TABLE>>];\n");
2028 			/* foreign keys */
2029 			for (list = mt->fk_list; list; list = list->next) {
2030 				GdaMetaTableForeignKey *tfk = GDA_META_TABLE_FOREIGN_KEY (list->data);
2031 				if (tfk->depend_on->obj_type != GDA_META_DB_UNKNOWN) {
2032 					g_string_append_printf (string, "\"%s\" -> \"%s.%s.%s\";\n", fullname,
2033 								tfk->depend_on->obj_catalog, tfk->depend_on->obj_schema,
2034 								tfk->depend_on->obj_name);
2035 					depend_dbo_list = g_slist_prepend (depend_dbo_list, tfk->depend_on);
2036 				}
2037 			}
2038 
2039 			/* dependencies other than foreign keys */
2040 			for (list = dbo->depend_list; list; list = list->next) {
2041 				if (!g_slist_find (depend_dbo_list, list->data)) {
2042 					GdaMetaDbObject *dep_dbo = GDA_META_DB_OBJECT (list->data);
2043 					if (dep_dbo->obj_type != GDA_META_DB_UNKNOWN)
2044 						g_string_append_printf (string, "\"%s\" -> \"%s.%s.%s\";\n",
2045 									fullname,
2046 									dep_dbo->obj_catalog, dep_dbo->obj_schema,
2047 									dep_dbo->obj_name);
2048 				}
2049 			}
2050 
2051 			g_slist_free (depend_dbo_list);
2052 		}
2053 		else if (dbo->obj_type == GDA_META_DB_VIEW) {
2054 			GdaMetaTable *mt = GDA_META_TABLE (dbo);
2055 			if (info & GDA_META_GRAPH_COLUMNS) {
2056 				for (list = mt->columns; list; list = list->next) {
2057 					GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data);
2058 					g_string_append_printf (string, "<TR><TD ALIGN=\"left\">%s</TD></TR>", tcol->column_name);
2059 				}
2060 			}
2061 			if (use_html)
2062 				g_string_append (string, "</TABLE>>];\n");
2063 			/* dependencies */
2064 			for (list = dbo->depend_list; list; list = list->next) {
2065 				GdaMetaDbObject *ddbo = GDA_META_DB_OBJECT (list->data);
2066 				if (ddbo->obj_type != GDA_META_DB_UNKNOWN)
2067 					g_string_append_printf (string, "\"%s\" -> \"%s.%s.%s\";\n", fullname,
2068 								ddbo->obj_catalog, ddbo->obj_schema,
2069 								ddbo->obj_name);
2070 			}
2071 		}
2072 
2073 		g_free (objname);
2074 		g_free (fullname);
2075 	}
2076 	g_string_append_c (string, '}');
2077 
2078 	result = string->str;
2079 	g_string_free (string, FALSE);
2080 	return result;
2081 }
2082 
2083 static void
gda_meta_db_object_free_contents(GdaMetaDbObject * dbo)2084 gda_meta_db_object_free_contents (GdaMetaDbObject *dbo)
2085 {
2086 	g_free (dbo->obj_catalog);
2087 	g_free (dbo->obj_schema);
2088 	g_free (dbo->obj_name);
2089 	g_free (dbo->obj_short_name);
2090 	g_free (dbo->obj_full_name);
2091 	g_free (dbo->obj_owner);
2092 	switch (dbo->obj_type) {
2093 	case GDA_META_DB_UNKNOWN:
2094 		break;
2095 	case GDA_META_DB_TABLE:
2096 		gda_meta_table_free_contents (GDA_META_TABLE (dbo));
2097 		break;
2098 	case GDA_META_DB_VIEW:
2099 		gda_meta_view_free_contents (GDA_META_VIEW (dbo));
2100 		break;
2101 	default:
2102 		TO_IMPLEMENT;
2103 	}
2104 	g_slist_free (dbo->depend_list);
2105 	memset (dbo, 0, sizeof (GdaMetaDbObject));
2106 }
2107 
2108 static void
gda_meta_db_object_free(GdaMetaDbObject * dbo)2109 gda_meta_db_object_free (GdaMetaDbObject *dbo)
2110 {
2111 	gda_meta_db_object_free_contents (dbo);
2112 	g_free (dbo);
2113 }
2114 
2115 static void
gda_meta_table_free_contents(GdaMetaTable * table)2116 gda_meta_table_free_contents (GdaMetaTable *table)
2117 {
2118 	g_slist_foreach (table->columns, (GFunc) gda_meta_table_column_free, NULL);
2119 	g_slist_free (table->columns);
2120 	g_free (table->pk_cols_array);
2121 	g_slist_foreach (table->fk_list, (GFunc) gda_meta_table_foreign_key_free, NULL);
2122 	g_slist_free (table->fk_list);
2123 	g_slist_free (table->reverse_fk_list);
2124 }
2125 
2126 static void
gda_meta_view_free_contents(GdaMetaView * view)2127 gda_meta_view_free_contents (GdaMetaView *view)
2128 {
2129 	gda_meta_table_free_contents ((GdaMetaTable*) view);
2130 	g_free (view->view_def);
2131 }
2132 
2133 static void
gda_meta_table_column_free(GdaMetaTableColumn * tcol)2134 gda_meta_table_column_free (GdaMetaTableColumn *tcol)
2135 {
2136 	g_free (tcol->column_name);
2137 	g_free (tcol->column_type);
2138 	g_free (tcol->default_value);
2139 	gda_attributes_manager_clear (att_mgr, tcol);
2140 	g_free (tcol);
2141 }
2142 
2143 static void
gda_meta_table_foreign_key_free(GdaMetaTableForeignKey * tfk)2144 gda_meta_table_foreign_key_free (GdaMetaTableForeignKey *tfk)
2145 {
2146 	gint i;
2147 	for (i = 0; i < tfk->cols_nb; i++) {
2148 		g_free (tfk->fk_names_array[i]);
2149 		g_free (tfk->ref_pk_names_array[i]);
2150 	}
2151 	g_free (tfk->fk_cols_array);
2152 	g_free (tfk->fk_names_array);
2153 	g_free (tfk->ref_pk_cols_array);
2154 	g_free (tfk->ref_pk_names_array);
2155 	g_free (tfk->fk_name);
2156 	g_free (tfk);
2157 }
2158 
2159 static gboolean
determine_db_object_from_schema_and_name(GdaMetaStruct * mstruct,GdaMetaDbObjectType * in_out_type,GValue ** out_catalog,GValue ** out_short_name,GValue ** out_full_name,GValue ** out_owner,const GValue * schema,const GValue * name)2160 determine_db_object_from_schema_and_name (GdaMetaStruct *mstruct,
2161 					  GdaMetaDbObjectType *in_out_type, GValue **out_catalog,
2162 					  GValue **out_short_name,
2163 					  GValue **out_full_name, GValue **out_owner,
2164 					  const GValue *schema, const GValue *name)
2165 {
2166 	const GValue *cvalue;
2167 	GdaDataModel *model = NULL;
2168 	*out_catalog = NULL;
2169 	*out_short_name = NULL;
2170 	*out_full_name = NULL;
2171 	*out_owner = NULL;
2172 
2173 	switch (*in_out_type) {
2174 	case GDA_META_DB_UNKNOWN: {
2175 		GdaMetaDbObjectType type = GDA_META_DB_TABLE;
2176 		if (determine_db_object_from_schema_and_name (mstruct, &type, out_catalog,
2177 							      out_short_name, out_full_name, out_owner,
2178 							      schema, name)) {
2179 			*in_out_type = GDA_META_DB_TABLE;
2180 			return TRUE;
2181 		}
2182 		type = GDA_META_DB_VIEW;
2183 		if (determine_db_object_from_schema_and_name (mstruct, &type, out_catalog,
2184 							      out_short_name, out_full_name, out_owner,
2185 							      schema, name)) {
2186 			*in_out_type = GDA_META_DB_VIEW;
2187 			return TRUE;
2188 		}
2189 		return FALSE;
2190 		break;
2191 	}
2192 
2193 	case GDA_META_DB_TABLE: {
2194 		const gchar *sql = "SELECT table_catalog, table_short_name, table_full_name, table_owner FROM _tables as t WHERE table_schema = ##ts::string AND table_name = ##tname::string AND table_name NOT IN (SELECT v.table_name FROM _views as v WHERE v.table_catalog=t.table_catalog AND v.table_schema=t.table_schema)";
2195 		gint nrows;
2196 		model = gda_meta_store_extract (mstruct->priv->store, sql, NULL, "ts", schema, "tname", name, NULL);
2197 		if (!model)
2198 			return FALSE;
2199 
2200 		nrows = gda_data_model_get_n_rows (model);
2201 		if (nrows != 1) {
2202 			g_object_unref (model);
2203 			return FALSE;
2204 		}
2205 		cvalue = gda_data_model_get_value_at (model, 0, 0, NULL);
2206 		if (!cvalue) goto copyerror;
2207 		*out_catalog = gda_value_copy (cvalue);
2208 
2209 		cvalue = gda_data_model_get_value_at (model, 1, 0, NULL);
2210 		if (!cvalue) goto copyerror;
2211 		*out_short_name = gda_value_copy (cvalue);
2212 
2213 		cvalue = gda_data_model_get_value_at (model, 2, 0, NULL);
2214 		if (!cvalue) goto copyerror;
2215 		*out_full_name = gda_value_copy (cvalue);
2216 
2217 		cvalue = gda_data_model_get_value_at (model, 3, 0, NULL);
2218 		if (!cvalue) goto copyerror;
2219 		*out_owner = gda_value_copy (cvalue);
2220 
2221 		g_object_unref (model);
2222 		return TRUE;
2223 	}
2224 
2225 	case GDA_META_DB_VIEW:{
2226 		const gchar *sql = "SELECT table_catalog, table_short_name, table_full_name, table_owner FROM _tables NATURAL JOIN _views WHERE table_schema = ##ts::string AND table_name = ##tname::string";
2227 		gint nrows;
2228 		model = gda_meta_store_extract (mstruct->priv->store, sql, NULL, "ts", schema, "tname", name, NULL);
2229 		if (!model)
2230 			return FALSE;
2231 
2232 		nrows = gda_data_model_get_n_rows (model);
2233 		if (nrows != 1) {
2234 			g_object_unref (model);
2235 			return FALSE;
2236 		}
2237 		cvalue = gda_data_model_get_value_at (model, 0, 0, NULL);
2238 		if (!cvalue) goto copyerror;
2239 		*out_catalog = gda_value_copy (cvalue);
2240 
2241 		cvalue = gda_data_model_get_value_at (model, 1, 0, NULL);
2242 		if (!cvalue) goto copyerror;
2243 		*out_short_name = gda_value_copy (cvalue);
2244 
2245 		cvalue = gda_data_model_get_value_at (model, 2, 0, NULL);
2246 		if (!cvalue) goto copyerror;
2247 		*out_full_name = gda_value_copy (cvalue);
2248 
2249 		cvalue = gda_data_model_get_value_at (model, 3, 0, NULL);
2250 		if (!cvalue) goto copyerror;
2251 		*out_owner = gda_value_copy (cvalue);
2252 
2253 		g_object_unref (model);
2254 		return TRUE;
2255 	}
2256 	default:
2257 		TO_IMPLEMENT;
2258 	}
2259 
2260  copyerror:
2261 	if (model)
2262 		g_object_unref (model);
2263 	if (*out_catalog) {
2264 		gda_value_free (*out_catalog);
2265 		*out_catalog = NULL;
2266 	}
2267 	if (*out_short_name) {
2268 		gda_value_free (*out_short_name);
2269 		*out_short_name = NULL;
2270 	}
2271 	if (*out_full_name) {
2272 		gda_value_free (*out_full_name);
2273 		*out_full_name = NULL;
2274 	}
2275 	if (*out_owner) {
2276 		gda_value_free (*out_owner);
2277 		*out_owner = NULL;
2278 	}
2279 
2280 	return FALSE;
2281 }
2282 
2283 static gboolean
determine_db_object_from_short_name(GdaMetaStruct * mstruct,GdaMetaDbObjectType * in_out_type,GValue ** out_catalog,GValue ** out_schema,GValue ** out_name,GValue ** out_short_name,GValue ** out_full_name,GValue ** out_owner,const GValue * name)2284 determine_db_object_from_short_name (GdaMetaStruct *mstruct,
2285 				     GdaMetaDbObjectType *in_out_type, GValue **out_catalog,
2286 				     GValue **out_schema, GValue **out_name, GValue **out_short_name,
2287 				     GValue **out_full_name, GValue **out_owner, const GValue *name)
2288 {
2289 	const GValue *cvalue;
2290 	GdaDataModel *model = NULL;
2291 	*out_name = NULL;
2292 	*out_schema = NULL;
2293 	*out_catalog = NULL;
2294 	*out_short_name = NULL;
2295 	*out_full_name = NULL;
2296 	*out_owner = NULL;
2297 
2298 	/* general lookup */
2299 	switch (*in_out_type) {
2300 	case GDA_META_DB_UNKNOWN: {
2301 		GdaMetaDbObjectType type = GDA_META_DB_TABLE;
2302 		if (determine_db_object_from_short_name (mstruct, &type, out_catalog, out_schema, out_name,
2303 							 out_short_name, out_full_name, out_owner, name)) {
2304 			*in_out_type = GDA_META_DB_TABLE;
2305 			return TRUE;
2306 		}
2307 		type = GDA_META_DB_VIEW;
2308 		if (determine_db_object_from_short_name (mstruct, &type, out_catalog, out_schema, out_name,
2309 							 out_short_name, out_full_name, out_owner, name)) {
2310 			*in_out_type = GDA_META_DB_VIEW;
2311 			return TRUE;
2312 		}
2313 		return FALSE;
2314 		break;
2315 	}
2316 
2317 	case GDA_META_DB_TABLE: {
2318 		const gchar *sql = "SELECT table_catalog, table_schema, table_name, table_short_name, table_full_name, table_owner FROM _tables as t WHERE table_short_name = ##tname::string AND table_name NOT IN (SELECT v.table_name FROM _views as v WHERE v.table_catalog=t.table_catalog AND v.table_schema=t.table_schema)";
2319 		gint nrows;
2320 		model = gda_meta_store_extract (mstruct->priv->store, sql, NULL, "tname", name, NULL);
2321 		if (!model)
2322 			return FALSE;
2323 
2324 		nrows = gda_data_model_get_n_rows (model);
2325 		if (nrows != 1) {
2326 			g_object_unref (model);
2327 			goto next;
2328 		}
2329 
2330 		cvalue = gda_data_model_get_value_at (model, 0, 0, NULL);
2331 		if (!cvalue) goto copyerror;
2332 		*out_catalog = gda_value_copy (cvalue);
2333 
2334 		cvalue = gda_data_model_get_value_at (model, 1, 0, NULL);
2335 		if (!cvalue) goto copyerror;
2336 		*out_schema = gda_value_copy (cvalue);
2337 
2338 		cvalue = gda_data_model_get_value_at (model, 2, 0, NULL);
2339 		if (!cvalue) goto copyerror;
2340 		*out_name = gda_value_copy (cvalue);
2341 
2342 		cvalue = gda_data_model_get_value_at (model, 3, 0, NULL);
2343 		if (!cvalue) goto copyerror;
2344 		*out_short_name = gda_value_copy (cvalue);
2345 
2346 		cvalue = gda_data_model_get_value_at (model, 4, 0, NULL);
2347 		if (!cvalue) goto copyerror;
2348 		*out_full_name = gda_value_copy (cvalue);
2349 
2350 		cvalue = gda_data_model_get_value_at (model, 5, 0, NULL);
2351 		if (!cvalue) goto copyerror;
2352 		*out_owner = gda_value_copy (cvalue);
2353 
2354 		g_object_unref (model);
2355 		return TRUE;
2356 	}
2357 
2358 	case GDA_META_DB_VIEW:{
2359 		const gchar *sql = "SELECT table_catalog, table_schema, table_name, table_short_name, table_full_name, table_owner FROM _tables NATURAL JOIN _views WHERE table_short_name = ##tname::string";
2360 		gint nrows;
2361 		model = gda_meta_store_extract (mstruct->priv->store, sql, NULL, "tname", name, NULL);
2362 		if (!model)
2363 			return FALSE;
2364 
2365 		nrows = gda_data_model_get_n_rows (model);
2366 		if (nrows != 1) {
2367 			g_object_unref (model);
2368 			goto next;
2369 		}
2370 
2371 		cvalue = gda_data_model_get_value_at (model, 0, 0, NULL);
2372 		if (!cvalue) goto copyerror;
2373 		*out_catalog = gda_value_copy (cvalue);
2374 
2375 		cvalue = gda_data_model_get_value_at (model, 1, 0, NULL);
2376 		if (!cvalue) goto copyerror;
2377 		*out_schema = gda_value_copy (cvalue);
2378 
2379 		cvalue = gda_data_model_get_value_at (model, 2, 0, NULL);
2380 		if (!cvalue) goto copyerror;
2381 		*out_name = gda_value_copy (cvalue);
2382 
2383 		cvalue = gda_data_model_get_value_at (model, 3, 0, NULL);
2384 		if (!cvalue) goto copyerror;
2385 		*out_short_name = gda_value_copy (cvalue);
2386 
2387 		cvalue = gda_data_model_get_value_at (model, 4, 0, NULL);
2388 		if (!cvalue) goto copyerror;
2389 		*out_full_name = gda_value_copy (cvalue);
2390 
2391 		cvalue = gda_data_model_get_value_at (model, 5, 0, NULL);
2392 		if (!cvalue) goto copyerror;
2393 		*out_owner = gda_value_copy (cvalue);
2394 
2395 		g_object_unref (model);
2396 		return TRUE;
2397 	}
2398 	default:
2399 		TO_IMPLEMENT;
2400 	}
2401 
2402  next:
2403 	model = NULL;
2404 	{
2405 		/* treat the case where name is in fact <schema>.<name> */
2406 		gchar *obj_schema;
2407 		gchar *obj_name;
2408 		if (_split_identifier_string (g_strdup ((gchar *) g_value_get_string (name)), &obj_schema, &obj_name)) {
2409 			GValue *sv, *nv;
2410 			gboolean retval;
2411 			if (!obj_schema) {
2412 				g_free (obj_name);
2413 				return FALSE;
2414 			}
2415 			if (!obj_name) {
2416 				g_free (obj_schema);
2417 				return FALSE;
2418 			}
2419 			g_value_take_string ((sv = gda_value_new (G_TYPE_STRING)), prepare_sql_identifier_for_compare (obj_schema));
2420 			g_value_take_string ((nv = gda_value_new (G_TYPE_STRING)), prepare_sql_identifier_for_compare (obj_name));
2421 			retval = determine_db_object_from_schema_and_name (mstruct, in_out_type, out_catalog,
2422 									   out_short_name, out_full_name, out_owner,
2423 									   sv, nv);
2424 			if (retval) {
2425 				*out_schema = sv;
2426 				*out_name = nv;
2427 			}
2428 			else {
2429 				gda_value_free (sv);
2430 				gda_value_free (nv);
2431 			}
2432 			return retval;
2433 		}
2434 	}
2435 
2436  copyerror:
2437 	if (model)
2438 		g_object_unref (model);
2439 	if (*out_catalog) {
2440 		gda_value_free (*out_catalog);
2441 		*out_catalog = NULL;
2442 	}
2443 	if (*out_schema) {
2444 		gda_value_free (*out_schema);
2445 		*out_schema = NULL;
2446 	}
2447 	if (*out_name) {
2448 		gda_value_free (*out_name);
2449 		*out_name = NULL;
2450 	}
2451 	if (*out_short_name) {
2452 		gda_value_free (*out_short_name);
2453 		*out_short_name = NULL;
2454 	}
2455 	if (*out_full_name) {
2456 		gda_value_free (*out_full_name);
2457 		*out_full_name = NULL;
2458 	}
2459 	if (*out_owner) {
2460 		gda_value_free (*out_owner);
2461 		*out_owner = NULL;
2462 	}
2463 
2464 	return FALSE;
2465 }
2466 
2467 static gboolean
determine_db_object_from_missing_type(GdaMetaStruct * mstruct,GdaMetaDbObjectType * out_type,GValue ** out_short_name,GValue ** out_full_name,GValue ** out_owner,const GValue * catalog,const GValue * schema,const GValue * name)2468 determine_db_object_from_missing_type (GdaMetaStruct *mstruct,
2469 				       GdaMetaDbObjectType *out_type, GValue **out_short_name,
2470 				       GValue **out_full_name, GValue **out_owner, const GValue *catalog,
2471 				       const GValue *schema, const GValue *name)
2472 {
2473 	/* try as a view first */
2474 	const gchar *sql = "SELECT table_short_name, table_full_name, table_owner FROM _tables NATURAL JOIN _views WHERE table_catalog = ##tc::string AND table_schema = ##ts::string AND table_name = ##tname::string";
2475 	GdaDataModel *model = NULL;
2476 	const GValue *cvalue;
2477 
2478 	*out_type = GDA_META_DB_UNKNOWN;
2479 	*out_short_name = NULL;
2480 	*out_full_name = NULL;
2481 	*out_owner = NULL;
2482 
2483 	model = gda_meta_store_extract (mstruct->priv->store, sql, NULL, "tc", catalog, "ts", schema, "tname", name, NULL);
2484 	if (model && (gda_data_model_get_n_rows (model) == 1)) {
2485 		*out_type = GDA_META_DB_VIEW;
2486 
2487 		cvalue = gda_data_model_get_value_at (model, 0, 0, NULL);
2488 		if (!cvalue) goto copyerror;
2489 		*out_short_name = gda_value_copy (cvalue);
2490 
2491 		cvalue = gda_data_model_get_value_at (model, 1, 0, NULL);
2492 		if (!cvalue) goto copyerror;
2493 		*out_full_name = gda_value_copy (cvalue);
2494 
2495 		cvalue = gda_data_model_get_value_at (model, 2, 0, NULL);
2496 		if (!cvalue) goto copyerror;
2497 		*out_owner = gda_value_copy (cvalue);
2498 
2499 		g_object_unref (model);
2500 		return TRUE;
2501 	}
2502 	if (model)
2503 		g_object_unref (model);
2504 
2505 	/* try as a table */
2506 	sql = "SELECT table_short_name, table_full_name, table_owner FROM _tables WHERE table_catalog = ##tc::string AND table_schema = ##ts::string AND table_name = ##tname::string";
2507 	model = gda_meta_store_extract (mstruct->priv->store, sql, NULL, "tc", catalog, "ts", schema, "tname", name, NULL);
2508 	if (model && (gda_data_model_get_n_rows (model) == 1)) {
2509 		*out_type = GDA_META_DB_TABLE;
2510 
2511 		cvalue = gda_data_model_get_value_at (model, 0, 0, NULL);
2512 		if (!cvalue) goto copyerror;
2513 		*out_short_name = gda_value_copy (cvalue);
2514 
2515 		cvalue = gda_data_model_get_value_at (model, 1, 0, NULL);
2516 		if (!cvalue) goto copyerror;
2517 		*out_full_name = gda_value_copy (cvalue);
2518 
2519 		cvalue = gda_data_model_get_value_at (model, 2, 0, NULL);
2520 		if (!cvalue) goto copyerror;
2521 		*out_owner = gda_value_copy (cvalue);
2522 
2523 		g_object_unref (model);
2524 		return TRUE;
2525 	}
2526 	if (model) {
2527 		g_object_unref (model);
2528 		model = NULL;
2529 	}
2530 
2531 copyerror:
2532 	if (model)
2533 		g_object_unref (model);
2534 
2535 	*out_type = GDA_META_DB_UNKNOWN;
2536 	if (*out_short_name) {
2537 		gda_value_free (*out_short_name);
2538 		*out_short_name = NULL;
2539 	}
2540 	if (*out_full_name) {
2541 		gda_value_free (*out_full_name);
2542 		*out_full_name = NULL;
2543 	}
2544 	if (*out_owner) {
2545 		gda_value_free (*out_owner);
2546 		*out_owner = NULL;
2547 	}
2548 	return FALSE;
2549 }
2550 
2551 /**
2552  * _gda_meta_struct_add_db_object:
2553  * @mstruct: a #GdaMetaStruct object
2554  * @dbo: a #GdaMetaDbObject structure
2555  * @error: (allow-none): a place to store errors, or %NULL
2556  *
2557  * Adds @dbo to the database objects known to @mstruct. In any case (whether an error occured or not)
2558  * @dbo's ownership is then transferred to @smtruct and should
2559  * not be used after calling this function (it may have been destroyed). If you need a pointer to the #GdaMetaDbObject
2560  * for a database object, use gda_meta_struct_get_db_object().
2561  *
2562  * Returns: (transfer none): a pointer to the #GdaMetaDbObject used in @mstruct to represent the added database object (may be @dbo or not)
2563  */
2564 GdaMetaDbObject *
_gda_meta_struct_add_db_object(GdaMetaStruct * mstruct,GdaMetaDbObject * dbo,GError ** error)2565 _gda_meta_struct_add_db_object (GdaMetaStruct *mstruct, GdaMetaDbObject *dbo, GError **error)
2566 {
2567 	GdaMetaDbObject *edbo;
2568 	GValue *v1 = NULL, *v2 = NULL, *v3 = NULL;
2569 	g_return_val_if_fail (GDA_IS_META_STRUCT (mstruct), NULL);
2570 	g_return_val_if_fail (dbo, NULL);
2571 
2572 	if (!dbo->obj_name) {
2573 		g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_INCOHERENCE_ERROR,
2574 			     "%s", _("Missing object name in GdaMetaDbObject structure"));
2575 		gda_meta_db_object_free (dbo);
2576 		return NULL;
2577 	}
2578 	if (dbo->obj_catalog)
2579 		g_value_set_string ((v1 = gda_value_new (G_TYPE_STRING)), dbo->obj_catalog);
2580 	if (dbo->obj_schema)
2581 		g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), dbo->obj_schema);
2582 	g_value_set_string ((v3 = gda_value_new (G_TYPE_STRING)), dbo->obj_name);
2583 
2584 	edbo = gda_meta_struct_get_db_object (mstruct, v1, v2, v3);
2585 	if (v1) gda_value_free (v1);
2586 	if (v2) gda_value_free (v2);
2587 	gda_value_free (v3);
2588 
2589 	if (edbo) {
2590 		if (edbo->obj_type == GDA_META_DB_UNKNOWN) {
2591 			/* overwrite */
2592 			gda_meta_db_object_free_contents (edbo);
2593 			*edbo = *dbo;
2594 			g_free (dbo);
2595 			return edbo;
2596 		}
2597 		else {
2598 			g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_DUPLICATE_OBJECT_ERROR,
2599 				     _("Database object '%s' already exists"), edbo->obj_full_name);
2600 			gda_meta_db_object_free (dbo);
2601 			return NULL;
2602 		}
2603 	}
2604 	else {
2605 		mstruct->priv->db_objects = g_slist_append (mstruct->priv->db_objects, dbo);
2606 		g_hash_table_insert (mstruct->priv->index, g_strdup (dbo->obj_full_name), dbo);
2607 		return dbo;
2608 	}
2609 }
2610 
2611 /**
2612  * gda_meta_table_column_get_attribute:
2613  * @tcol: a #GdaMetaTableColumn
2614  * @attribute: attribute name as a string
2615  *
2616  * Get the value associated to a named attribute.
2617  *
2618  * Attributes can have any name, but Libgda proposes some default names, see <link linkend="libgda-5.0-Attributes-manager.synopsis">this section</link>.
2619  *
2620  * Returns: (transfer none): a read-only #GValue, or %NULL if not attribute named @attribute has been set for @column
2621  */
2622 const GValue *
gda_meta_table_column_get_attribute(GdaMetaTableColumn * tcol,const gchar * attribute)2623 gda_meta_table_column_get_attribute (GdaMetaTableColumn *tcol, const gchar *attribute)
2624 {
2625 	return gda_attributes_manager_get (att_mgr, tcol, attribute);
2626 }
2627 
2628 /**
2629  * gda_meta_table_column_set_attribute:
2630  * @tcol: a #GdaMetaTableColumn
2631  * @attribute: attribute name as a static string
2632  * @value: (allow-none): a #GValue, or %NULL
2633  * @destroy: (allow-none): function called when @attribute has to be freed, or %NULL
2634  *
2635  * Set the value associated to a named attribute.
2636  *
2637  * Attributes can have any name, but Libgda proposes some default names, see <link linkend="libgda-40-Attributes-manager.synopsis">this section</link>.
2638  * If there is already an attribute named @attribute set, then its value is replaced with the new @value,
2639  * except if @value is %NULL, in which case the attribute is removed.
2640  *
2641  * Warning: @attribute is not copied, if it needs to be freed when not used anymore, then @destroy should point to
2642  * the functions which will free it (typically g_free()). If @attribute does not need to be freed, then @destroy can be %NULL.
2643  */
2644 void
gda_meta_table_column_set_attribute(GdaMetaTableColumn * tcol,const gchar * attribute,const GValue * value,GDestroyNotify destroy)2645 gda_meta_table_column_set_attribute (GdaMetaTableColumn *tcol, const gchar *attribute, const GValue *value,
2646 				     GDestroyNotify destroy)
2647 {
2648 	const GValue *cvalue;
2649 	cvalue = gda_attributes_manager_get (att_mgr, tcol, attribute);
2650 	if ((value && cvalue && !gda_value_differ (cvalue, value)) ||
2651 	    (!value && !cvalue))
2652 		return;
2653 
2654 	gda_attributes_manager_set_full (att_mgr, tcol, attribute, value, destroy);
2655 }
2656 
2657 /**
2658  * gda_meta_table_column_foreach_attribute:
2659  * @tcol: a #GdaMetaTableColumn
2660  * @func: (scope call): a #GdaAttributesManagerFunc function
2661  * @data: (closure): user data to be passed as last argument of @func each time it is called
2662  *
2663  * Calls @func for each attribute set to tcol
2664  */
2665 void
gda_meta_table_column_foreach_attribute(GdaMetaTableColumn * tcol,GdaAttributesManagerFunc func,gpointer data)2666 gda_meta_table_column_foreach_attribute (GdaMetaTableColumn *tcol, GdaAttributesManagerFunc func, gpointer data)
2667 {
2668 	gda_attributes_manager_foreach (att_mgr, tcol, func, data);
2669 }
2670