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