1 /*
2  * Copyright (C) 2008 Murray Cumming <murrayc@murrayc.com>
3  * Copyright (C) 2008 - 2011 Vivien Malerba <malerba@gnome-db.org>
4  * Copyright (C) 2010 David King <davidk@openismus.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 
21 #include <string.h>
22 #include <glib/gi18n-lib.h>
23 #include <gda-ddl-creator.h>
24 #include <libgda/gda-connection.h>
25 #include <libgda/gda-server-provider.h>
26 #include <libgda/gda-util.h>
27 #include <libxml/parser.h>
28 #include <libxml/tree.h>
29 #include <libgda/gda-connection.h>
30 #include <libgda/gda-meta-struct.h>
31 #include <libgda/gda-meta-struct-private.h>
32 #include <libgda/gda-config.h>
33 #include <libgda/gda-debug-macros.h>
34 #include <libgda/sql-parser/gda-statement-struct-util.h>
35 
36 /*
37  * Main static functions
38  */
39 static void gda_ddl_creator_class_init (GdaDDLCreatorClass *klass);
40 static void gda_ddl_creator_init (GdaDDLCreator *creator);
41 static void gda_ddl_creator_dispose (GObject *object);
42 static void gda_ddl_creator_finalize (GObject *object);
43 
44 static void gda_ddl_creator_set_property (GObject *object,
45 					 guint param_id,
46 					 const GValue *value,
47 					 GParamSpec *pspec);
48 static void gda_ddl_creator_get_property (GObject *object,
49 					 guint param_id,
50 					 GValue *value,
51 					 GParamSpec *pspec);
52 
53 static gboolean load_customization (GdaDDLCreator *ddlc, const gchar *xml_spec_file, GError **error);
54 static GdaServerOperation *prepare_dbo_server_operation (GdaDDLCreator *ddlc, GdaServerProvider *prov, GdaConnection *cnc,
55 							 GdaMetaDbObject *dbo, GError **error);
56 static GStaticRecMutex init_mutex = G_STATIC_REC_MUTEX_INIT;
57 
58 typedef struct {
59 	gchar  *prov;
60 	gchar  *path;
61 	gchar  *expr;
62 } ProviderSpecificKey;
63 
64 typedef struct {
65 	gchar  *repl;
66 } ProviderSpecificValue;
67 
68 static guint ProviderSpecific_hash (gconstpointer key);
69 static gboolean ProviderSpecific_equal (gconstpointer a, gconstpointer b);
70 static void ProviderSpecific_key_free (ProviderSpecificKey *key);
71 static void ProviderSpecific_value_free (ProviderSpecificValue *value);
72 
73 struct _GdaDDLCreatorPrivate {
74 	GdaConnection *cnc;
75 	GdaMetaStruct *d_mstruct;
76 
77 	GHashTable    *provider_specifics; /* key = a ProviderSpecificKey , value = a ProviderSpecificValue */
78 	GValue *catalog;
79 	GValue *schema;
80 	gchar *quoted_catalog;
81 	gchar *quoted_schema;
82 };
83 
84 /* get a pointer to the parents to be able to call their destructor */
85 static GObjectClass *parent_class = NULL;
86 
87 
88 /* properties */
89 enum {
90 	PROP_0,
91 	PROP_CNC_OBJECT,
92 	PROP_CATALOG,
93 	PROP_SCHEMA
94 };
95 
96 /* module error */
gda_ddl_creator_error_quark(void)97 GQuark gda_ddl_creator_error_quark (void) {
98 	static GQuark quark;
99 	if (!quark)
100 		quark = g_quark_from_static_string ("gda_ddl_creator_error");
101 	return quark;
102 }
103 
104 GType
gda_ddl_creator_get_type(void)105 gda_ddl_creator_get_type (void) {
106 	static GType type = 0;
107 
108 	if (G_UNLIKELY (type == 0)) {
109 		static const GTypeInfo info = {
110 			sizeof (GdaDDLCreatorClass),
111 			(GBaseInitFunc) NULL,
112 			(GBaseFinalizeFunc) NULL,
113 			(GClassInitFunc) gda_ddl_creator_class_init,
114 			NULL,
115 			NULL,
116 			sizeof (GdaDDLCreator),
117 			0,
118 			(GInstanceInitFunc) gda_ddl_creator_init,
119 			0
120 		};
121 
122 		g_static_rec_mutex_lock (&init_mutex);
123 		if (type == 0)
124 			type = g_type_register_static (G_TYPE_OBJECT, "GdaDDLCreator", &info, 0);
125 		g_static_rec_mutex_unlock (&init_mutex);
126 	}
127 	return type;
128 }
129 
130 static guint
ProviderSpecific_hash(gconstpointer key)131 ProviderSpecific_hash (gconstpointer key)
132 {
133 	ProviderSpecificKey *pkey = (ProviderSpecificKey*) key;
134 	return g_str_hash (pkey->path) + g_str_hash (pkey->prov) +
135 		(pkey->expr ? g_str_hash (pkey->expr) : 0);
136 }
137 
138 static gboolean
ProviderSpecific_equal(gconstpointer a,gconstpointer b)139 ProviderSpecific_equal (gconstpointer a, gconstpointer b)
140 {
141 	ProviderSpecificKey *pa, *pb;
142 	pa = (ProviderSpecificKey*) a;
143 	pb = (ProviderSpecificKey*) b;
144 
145 	if (strcmp (pa->prov, pb->prov) ||
146 	    (pa->expr && !pb->expr) ||
147 	    (pb->expr && !pa->expr) ||
148 	    (pa->expr && pb->expr && strcmp (pa->expr, pb->expr)) ||
149 	    strcmp (pa->path, pb->path))
150 		return FALSE;
151 	else
152 		return TRUE;
153 }
154 
155 static void
ProviderSpecific_key_free(ProviderSpecificKey * key)156 ProviderSpecific_key_free (ProviderSpecificKey *key)
157 {
158 	g_free (key->prov);
159 	g_free (key->path);
160 	g_free (key->expr);
161 	g_free (key);
162 }
163 
164 static void
ProviderSpecific_value_free(ProviderSpecificValue * value)165 ProviderSpecific_value_free (ProviderSpecificValue *value)
166 {
167 	g_free (value->repl);
168 	g_free (value);
169 }
170 
171 
172 static void
gda_ddl_creator_class_init(GdaDDLCreatorClass * klass)173 gda_ddl_creator_class_init (GdaDDLCreatorClass *klass)
174 {
175 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
176 
177 	g_static_rec_mutex_lock (&init_mutex);
178 	parent_class = g_type_class_peek_parent (klass);
179 
180 	/* Properties */
181 	object_class->set_property = gda_ddl_creator_set_property;
182 	object_class->get_property = gda_ddl_creator_get_property;
183 	g_object_class_install_property (object_class, PROP_CNC_OBJECT,
184 		g_param_spec_object ("cnc", NULL, _ ("Connection object"), GDA_TYPE_CONNECTION,
185 		(G_PARAM_READABLE | G_PARAM_WRITABLE)));
186 	g_object_class_install_property (object_class, PROP_CATALOG,
187 		g_param_spec_string ("catalog", NULL, _ ("Catalog in which the database objects will be created"), NULL,
188 		(G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
189 	g_object_class_install_property (object_class, PROP_SCHEMA,
190 		g_param_spec_string ("schema", NULL, _ ("Schema in which the database objects will be created"), NULL,
191 		(G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
192 
193 	object_class->dispose = gda_ddl_creator_dispose;
194 	object_class->finalize = gda_ddl_creator_finalize;
195 
196 	g_static_rec_mutex_unlock (&init_mutex);
197 }
198 
199 
200 static void
gda_ddl_creator_init(GdaDDLCreator * creator)201 gda_ddl_creator_init (GdaDDLCreator *creator)
202 {
203 	creator->priv = g_new0 (GdaDDLCreatorPrivate, 1);
204 	creator->priv->cnc = NULL;
205 	creator->priv->d_mstruct = NULL;
206 	creator->priv->provider_specifics = g_hash_table_new_full (ProviderSpecific_hash, ProviderSpecific_equal,
207 								   (GDestroyNotify) ProviderSpecific_key_free,
208 								   (GDestroyNotify) ProviderSpecific_value_free);
209 	creator->priv->catalog = NULL;
210 	creator->priv->schema = NULL;
211 	creator->priv->quoted_catalog = NULL;
212 	creator->priv->quoted_schema = NULL;
213 }
214 
215 static void
gda_ddl_creator_dispose(GObject * object)216 gda_ddl_creator_dispose (GObject *object)
217 {
218 	GdaDDLCreator *creator;
219 
220 	g_return_if_fail (GDA_IS_DDL_CREATOR (object));
221 
222 	creator = GDA_DDL_CREATOR (object);
223 	if (creator->priv) {
224 		if (creator->priv->catalog)
225 			gda_value_free (creator->priv->catalog);
226 		if (creator->priv->schema)
227 			gda_value_free (creator->priv->schema);
228 		g_free (creator->priv->quoted_catalog);
229 		g_free (creator->priv->quoted_schema);
230 
231 		if (creator->priv->cnc) {
232 			g_object_unref (creator->priv->cnc);
233 			creator->priv->cnc = NULL;
234 		}
235 
236 		if (creator->priv->d_mstruct) {
237 			g_object_unref (creator->priv->d_mstruct);
238 			creator->priv->d_mstruct = NULL;
239 		}
240 	}
241 
242 	/* parent class */
243 	parent_class->dispose (object);
244 }
245 
246 static void
gda_ddl_creator_finalize(GObject * object)247 gda_ddl_creator_finalize (GObject *object)
248 {
249 	GdaDDLCreator *creator;
250 
251 	g_return_if_fail (object != NULL);
252 	g_return_if_fail (GDA_IS_DDL_CREATOR (object));
253 
254 	creator = GDA_DDL_CREATOR (object);
255 	if (creator->priv) {
256 		if (creator->priv->provider_specifics)
257 			g_hash_table_destroy (creator->priv->provider_specifics);
258 		g_free (creator->priv);
259 		creator->priv = NULL;
260 	}
261 
262 	/* parent class */
263 	parent_class->finalize (object);
264 }
265 
266 static void
gda_ddl_creator_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)267 gda_ddl_creator_set_property (GObject *object,
268 			      guint param_id,
269 			      const GValue *value,
270 			      GParamSpec *pspec)
271 {
272 	GdaDDLCreator *creator;
273 
274 	creator = GDA_DDL_CREATOR (object);
275 	if (creator->priv) {
276 		switch (param_id) {
277 		case PROP_CNC_OBJECT:
278 			if (creator->priv->cnc)
279 				g_object_unref (creator->priv->cnc);
280 
281 			creator->priv->cnc = g_value_get_object (value);
282 			if (creator->priv->cnc)
283 				g_object_ref (creator->priv->cnc);
284 			break;
285 		case PROP_CATALOG:
286 			if (creator->priv->catalog)
287 				gda_value_free (creator->priv->catalog);
288 			creator->priv->catalog = NULL;
289 			g_free (creator->priv->quoted_catalog);
290 			creator->priv->quoted_catalog = NULL;
291 			if (g_value_get_string (value) && *g_value_get_string (value)) {
292 				creator->priv->catalog = gda_value_copy (value);
293 				if (!creator->priv->cnc)
294 					g_warning ("The \"catalog\" property should be set after the \"cnc\" one");
295 				creator->priv->quoted_catalog =
296 					gda_sql_identifier_quote (g_value_get_string (value), creator->priv->cnc, NULL,
297 								  FALSE, FALSE);
298 			}
299 			break;
300 		case PROP_SCHEMA:
301 			if (creator->priv->schema)
302 				gda_value_free (creator->priv->schema);
303 			creator->priv->schema = NULL;
304 			g_free (creator->priv->quoted_schema);
305 			creator->priv->quoted_schema = NULL;
306 			if (g_value_get_string (value) && *g_value_get_string (value)) {
307 				creator->priv->schema = gda_value_copy (value);
308 				if (!creator->priv->cnc)
309 					g_warning ("The \"schema\" property should be set after the \"cnc\" one");
310 				creator->priv->quoted_schema =
311 					gda_sql_identifier_quote (g_value_get_string (value), creator->priv->cnc, NULL,
312 								  FALSE, FALSE);
313 			}
314 			break;
315 		default:
316 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
317 			break;
318 		}
319 	}
320 }
321 
322 static void
gda_ddl_creator_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)323 gda_ddl_creator_get_property (GObject *object,
324 			     guint param_id,
325 			     GValue *value,
326 			     GParamSpec *pspec)
327 {
328 	GdaDDLCreator *creator;
329 	creator = GDA_DDL_CREATOR (object);
330 
331 	if (creator->priv) {
332 		switch (param_id) {
333 		case PROP_CNC_OBJECT:
334 			g_value_set_object (value, (GObject *) creator->priv->cnc);
335 			break;
336 		case PROP_CATALOG:
337 			if (creator->priv->catalog)
338 				g_value_set_string (value, g_value_get_string (creator->priv->catalog));
339 			else
340 				g_value_set_string (value, NULL);
341 			break;
342 		case PROP_SCHEMA:
343 			if (creator->priv->schema)
344 				g_value_set_string (value, g_value_get_string (creator->priv->schema));
345 			else
346 				g_value_set_string (value, NULL);
347 			break;
348 		default:
349 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
350 			break;
351 		}
352 	}
353 }
354 
355 /**
356  * gda_ddl_creator_new
357  * Create a new #GdaDDLCreator object
358  *
359  * Returns: the newly created object
360  */
361 GdaDDLCreator *
gda_ddl_creator_new(void)362 gda_ddl_creator_new (void)
363 {
364 	return (GdaDDLCreator *) g_object_new (GDA_TYPE_DDL_CREATOR, NULL);
365 }
366 
367 /**
368  * gda_ddl_creator_set_dest_from_file
369  * @ddlc: a #GdaDDLCreator object
370  * @xml_spec_file: a file name
371  * @error: a place to store errors, or %NULL
372  *
373  * Sets the destination structure
374  *
375  * Returns: TRUE if no error occurred
376  */
377 gboolean
gda_ddl_creator_set_dest_from_file(GdaDDLCreator * ddlc,const gchar * xml_spec_file,GError ** error)378 gda_ddl_creator_set_dest_from_file (GdaDDLCreator *ddlc, const gchar *xml_spec_file, GError **error)
379 {
380 	g_return_val_if_fail (GDA_IS_DDL_CREATOR (ddlc), FALSE);
381 	g_return_val_if_fail (xml_spec_file && *xml_spec_file, FALSE);
382 
383 	if (ddlc->priv->d_mstruct)
384 		g_object_unref (ddlc->priv->d_mstruct);
385 
386 	ddlc->priv->d_mstruct = (GdaMetaStruct*) g_object_new (GDA_TYPE_META_STRUCT, NULL);
387 
388 	if (!gda_meta_struct_load_from_xml_file (ddlc->priv->d_mstruct, NULL, NULL, xml_spec_file, error) ||
389 	    !load_customization (ddlc, xml_spec_file, error)) {
390 		g_object_unref (ddlc->priv->d_mstruct);
391 		ddlc->priv->d_mstruct = NULL;
392 		return FALSE;
393 	}
394 	else
395 		return TRUE;
396 }
397 
398 static gboolean
load_customization(GdaDDLCreator * ddlc,const gchar * xml_spec_file,GError ** error)399 load_customization (GdaDDLCreator *ddlc, const gchar *xml_spec_file, GError **error)
400 {
401 	xmlNodePtr node;
402 	xmlDocPtr doc;
403 
404 	/* load information schema's structure XML file */
405 	doc = xmlParseFile (xml_spec_file);
406 	if (!doc) {
407 		g_set_error (error, GDA_DDL_CREATOR_ERROR, GDA_DDL_CREATOR_SPECFILE_NOT_FOUND_ERROR,
408 			     _("Could not load file '%s'"), xml_spec_file);
409 		return FALSE;
410 	}
411 
412 	node = xmlDocGetRootElement (doc);
413 	if (!node || strcmp ((gchar *) node->name, "schema")) {
414 		g_set_error (error, GDA_DDL_CREATOR_ERROR, GDA_DDL_CREATOR_INCORRECT_SCHEMA_ERROR,
415 			     _("Root node of file '%s' should be <schema>."), xml_spec_file);
416 		xmlFreeDoc (doc);
417 		return FALSE;
418 	}
419 
420 	/* walk through the xmlDoc */
421 	for (node = node->children; node; node = node->next) {
422 		/* <specifics> tag to allow for provider specific transformations */
423 		if (!strcmp ((gchar *) node->name, "specifics")) {
424 			xmlNodePtr snode;
425 			for (snode = node->children; snode; snode = snode->next) {
426 				if (strcmp ((gchar *) snode->name, "provider"))
427 					continue;
428 				xmlChar *pname;
429 				pname = xmlGetProp (snode, BAD_CAST "name");
430 				if (!pname) {
431 					g_warning ("<provider> section ignored because no provider name specified");
432 					continue; /* ignore this section */
433 				}
434 
435 				xmlNodePtr rnode;
436 				for (rnode = snode->children; rnode; rnode = rnode->next) {
437 					if (!strcmp ((gchar *) rnode->name, "replace") ||
438 					    !strcmp ((gchar *) rnode->name, "ignore")) {
439 						xmlChar *context, *tmp;
440 						context = xmlGetProp (rnode, BAD_CAST "context");
441 						if (!context) {
442 							g_warning ("<%s> section ignored because no context specified",
443 								   snode->name);
444 							continue;
445 						}
446 						ProviderSpecificKey *key = g_new0 (ProviderSpecificKey, 1);
447 						ProviderSpecificValue *val = g_new0 (ProviderSpecificValue, 1);
448 						key->prov = g_strdup ((gchar *) pname);
449 						key->path = g_strdup ((gchar *) context);
450 						xmlFree (context);
451 						tmp = xmlGetProp (rnode, BAD_CAST "expr");
452 						if (tmp) {
453 							key->expr = g_strdup ((gchar *) tmp);
454 							xmlFree (tmp);
455 						}
456 						tmp = xmlGetProp (rnode, BAD_CAST "replace_with");
457 						if (tmp) {
458 							val->repl = g_strdup ((gchar *) tmp);
459 							xmlFree (tmp);
460 						}
461 						g_hash_table_insert (ddlc->priv->provider_specifics, key, val);
462 						/*g_print ("RULE: %s, %s, %s => %s\n", key->prov,
463 						  key->path, key->expr, val->repl);*/
464 					}
465 				}
466 				xmlFree (pname);
467 			}
468 		}
469 	}
470 	xmlFreeDoc (doc);
471 
472 	return TRUE;
473 }
474 
475 static GdaServerOperation *create_server_operation_for_table (GdaDDLCreator *ddlc, GdaServerProvider *prov, GdaConnection *cnc,
476 							      GdaMetaDbObject *dbobj, GError **error);
477 static GdaServerOperation *create_server_operation_for_view (GdaDDLCreator *ddlc, GdaServerProvider *prov, GdaConnection *cnc,
478 							     GdaMetaDbObject *dbobj, GError **error);
479 
480 static GdaServerOperation *
prepare_dbo_server_operation(GdaDDLCreator * ddlc,GdaServerProvider * prov,GdaConnection * cnc,GdaMetaDbObject * dbo,GError ** error)481 prepare_dbo_server_operation (GdaDDLCreator *ddlc, GdaServerProvider *prov, GdaConnection *cnc, GdaMetaDbObject *dbo, GError **error)
482 {
483 	GdaServerOperation *op = NULL;
484 	switch (dbo->obj_type) {
485 	case GDA_META_DB_UNKNOWN:
486 		g_set_error (error, GDA_DDL_CREATOR_ERROR, GDA_DDL_CREATOR_INCORRECT_SCHEMA_ERROR,
487 			     _("Unknown database object '%s'"), dbo->obj_full_name);
488 		break;
489 
490 	case GDA_META_DB_TABLE:
491 		op = create_server_operation_for_table (ddlc, prov, cnc, dbo, error);
492 		break;
493 
494 	case GDA_META_DB_VIEW:
495 		op = create_server_operation_for_view (ddlc, prov, cnc, dbo, error);
496 		break;
497 	default:
498 		TO_IMPLEMENT;
499 		break;
500 	}
501 
502 	return op;
503 }
504 
505 static const gchar *
provider_specific_match(GHashTable * specific_hash,GdaServerProvider * prov,const gchar * expr,const gchar * path)506 provider_specific_match (GHashTable *specific_hash, GdaServerProvider *prov, const gchar *expr, const gchar *path)
507 {
508 	ProviderSpecificKey spec;
509 	ProviderSpecificValue *val;
510 
511 	spec.prov = (gchar *) gda_server_provider_get_name (prov);
512 	spec.path = (gchar *) path;
513 	spec.expr = (gchar *) expr;
514 	val = g_hash_table_lookup (specific_hash, &spec);
515 	/*g_print ("RULESEARCH %s, %s, %s => %s\n", spec.prov, spec.path, spec.expr, val ? val->repl : "-no rule found-");*/
516 	if (val)
517 		return val->repl;
518 	else
519 		return expr;
520 }
521 
522 typedef struct {
523 	GdaServerOperation *op;
524 	gint index;
525 	GError **error;
526 	gboolean allok;
527 } FData;
528 static void
meta_table_column_foreach_attribute_func(const gchar * att_name,const GValue * value,FData * fdata)529 meta_table_column_foreach_attribute_func (const gchar *att_name, const GValue *value, FData *fdata)
530 {
531 	if (!fdata->allok)
532 		return;
533 	if (!strcmp (att_name, GDA_ATTRIBUTE_AUTO_INCREMENT) &&
534 	    (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN) &&
535 	    g_value_get_boolean (value)) {
536 		fdata->allok = gda_server_operation_set_value_at (fdata->op, "TRUE", fdata->error,
537 								  "/FIELDS_A/@COLUMN_AUTOINC/%d",
538 								  fdata->index);
539 	}
540 }
541 
542 static GdaServerOperation *
create_server_operation_for_table(GdaDDLCreator * ddlc,GdaServerProvider * prov,GdaConnection * cnc,GdaMetaDbObject * dbobj,GError ** error)543 create_server_operation_for_table (GdaDDLCreator *ddlc, GdaServerProvider *prov, GdaConnection *cnc,
544 				   GdaMetaDbObject *dbobj, GError **error)
545 {
546 	GdaServerOperation *op;
547 	GSList *list;
548 	gint index;
549 	const gchar *repl;
550 
551 	op = gda_server_provider_create_operation (prov, cnc, GDA_SERVER_OPERATION_CREATE_TABLE, NULL, error);
552 	if (!op)
553 		return NULL;
554 	if (! gda_server_operation_set_value_at (op, dbobj->obj_name, error, "/TABLE_DEF_P/TABLE_NAME"))
555 		goto onerror;
556 
557 	/* columns */
558 	for (index = 0, list = GDA_META_TABLE (dbobj)->columns; list; list = list->next, index++) {
559 		GdaMetaTableColumn *tcol = GDA_META_TABLE_COLUMN (list->data);
560 		if (! gda_server_operation_set_value_at (op, tcol->column_name, error,
561 							 "/FIELDS_A/@COLUMN_NAME/%d", index))
562 			goto onerror;
563 		repl = provider_specific_match (ddlc->priv->provider_specifics, prov, tcol->column_type ? tcol->column_type : "string",
564 						"/FIELDS_A/@COLUMN_TYPE");
565 		if (! gda_server_operation_set_value_at (op, repl ? repl : "string", error,
566 							 "/FIELDS_A/@COLUMN_TYPE/%d", index))
567 			goto onerror;
568 		if (! gda_server_operation_set_value_at (op, NULL, error,
569 							 "/FIELDS_A/@COLUMN_SIZE/%d", index))
570 			goto onerror;
571 		if (! gda_server_operation_set_value_at (op, tcol->nullok ? "FALSE" : "TRUE", error,
572 							 "/FIELDS_A/@COLUMN_NNUL/%d", index))
573 			goto onerror;
574 		if (! gda_server_operation_set_value_at (op, "FALSE", error,
575 							 "/FIELDS_A/@COLUMN_AUTOINC/%d", index))
576 			goto onerror;
577 		if (! gda_server_operation_set_value_at (op, "FALSE", error,
578 							 "/FIELDS_A/@COLUMN_UNIQUE/%d", index))
579 			goto onerror;
580 		FData fdata;
581 		fdata.op = op;
582 		fdata.index = index;
583 		fdata.error = error;
584 		fdata.allok = TRUE;
585 		gda_meta_table_column_foreach_attribute (tcol, (GdaAttributesManagerFunc) meta_table_column_foreach_attribute_func,
586 							 &fdata);
587 		if (!fdata.allok)
588 			goto onerror;
589 
590 		repl = provider_specific_match (ddlc->priv->provider_specifics, prov, "dummy", "/FIELDS_A/@COLUMN_PKEY");
591 		if (repl) {
592 			if (! gda_server_operation_set_value_at (op, tcol->pkey ? "TRUE" : "FALSE", error,
593 								 "/FIELDS_A/@COLUMN_PKEY/%d", index))
594 				goto onerror;
595 		}
596 		else {
597 			if (! gda_server_operation_set_value_at (op, "FALSE", error, "/FIELDS_A/@COLUMN_PKEY/%d", index))
598 				goto onerror;
599 		}
600 	}
601 
602 	/* foreign keys */
603 	gint fkindex;
604 	for (fkindex = 0, list = GDA_META_TABLE (dbobj)->fk_list; list; fkindex++, list = list->next) {
605 		GdaMetaTableForeignKey *mfkey = GDA_META_TABLE_FOREIGN_KEY (list->data);
606 		gint col;
607 		if (! gda_server_operation_set_value_at (op, mfkey->depend_on->obj_full_name, error, "/FKEY_S/%d/FKEY_REF_TABLE",
608 							 fkindex))
609 			goto onerror;
610 		for (col = 0; col < mfkey->cols_nb; col++) {
611 			if (! gda_server_operation_set_value_at (op, mfkey->fk_names_array[col], error,
612 								 "/FKEY_S/%d/FKEY_FIELDS_A/@FK_FIELD/%d",
613 								 fkindex, col))
614 				goto onerror;
615 			if (! gda_server_operation_set_value_at (op, mfkey->ref_pk_names_array[col], error,
616 								 "/FKEY_S/%d/FKEY_FIELDS_A/@FK_REF_PK_FIELD/%d",
617 								 fkindex, col))
618 				goto onerror;
619 		}
620 	}
621 
622 #ifdef GDA_DEBUG_NO
623 	{
624 		xmlNodePtr node;
625 		xmlBufferPtr buffer;
626 		node = gda_server_operation_save_data_to_xml (op, NULL);
627 		buffer = xmlBufferCreate ();
628 		xmlNodeDump (buffer, NULL, node, 5, 1);
629 		xmlFreeNode (node);
630 		xmlBufferDump (stdout, buffer);
631 		xmlBufferFree (buffer);
632 	}
633 #endif
634 
635 	return op;
636  onerror:
637 	g_object_unref (op);
638 	return NULL;
639 }
640 
641 static GdaServerOperation *
create_server_operation_for_view(G_GNUC_UNUSED GdaDDLCreator * ddlc,GdaServerProvider * prov,GdaConnection * cnc,GdaMetaDbObject * dbobj,GError ** error)642 create_server_operation_for_view (G_GNUC_UNUSED GdaDDLCreator *ddlc, GdaServerProvider *prov, GdaConnection *cnc,
643 				  GdaMetaDbObject *dbobj, GError **error)
644 {
645 	GdaServerOperation *op;
646 
647 	op = gda_server_provider_create_operation (prov, cnc, dbobj->obj_type, NULL, error);
648 	if (!op)
649 		return NULL;
650 	if (! gda_server_operation_set_value_at (op, dbobj->obj_name, error, "/VIEW_DEF_P/VIEW_NAME"))
651 		goto onerror;
652 	if (! gda_server_operation_set_value_at (op, GDA_META_VIEW (dbobj)->view_def, error, "/VIEW_DEF_P/VIEW_DEF"))
653 		goto onerror;
654 
655 	return op;
656  onerror:
657 	g_object_unref (op);
658 	return NULL;
659 }
660 
661 /**
662  * gda_ddl_creator_set_connection
663  * @ddlc: a #GdaDDLCreator object
664  * @cnc: (allow-none): a #GdaConnection object or %NULL
665  *
666  *
667  */
668 void
gda_ddl_creator_set_connection(GdaDDLCreator * ddlc,GdaConnection * cnc)669 gda_ddl_creator_set_connection (GdaDDLCreator *ddlc, GdaConnection *cnc)
670 {
671 	g_return_if_fail (GDA_IS_DDL_CREATOR (ddlc));
672 	g_return_if_fail (!cnc || GDA_IS_CONNECTION (cnc));
673 
674 	g_object_set (G_OBJECT (ddlc), "cnc", cnc, NULL);
675 }
676 
677 /**
678  * gda_ddl_creator_get_sql
679  * @ddlc: a #GdaDDLCreator object
680  * @error: a place to store errors, or %NULL
681  *
682  * Get the SQL code which would be executed to create the database objects
683  *
684  * Returns: a new string if no error occurred, or %NULL
685  */
686 gchar *
gda_ddl_creator_get_sql(GdaDDLCreator * ddlc,GError ** error)687 gda_ddl_creator_get_sql (GdaDDLCreator *ddlc, GError **error)
688 {
689 	GString *string;
690 	gchar *sql;
691 	g_return_val_if_fail (GDA_IS_DDL_CREATOR (ddlc), NULL);
692 	g_return_val_if_fail (ddlc->priv, NULL);
693 	if (!ddlc->priv->cnc) {
694 		g_set_error (error, GDA_DDL_CREATOR_ERROR, GDA_DDL_CREATOR_NO_CONNECTION_ERROR,
695 			     "%s", _("No connection specified"));
696 		return NULL;
697 	}
698 
699 	/* render operations to SQL */
700 	GdaServerProvider *prov = gda_connection_get_provider (ddlc->priv->cnc);
701 	GSList *objlist, *list;
702 	objlist = gda_meta_struct_get_all_db_objects (ddlc->priv->d_mstruct);
703 
704 	string = g_string_new ("");
705 	for (list = objlist; list; list = list->next) {
706 		GdaServerOperation *op;
707 		op = prepare_dbo_server_operation (ddlc, prov, NULL, GDA_META_DB_OBJECT (list->data), error);
708 		if (!op) {
709 			g_string_free (string, TRUE);
710 			return NULL;
711 		}
712 		else {
713 			sql = gda_server_provider_render_operation (prov, ddlc->priv->cnc, op, error);
714 			if (!sql) {
715 				g_string_free (string, TRUE);
716 				return NULL;
717 			}
718 			else {
719 				g_string_append_printf (string, "--\n-- Database object: %s\n--\n",
720 							GDA_META_DB_OBJECT (list->data)->obj_full_name);
721 				g_string_append (string, sql);
722 				g_string_append (string, ";\n\n");
723 				g_free (sql);
724 			}
725 		}
726 		g_object_unref (op);
727 	}
728 
729 	sql = string->str;
730 	g_string_free (string, FALSE);
731 	return sql;
732 }
733 
734 /**
735  * gda_ddl_creator_execute
736  * @ddlc: a #GdaDDLCreator object
737  * @error: a place to store errors, or %NULL
738  *
739  *
740  */
741 gboolean
gda_ddl_creator_execute(GdaDDLCreator * ddlc,GError ** error)742 gda_ddl_creator_execute (GdaDDLCreator *ddlc, GError **error)
743 {
744 	g_return_val_if_fail (GDA_IS_DDL_CREATOR (ddlc), FALSE);
745 	g_return_val_if_fail (ddlc->priv, FALSE);
746 	if (!ddlc->priv->cnc) {
747 		g_set_error (error, GDA_DDL_CREATOR_ERROR, GDA_DDL_CREATOR_NO_CONNECTION_ERROR,
748 			     "%s", _("No connection specified"));
749 		return FALSE;
750 	}
751 	if (!ddlc->priv->d_mstruct) {
752 		g_set_error (error, GDA_DDL_CREATOR_ERROR, GDA_DDL_CREATOR_NO_CONNECTION_ERROR,
753 			     "%s", _("No destination database objects specified"));
754 		return FALSE;
755 	}
756 
757 	/* begin transaction */
758 	if (!gda_connection_begin_transaction (ddlc->priv->cnc, NULL, GDA_TRANSACTION_ISOLATION_UNKNOWN,
759 					       error))
760 		return FALSE;
761 
762 	/* execute operations */
763 	GdaServerProvider *prov = gda_connection_get_provider (ddlc->priv->cnc);
764 	GSList *objlist, *list;
765 	objlist = gda_meta_struct_get_all_db_objects (ddlc->priv->d_mstruct);
766 	for (list = objlist; list; list = list->next) {
767 		GdaServerOperation *op;
768 		op = prepare_dbo_server_operation (ddlc, prov, NULL, GDA_META_DB_OBJECT (list->data), error);
769 		if (!op)
770 			goto onerror;
771 		else {
772 			if (!gda_server_provider_perform_operation (prov, ddlc->priv->cnc, op, error)) {
773 				g_object_unref (op);
774 				goto onerror;
775 			}
776 		}
777 		g_object_unref (op);
778 	}
779 
780 	if (!gda_connection_commit_transaction (ddlc->priv->cnc, NULL, error))
781 		goto onerror;
782 
783 	return TRUE;
784 
785  onerror:
786 	gda_connection_rollback_transaction (ddlc->priv->cnc, NULL, NULL);
787 	return FALSE;
788 }
789 
790