1 /*
2 * Copyright (C) 2006 - 2008 Murray Cumming <murrayc@murrayc.com>
3 * Copyright (C) 2006 - 2011 Vivien Malerba <malerba@gnome-db.org>
4 * Copyright (C) 2007 Leonardo Boshell <lb@kmc.com.co>
5 * Copyright (C) 2008 Armin Burgmeier <armin@openismus.com>
6 * Copyright (C) 2008 Phil Longstaff <plongstaff@rogers.com>
7 * Copyright (C) 2008 Przemysław Grzegorczyk <pgrzegorczyk@gmail.com>
8 * Copyright (C) 2009 Bas Driessen <bas.driessen@xobas.com>
9 * Copyright (C) 2010 David King <davidk@openismus.com>
10 * Copyright (C) 2010 Jonh Wendell <jwendell@gnome.org>
11 * Copyright (C) 2011 - 2012 Daniel Espinosa <despinosa@src.gnome.org>
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the
25 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
26 * Boston, MA 02110-1301, USA.
27 */
28
29 #include <stdlib.h>
30 #include <glib.h>
31 #include <libgda/gda-marshal.h>
32 #include <libgda/gda-server-provider.h>
33 #include <libgda/gda-server-operation.h>
34 #include <libgda/gda-set.h>
35 #include <libgda/gda-holder.h>
36 #include <libgda/gda-connection.h>
37 #include <libgda/gda-config.h>
38 #include <libgda/gda-data-model-private.h>
39 #include <libgda/gda-data-model-import.h>
40 #include <libgda/gda-data-model-array.h>
41 #include "gda-util.h"
42 #include <string.h>
43 #ifdef HAVE_LOCALE_H
44 #include <locale.h>
45 #endif
46 #include <glib/gi18n-lib.h>
47
48 extern gchar *gda_lang_locale;
49
50 #define CLASS(operation) (GDA_SERVER_OPERATION_CLASS (G_OBJECT_GET_CLASS (operation)))
51
52 static void gda_server_operation_class_init (GdaServerOperationClass *klass);
53 static void gda_server_operation_init (GdaServerOperation *operation,
54 GdaServerOperationClass *klass);
55 static void gda_server_operation_dispose (GObject *object);
56
57 static void gda_server_operation_set_property (GObject *object,
58 guint param_id,
59 const GValue *value,
60 GParamSpec *pspec);
61 static void gda_server_operation_get_property (GObject *object,
62 guint param_id,
63 GValue *value,
64 GParamSpec *pspec);
65
66 /* signals */
67 enum
68 {
69 SEQUENCE_ITEM_ADDED,
70 SEQUENCE_ITEM_REMOVE,
71 LAST_SIGNAL
72 };
73
74 static gint gda_server_operation_signals[LAST_SIGNAL] = { 0, 0 };
75
76 /* properties */
77 enum
78 {
79 PROP_0,
80 PROP_CNC,
81 PROP_PROV,
82 PROP_OP_TYPE,
83 PROP_SPEC_FILE
84 };
85
86 extern xmlDtdPtr _gda_server_op_dtd;
87 static GObjectClass *parent_class = NULL;
88
89 typedef struct _Node {
90 struct _Node *parent;
91 GdaServerOperationNodeType type;
92 GdaServerOperationNodeStatus status;
93 gchar *path_name; /* NULL for GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM nodes */
94 union {
95 GdaSet *plist;
96 GdaDataModel *model;
97 GdaHolder *param;
98 struct {
99 GSList *seq_tmpl; /* list of Node templates */
100 guint min_items;
101 guint max_items;
102 GSList *seq_items; /* list of Node of type GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM */
103 gchar *name;
104 gchar *descr;
105 xmlNodePtr xml_spec; /* references a op->priv->xml_spec_doc node,
106 for future instantiation of nodes */
107 } seq;
108 GSList *seq_item_nodes; /* list of Node structures composing the item */
109 } d;
110 } Node;
111 #define NODE(x) ((Node*)(x))
112
113 static void node_destroy (GdaServerOperation *op, Node *node);
114 static Node *node_new (Node *parent, GdaServerOperationNodeType type, const gchar *path);
115 static void sequence_add_item (GdaServerOperation *op, Node *node);
116 static Node *node_find (GdaServerOperation *op, const gchar *path);
117 static Node *node_find_or_create (GdaServerOperation *op, const gchar *path);
118 static gchar *node_get_complete_path (GdaServerOperation *op, Node *node);
119 static void clean_nodes_info_cache (GdaServerOperation *operation);
120 struct _GdaServerOperationPrivate {
121 GdaServerOperationType op_type;
122 gboolean cnc_set;
123 GdaConnection *cnc;
124 gboolean prov_set;
125 GdaServerProvider *prov;
126
127 xmlDocPtr xml_spec_doc;
128 GSList *sources; /* list of GdaDataModel as sources for the parameters */
129
130 GSList *allnodes; /* list of all the Node structures, referenced here only */
131 GSList *topnodes; /* list of the "/(*)" named nodes, not referenced here */
132 GHashTable *info_hash; /* key = path, value = a GdaServerOperationNode */
133 };
134
135
136
137 /*
138 * GdaServerOperation class implementation
139 */
140 static void
gda_server_operation_class_init(GdaServerOperationClass * klass)141 gda_server_operation_class_init (GdaServerOperationClass *klass)
142 {
143 GObjectClass *object_class = G_OBJECT_CLASS (klass);
144
145 parent_class = g_type_class_peek_parent (klass);
146
147 /* signals */
148 /**
149 * GdaServerOperation::sequence-item-added:
150 * @op: the #GdaServerOperation
151 * @seq_path: the path to the new sequence item
152 * @item_index: the index (starting from 0) of the new sequence item in the sequence
153 *
154 * Gets emitted whenever a new sequence item (from a sequence template) has been added
155 */
156 gda_server_operation_signals[SEQUENCE_ITEM_ADDED] =
157 g_signal_new ("sequence-item-added",
158 G_TYPE_FROM_CLASS (object_class),
159 G_SIGNAL_RUN_FIRST,
160 G_STRUCT_OFFSET (GdaServerOperationClass, seq_item_added),
161 NULL, NULL,
162 _gda_marshal_VOID__STRING_INT, G_TYPE_NONE,
163 2, G_TYPE_STRING, G_TYPE_INT);
164 /**
165 * GdaServerOperation::sequence-item-remove:
166 * @op: the #GdaServerOperation
167 * @seq_path: the path to the sequence item to be removed
168 * @item_index: the index (starting from 0) of the sequence item in the sequence
169 *
170 * Gets emitted whenever a sequence item is about to be removed
171 */
172 gda_server_operation_signals[SEQUENCE_ITEM_REMOVE] =
173 g_signal_new ("sequence-item-remove",
174 G_TYPE_FROM_CLASS (object_class),
175 G_SIGNAL_RUN_FIRST,
176 G_STRUCT_OFFSET (GdaServerOperationClass, seq_item_remove),
177 NULL, NULL,
178 _gda_marshal_VOID__STRING_INT, G_TYPE_NONE,
179 2, G_TYPE_STRING, G_TYPE_INT);
180
181 klass->seq_item_added = NULL;
182 klass->seq_item_remove = NULL;
183
184 object_class->dispose = gda_server_operation_dispose;
185
186 /* Properties */
187 object_class->set_property = gda_server_operation_set_property;
188 object_class->get_property = gda_server_operation_get_property;
189
190 g_object_class_install_property (object_class, PROP_CNC,
191 g_param_spec_object ("connection", NULL, "Connection to use",
192 GDA_TYPE_CONNECTION,
193 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
194 g_object_class_install_property (object_class, PROP_PROV,
195 g_param_spec_object ("provider", NULL,
196 "Database provider which created the object",
197 GDA_TYPE_SERVER_PROVIDER,
198 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
199 g_object_class_install_property (object_class, PROP_SPEC_FILE,
200 g_param_spec_string ("spec-filename", NULL,
201 "XML file which contains the object's data structure",
202 NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
203 g_object_class_install_property (object_class, PROP_OP_TYPE,
204 g_param_spec_int ("op-type", NULL, "Type of operation to be done",
205 0, GDA_SERVER_OPERATION_LAST - 1,
206 0, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
207 }
208
209 static void
gda_server_operation_init(GdaServerOperation * operation,G_GNUC_UNUSED GdaServerOperationClass * klass)210 gda_server_operation_init (GdaServerOperation *operation,
211 G_GNUC_UNUSED GdaServerOperationClass *klass)
212 {
213 g_return_if_fail (GDA_IS_SERVER_OPERATION (operation));
214
215 operation->priv = g_new0 (GdaServerOperationPrivate, 1);
216 operation->priv->allnodes = NULL;
217 operation->priv->info_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
218 }
219
220 static void
clean_nodes_info_cache(GdaServerOperation * operation)221 clean_nodes_info_cache (GdaServerOperation *operation)
222 {
223 if (operation->priv->info_hash)
224 g_hash_table_destroy (operation->priv->info_hash);
225
226 operation->priv->info_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
227 }
228
229
230 static void
gda_server_operation_dispose(GObject * object)231 gda_server_operation_dispose (GObject *object)
232 {
233 GdaServerOperation *operation = (GdaServerOperation *) object;
234
235 g_return_if_fail (GDA_IS_SERVER_OPERATION (operation));
236
237 /* free memory */
238 if (operation->priv) {
239 if (operation->priv->info_hash)
240 g_hash_table_destroy (operation->priv->info_hash);
241
242 if (operation->priv->cnc)
243 g_object_unref (operation->priv->cnc);
244 if (operation->priv->prov)
245 g_object_unref (operation->priv->prov);
246
247 while (operation->priv->topnodes)
248 node_destroy (operation, NODE (operation->priv->topnodes->data));
249 g_assert (!operation->priv->allnodes);
250
251 /* don't free operation->priv->xml_spec_doc */
252
253 if (operation->priv->sources) {
254 g_slist_foreach (operation->priv->sources, (GFunc) g_object_unref, NULL);
255 g_slist_free (operation->priv->sources);
256 }
257
258 g_free (operation->priv);
259 operation->priv = NULL;
260 }
261
262 /* chain to parent class */
263 parent_class->dispose (object);
264 }
265
266 /* module error */
267 GQuark
gda_server_operation_error_quark(void)268 gda_server_operation_error_quark (void)
269 {
270 static GQuark quark;
271 if (!quark)
272 quark = g_quark_from_static_string ("gda_server_operation_error");
273 return quark;
274 }
275
276 GType
gda_server_operation_get_type(void)277 gda_server_operation_get_type (void)
278 {
279 static GType type = 0;
280
281 if (G_UNLIKELY (type == 0)) {
282 static GMutex registering;
283
284 static const GTypeInfo info = {
285 sizeof (GdaServerOperationClass),
286 (GBaseInitFunc) NULL,
287 (GBaseFinalizeFunc) NULL,
288 (GClassInitFunc) gda_server_operation_class_init,
289 NULL,
290 NULL,
291 sizeof (GdaServerOperation),
292 0,
293 (GInstanceInitFunc) gda_server_operation_init,
294 0
295 };
296
297 g_mutex_lock (®istering);
298 if (!type)
299 type = g_type_register_static (G_TYPE_OBJECT, "GdaServerOperation", &info, 0);
300 g_mutex_unlock (®istering);
301 }
302 return type;
303 }
304
305 /* create a new Node structure */
306 static Node *
node_new(Node * parent,GdaServerOperationNodeType type,const gchar * path)307 node_new (Node *parent, GdaServerOperationNodeType type, const gchar *path)
308 {
309 Node *node;
310
311 node = g_new0 (Node, 1);
312 node->parent = parent;
313 node->type = type;
314 node->status = GDA_SERVER_OPERATION_STATUS_REQUIRED;
315 node->path_name = g_strdup (path);
316
317 return node;
318 }
319
320 /* destroy a Node structure */
321 static void
node_destroy(GdaServerOperation * op,Node * node)322 node_destroy (GdaServerOperation *op, Node *node)
323 {
324 switch (node->type) {
325 case GDA_SERVER_OPERATION_NODE_PARAMLIST:
326 g_object_unref (G_OBJECT (node->d.plist));
327 break;
328 case GDA_SERVER_OPERATION_NODE_DATA_MODEL:
329 g_object_unref (G_OBJECT (node->d.model));
330 break;
331 case GDA_SERVER_OPERATION_NODE_PARAM:
332 g_object_unref (G_OBJECT (node->d.param));
333 break;
334 case GDA_SERVER_OPERATION_NODE_SEQUENCE: {
335 GSList *list;
336
337 for (list = node->d.seq.seq_tmpl; list; list = list->next)
338 node_destroy (op, NODE (list->data));
339 g_slist_free (node->d.seq.seq_tmpl);
340
341 for (list = node->d.seq.seq_items; list; list = list->next)
342 node_destroy (op, NODE (list->data));
343 g_slist_free (node->d.seq.seq_items);
344
345 g_free (node->d.seq.name);
346 g_free (node->d.seq.descr);
347 break;
348 }
349 case GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM: {
350 GSList *list;
351
352 for (list = node->d.seq_item_nodes; list; list = list->next)
353 node_destroy (op, NODE (list->data));
354 g_slist_free (node->d.seq_item_nodes);
355 break;
356 }
357 default:
358 g_assert_not_reached ();
359 break;
360 }
361
362 g_free (node->path_name);
363 if (op) {
364 op->priv->topnodes = g_slist_remove (op->priv->topnodes, node);
365 op->priv->allnodes = g_slist_remove (op->priv->allnodes, node);
366 }
367
368 g_free (node);
369 }
370
371 /*
372 * Find a Node from its full path
373 */
374 static Node *
node_find(GdaServerOperation * op,const gchar * path)375 node_find (GdaServerOperation *op, const gchar *path)
376 {
377 Node *node = NULL;
378 GSList *list;
379
380 if (!path || !*path || (*path != '/'))
381 return NULL;
382
383 for (list = op->priv->allnodes; list; list = list->next) {
384 gchar *str;
385 str = node_get_complete_path (op, NODE (list->data));
386 if (!strcmp (str, path)) {
387 node = NODE (list->data);
388 g_free (str);
389 break;
390 }
391 g_free (str);
392 }
393 /*g_print ("%s(%s) => %p\n", __FUNCTION__, path, node);*/
394 return node;
395 }
396
397 /*
398 * Find a node from its full path and if it does not exist, tries to
399 * create it (for sequences' items)
400 */
401 static Node *
node_find_or_create(GdaServerOperation * op,const gchar * path)402 node_find_or_create (GdaServerOperation *op, const gchar *path)
403 {
404 Node *node;
405
406 if (!path || !*path || (*path != '/'))
407 return NULL;
408
409 node = node_find (op, path);
410 if (!node) {
411 gchar *cpath = g_strdup (path);
412 gchar *ptr;
413 gchar *root, *ext;
414
415 /* separate @path to <root>/<ext> */
416 ptr = cpath + strlen (cpath) - 1;
417 while (*ptr && (*ptr != '/')) ptr--;
418 *ptr = 0;
419
420 root = cpath;
421 ext = ptr+1;
422
423 /* treatment */
424 node = node_find_or_create (op, root);
425 if (node)
426 switch (node->type) {
427 case GDA_SERVER_OPERATION_NODE_SEQUENCE: {
428 gint index;
429
430 index = strtol (ext, &ptr, 10);
431 if (ptr && *ptr)
432 index = -1; /* could not convert array[i] to an int */
433 if (index >= 0) {
434 gint i;
435
436 for (i = g_slist_length (node->d.seq.seq_items); i <= index; i++)
437 sequence_add_item (op, node);
438 node = node_find (op, path);
439 g_assert (node);
440 }
441 break;
442 }
443 case GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM: {
444 node = node_find (op, path);
445 g_assert (node);
446 break;
447 }
448 default:
449 node = NULL;
450 break;
451 }
452 g_free(cpath);
453 }
454
455 /*g_print ("# %s (%s) => %p\n", __FUNCTION__, path, node);*/
456
457 return node;
458 }
459
460 /*
461 * Computes the complete path of a node
462 */
463 static gchar *
node_get_complete_path(G_GNUC_UNUSED GdaServerOperation * op,Node * node)464 node_get_complete_path (G_GNUC_UNUSED GdaServerOperation *op, Node *node)
465 {
466 GString *string;
467 gchar *retval;
468 Node *lnode;
469
470 if (!node)
471 return NULL;
472
473 string = g_string_new ("");
474 for (lnode = node; lnode; lnode = lnode->parent) {
475 if (lnode->type == GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM) {
476 gchar *str;
477
478 g_assert (lnode->parent);
479 g_assert (lnode->parent->type == GDA_SERVER_OPERATION_NODE_SEQUENCE);
480 str = g_strdup_printf ("%d", g_slist_index (lnode->parent->d.seq.seq_items, lnode));
481 g_string_prepend (string, str);
482 g_free (str);
483 }
484 else
485 g_string_prepend (string, lnode->path_name);
486 g_string_prepend_c (string, '/');
487 }
488
489 retval = string->str;
490 g_string_free (string, FALSE);
491
492 /*g_print ("%s(%p) => %s\n", __FUNCTION__, node, retval);*/
493 return retval;
494 }
495
496 static GSList *load_xml_spec (GdaServerOperation *op, xmlNodePtr specnode, const gchar *root, GError **error);
497
498 /* add a new item to @node and inserts it into @op's private structures */
499 static void
sequence_add_item(GdaServerOperation * op,Node * node)500 sequence_add_item (GdaServerOperation *op, Node *node)
501 {
502 gchar *path, *seq_path;
503 Node *new_node;
504 GSList *seq_item_nodes, *list;
505
506 g_assert (node);
507 g_assert (node->type == GDA_SERVER_OPERATION_NODE_SEQUENCE);
508
509 seq_path = node_get_complete_path (op, node);
510 path = g_strdup_printf ("%s/%d", seq_path, g_slist_length (node->d.seq.seq_items));
511
512 seq_item_nodes = load_xml_spec (op, node->d.seq.xml_spec, path, NULL);
513 g_assert (seq_item_nodes);
514
515 new_node = node_new (node, GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM, NULL);
516 op->priv->allnodes = g_slist_append (op->priv->allnodes, new_node);
517 new_node->d.seq_item_nodes = NULL;
518 new_node->status = node->status;
519 node->d.seq.seq_items = g_slist_append (node->d.seq.seq_items, new_node);
520
521 new_node->d.seq_item_nodes = seq_item_nodes;
522 for (list = seq_item_nodes; list; list = list->next)
523 ((Node*) list->data)->parent = new_node;
524
525 clean_nodes_info_cache (op);
526 #ifdef GDA_DEBUG_signal
527 g_print (">> 'SEQUENCE_ITEM_ADDED' from %s\n", __FUNCTION__);
528 #endif
529 g_signal_emit (G_OBJECT (op), gda_server_operation_signals [SEQUENCE_ITEM_ADDED], 0,
530 seq_path, g_slist_length (node->d.seq.seq_items) - 1);
531 #ifdef GDA_DEBUG_signal
532 g_print ("<< 'SEQUENCE_ITEM_ADDED' from %s\n", __FUNCTION__);
533 #endif
534
535 g_free (seq_path);
536 g_free (path);
537 }
538
539 static void xml_validity_error_func (void *ctx, const char *msg, ...);
540 static gboolean use_xml_spec (GdaServerOperation *op, xmlDocPtr doc, const gchar *xmlfile);
541
542 static void
gda_server_operation_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)543 gda_server_operation_set_property (GObject *object,
544 guint param_id,
545 const GValue *value,
546 GParamSpec *pspec)
547 {
548 GdaServerOperation *op;
549
550 op = GDA_SERVER_OPERATION (object);
551 if (op->priv) {
552 switch (param_id) {
553 case PROP_CNC:
554 if (op->priv->cnc)
555 g_object_unref (op->priv->cnc);
556
557 op->priv->cnc = GDA_CONNECTION (g_value_get_object (value));
558 op->priv->cnc_set = TRUE;
559
560 if (op->priv->cnc) {
561 g_object_ref (op->priv->cnc);
562
563 if (gda_connection_get_provider (op->priv->cnc)) {
564 if (op->priv->prov)
565 g_object_unref (op->priv->prov);
566 op->priv->prov = gda_connection_get_provider (op->priv->cnc);
567 g_object_ref (op->priv->prov);
568 op->priv->prov_set = TRUE;
569 }
570 }
571 break;
572 case PROP_PROV:
573 if (g_value_get_object (value)) {
574 if (op->priv->prov)
575 g_object_unref (op->priv->prov);
576 op->priv->prov = g_value_get_object(value);
577 g_object_ref (op->priv->prov);
578 }
579 op->priv->prov_set = TRUE;
580 break;
581 case PROP_OP_TYPE:
582 op->priv->op_type = g_value_get_int (value);
583 break;
584 case PROP_SPEC_FILE: {
585 xmlDocPtr doc;
586 const gchar *xmlfile;
587 static GHashTable *doc_hash = NULL; /* key = file name, value = xmlDocPtr */
588
589 xmlfile = g_value_get_string (value);
590 if (!xmlfile)
591 return;
592
593 if (!doc_hash)
594 doc_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
595 g_free, (GDestroyNotify) xmlFreeDoc);
596 else {
597 doc = g_hash_table_lookup (doc_hash, xmlfile);
598 if (doc) {
599 op->priv->xml_spec_doc = doc;
600 break;
601 }
602 }
603
604 if (! g_file_test (xmlfile, G_FILE_TEST_EXISTS)) {
605 g_warning (_("GdaServerOperation: could not find file '%s'"), xmlfile);
606 return;
607 }
608
609 doc = xmlParseFile (xmlfile);
610 if (doc) {
611 if (!use_xml_spec (op, doc, xmlfile))
612 return;
613 g_hash_table_insert (doc_hash, g_strdup (xmlfile), doc);
614 }
615 else {
616 g_warning (_("GdaServerOperation: could not load file '%s'"), xmlfile);
617 return;
618 }
619 break;
620 }
621 default:
622 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
623 break;
624 }
625 }
626
627 if (!op->priv->topnodes && op->priv->xml_spec_doc && op->priv->cnc_set && op->priv->prov_set) {
628 /* load XML file */
629 GError *lerror = NULL;
630 op->priv->topnodes = load_xml_spec (op, xmlDocGetRootElement (op->priv->xml_spec_doc), NULL, &lerror);
631 if (!op->priv->topnodes) {
632 g_warning (_("Could not load XML specifications: %s"),
633 lerror && lerror->message ? lerror->message : _("No detail"));
634 if (lerror)
635 g_error_free (lerror);
636 }
637 }
638 }
639
640 static void
gda_server_operation_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)641 gda_server_operation_get_property (GObject *object,
642 guint param_id,
643 GValue *value,
644 GParamSpec *pspec)
645 {
646 GdaServerOperation *op;
647
648 op = GDA_SERVER_OPERATION (object);
649 if (op->priv) {
650 switch (param_id) {
651 case PROP_CNC:
652 g_value_set_object (value, op->priv->cnc);
653 break;
654 case PROP_PROV:
655 g_value_set_object (value, op->priv->prov);
656 break;
657 case PROP_OP_TYPE:
658 g_value_set_int (value, op->priv->op_type);
659 break;
660 default:
661 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
662 break;
663 }
664 }
665 }
666
667 /*
668 * Steals @doc (it is freed if necessary)
669 */
670 static gboolean
use_xml_spec(GdaServerOperation * op,xmlDocPtr doc,const gchar * xmlfile)671 use_xml_spec (GdaServerOperation *op, xmlDocPtr doc, const gchar *xmlfile)
672 {
673 /* doc validation */
674 xmlValidCtxtPtr validc;
675 int xmlcheck;
676 xmlDtdPtr old_dtd = NULL;
677
678 validc = g_new0 (xmlValidCtxt, 1);
679 validc->userData = op;
680 validc->error = xml_validity_error_func;
681 validc->warning = NULL;
682
683 xmlcheck = xmlDoValidityCheckingDefaultValue;
684 xmlDoValidityCheckingDefaultValue = 1;
685
686 /* replace the DTD with ours */
687 if (_gda_server_op_dtd) {
688 old_dtd = doc->intSubset;
689 doc->intSubset = _gda_server_op_dtd;
690 }
691 #ifndef G_OS_WIN32
692 if (doc->intSubset && !xmlValidateDocument (validc, doc)) {
693 gchar *str;
694
695 if (_gda_server_op_dtd)
696 doc->intSubset = old_dtd;
697 xmlFreeDoc (doc);
698 g_free (validc);
699 str = g_object_get_data (G_OBJECT (op), "xmlerror");
700 if (str) {
701 if (xmlfile)
702 g_warning (_("GdaServerOperation: file '%s' does not conform to DTD:\n%s"),
703 xmlfile, str);
704 else
705 g_warning (_("GdaServerOperation specification does not conform to DTD:\n%s"),
706 str);
707 g_free (str);
708 g_object_set_data (G_OBJECT (op), "xmlerror", NULL);
709 }
710 else {
711 if (xmlfile)
712 g_warning (_("GdaServerOperation: file '%s' does not conform to DTD"),
713 xmlfile);
714 else
715 g_warning (_("GdaServerOperation specification does not conform to DTD\n"));
716 }
717
718 xmlDoValidityCheckingDefaultValue = xmlcheck;
719 xmlFreeDoc (doc);
720 return FALSE;
721 }
722 #endif
723
724 xmlDoValidityCheckingDefaultValue = xmlcheck;
725 g_free (validc);
726 if (_gda_server_op_dtd)
727 doc->intSubset = old_dtd;
728 op->priv->xml_spec_doc = doc;
729
730 return TRUE;
731 }
732
733
734 /*
735 * function called when an error occurred during the document validation
736 */
737 static void
xml_validity_error_func(void * ctx,const char * msg,...)738 xml_validity_error_func (void *ctx, const char *msg, ...)
739 {
740 va_list args;
741 gchar *str, *str2, *newerr;
742 GdaServerOperation *op;
743
744 op = GDA_SERVER_OPERATION (ctx);
745 str2 = g_object_get_data (G_OBJECT (op), "xmlerror");
746
747 va_start (args, msg);
748 str = g_strdup_vprintf (msg, args);
749 va_end (args);
750
751 if (str2) {
752 newerr = g_strdup_printf ("%s\n%s", str2, str);
753 g_free (str2);
754 }
755 else
756 newerr = g_strdup (str);
757 g_free (str);
758 g_object_set_data (G_OBJECT (op), "xmlerror", newerr);
759 }
760
761 /*
762 * Warning: the new nodes' parent is not set!
763 */
764 static GSList *
load_xml_spec(GdaServerOperation * op,xmlNodePtr specnode,const gchar * root,GError ** error)765 load_xml_spec (GdaServerOperation *op, xmlNodePtr specnode, const gchar *root, GError **error)
766 {
767 xmlNodePtr node;
768 const gchar *lang = gda_lang_locale;
769 GSList *retlist = NULL;
770 Node *parent = NULL;
771
772 if (root)
773 parent = node_find (op, root);
774
775 g_assert (specnode);
776
777 /* Parameters' sources, not mandatory: makes the op->priv->sources list */
778 if (!op->priv->sources) {
779 GSList *sources = NULL;
780
781 node = specnode->children;
782 while (node && (xmlNodeIsText (node) || strcmp ((gchar*)node->name, "sources")))
783 node = node->next;
784 if (node && !strcmp ((gchar*)node->name, "sources")) {
785 for (node = node->xmlChildrenNode; (node != NULL); node = node->next) {
786 if (xmlNodeIsText (node))
787 continue;
788
789 if (!strcmp ((gchar*)node->name, "gda_array")) {
790 GdaDataModel *model;
791 GSList *errors;
792
793 model = gda_data_model_import_new_xml_node (node);
794 errors = gda_data_model_import_get_errors (GDA_DATA_MODEL_IMPORT (model));
795 if (errors) {
796 g_object_unref (model);
797 if (sources) {
798 g_slist_foreach (sources, (GFunc) g_object_unref, NULL);
799 g_slist_free (sources);
800 return NULL;
801 }
802 }
803 else {
804 xmlChar *str;
805 sources = g_slist_prepend (sources, model);
806 str = xmlGetProp (node, (xmlChar*)"name");
807 if (str)
808 g_object_set_data_full (G_OBJECT (model), "name", (gchar*)str, xmlFree);
809 }
810 }
811 }
812 }
813 op->priv->sources = sources;
814 }
815
816 /* actual objects loading */
817 node = specnode->children;
818 while (node) {
819 xmlChar *id, *this_lang;
820 gchar *complete_path = NULL, *path_name = NULL;
821 Node *opnode = NULL;
822 Node *old_opnode;
823
824 if (xmlNodeIsText (node)) {
825 xmlNodePtr nextnode;
826 nextnode = node->next;
827 xmlUnlinkNode (node);
828 xmlFreeNode (node);
829 node = nextnode;
830 continue;
831 }
832
833 /* don't care about entries for the wrong locale */
834 this_lang = xmlGetProp(node, (xmlChar*)"lang");
835 if (this_lang) {
836 if (strncmp ((gchar*)this_lang, lang, strlen ((gchar*)this_lang))) {
837 xmlNodePtr nextnode;
838 xmlFree (this_lang);
839 nextnode = node->next;
840 xmlUnlinkNode (node);
841 xmlFreeNode (node);
842 node = nextnode;
843 continue;
844 }
845
846 xmlFree (this_lang);
847 }
848
849 id = xmlGetProp (node, BAD_CAST "id");
850 if (!id) {
851 node = node->next;
852 continue;
853 }
854
855 complete_path = g_strdup_printf ("%s/%s", root ? root : "", id);
856 path_name = g_strdup ((gchar*)id);
857 xmlFree (id);
858
859 old_opnode = node_find (op, complete_path);
860 if (old_opnode) {
861 node_destroy (op, old_opnode);
862 retlist = g_slist_remove (retlist, old_opnode);
863 }
864
865 /* GDA_SERVER_OPERATION_NODE_PARAMLIST */
866 if (!strcmp ((gchar*)node->name, "parameters")) {
867 GdaSet *plist;
868
869 plist = gda_set_new_from_spec_node (node, error);
870 if (plist) {
871 opnode = node_new (parent, GDA_SERVER_OPERATION_NODE_PARAMLIST, path_name);
872 opnode->d.plist = plist;
873 }
874 }
875 /* GDA_SERVER_OPERATION_NODE_DATA_MODEL */
876 else if (!strcmp ((gchar*)node->name, "gda_array")) {
877 GdaDataModel *import;
878
879 import = gda_data_model_import_new_xml_node (node);
880 if (import) {
881 GdaDataModel *model;
882 model = (GdaDataModel*) gda_data_model_array_copy_model (import, NULL);
883 opnode = node_new (parent, GDA_SERVER_OPERATION_NODE_DATA_MODEL, path_name);
884 opnode->d.model = model;
885 g_object_unref (import);
886 }
887 }
888
889 /* GDA_SERVER_OPERATION_NODE_SEQUENCE */
890 else if (!strcmp ((gchar*)node->name, "sequence")) {
891 GSList *seq_tmpl = NULL;
892 xmlChar *prop;
893
894 opnode = node_new (parent, GDA_SERVER_OPERATION_NODE_SEQUENCE, path_name);
895 opnode->d.seq.seq_tmpl = NULL;
896 opnode->d.seq.min_items = 0;
897 opnode->d.seq.max_items = G_MAXUINT;
898 opnode->d.seq.seq_items = NULL;
899 opnode->d.seq.xml_spec = node;
900
901 prop = xmlGetProp(node, (xmlChar*)"name");
902 if (prop) {
903 opnode->d.seq.name = g_strdup ((gchar*)prop);
904 xmlFree (prop);
905 }
906
907 prop = xmlGetProp(node, (xmlChar*)"descr");
908 if (prop) {
909 opnode->d.seq.descr = g_strdup ((gchar*)prop);
910 xmlFree (prop);
911 }
912
913
914 prop = xmlGetProp(node, (xmlChar*)"minitems");
915 if (prop) {
916 gint tmp;
917 tmp = atoi ((gchar*)prop); /* Flawfinder: ignore */
918 if (tmp < 0)
919 opnode->d.seq.min_items = 0;
920 else
921 opnode->d.seq.min_items = tmp;
922 xmlFree (prop);
923 }
924
925 prop = xmlGetProp(node, (xmlChar*)"maxitems");
926 if (prop) {
927 opnode->d.seq.max_items = atoi ((gchar*)prop); /* Flawfinder: ignore */
928 if (opnode->d.seq.max_items < opnode->d.seq.min_items)
929 opnode->d.seq.max_items = opnode->d.seq.min_items;
930 xmlFree (prop);
931 }
932
933 seq_tmpl = load_xml_spec (op, node, complete_path, error);
934 if (! seq_tmpl) {
935 node_destroy (NULL, opnode);
936 opnode = NULL;
937 }
938 else
939 opnode->d.seq.seq_tmpl = seq_tmpl;
940 }
941
942 /* GDA_SERVER_OPERATION_NODE_PARAM */
943 else if (!strcmp ((gchar*)node->name, "parameter")) {
944 GdaHolder *param = NULL;
945 xmlChar *gdatype;
946 GType gt;
947
948 /* find data type and create GdaHolder */
949 gdatype = xmlGetProp (node, BAD_CAST "gdatype");
950 gt = gdatype ? gda_g_type_from_string ((gchar*) gdatype) : G_TYPE_STRING;
951 if (gt == G_TYPE_INVALID)
952 gt = GDA_TYPE_NULL;
953 param = GDA_HOLDER (g_object_new (GDA_TYPE_HOLDER,
954 "g-type", gt,
955 NULL));
956 if (gdatype)
957 xmlFree (gdatype);
958
959 /* set parameter's attributes */
960 if (gda_utility_holder_load_attributes (param, node, op->priv->sources, error)) {
961 opnode = node_new (parent, GDA_SERVER_OPERATION_NODE_PARAM, path_name);
962 opnode->d.param = param;
963 }
964 }
965 else {
966 node = node->next;
967 g_free (path_name);
968 continue;
969 }
970
971 /* really insert the new Node, and set its status */
972 if (opnode) {
973 xmlChar *status;
974
975 /* insert */
976 op->priv->allnodes = g_slist_append (op->priv->allnodes, opnode);
977 retlist = g_slist_append (retlist, opnode);
978 /*g_print ("+ %s (node's path = %s) %p\n", complete_path, opnode->path_name, opnode);*/
979
980 /* status */
981 status = xmlGetProp (node, BAD_CAST "status");
982 if (status) {
983 if (!strcmp ((gchar*)status, "OPT"))
984 opnode->status = GDA_SERVER_OPERATION_STATUS_OPTIONAL;
985 xmlFree (status);
986 }
987
988 if (opnode->type == GDA_SERVER_OPERATION_NODE_SEQUENCE) {
989 /* add sequence items if necessary */
990 if (opnode->d.seq.min_items > 0) {
991 guint i;
992
993 for (i = 0; i < opnode->d.seq.min_items; i++)
994 gda_server_operation_add_item_to_sequence (op, complete_path);
995 }
996 }
997 }
998 else {
999 g_free (path_name);
1000 g_free (complete_path);
1001 g_slist_free (retlist);
1002 return NULL;
1003 }
1004 g_free (path_name);
1005 g_free (complete_path);
1006 node = node->next;
1007 }
1008
1009 return retlist;
1010 }
1011
1012 /*
1013 * @xml_spec: the specifications for the GdaServerOperation object to create as a string
1014 * Internal function
1015 */
1016 GdaServerOperation *
_gda_server_operation_new_from_string(GdaServerOperationType op_type,const gchar * xml_spec)1017 _gda_server_operation_new_from_string (GdaServerOperationType op_type,
1018 const gchar *xml_spec)
1019 {
1020 GObject *obj;
1021 xmlDocPtr doc;
1022 GdaServerOperation *op;
1023
1024 doc = xmlParseMemory (xml_spec, strlen (xml_spec) + 1);
1025 if (!doc)
1026 return NULL;
1027 obj = g_object_new (GDA_TYPE_SERVER_OPERATION, "op-type", op_type, NULL);
1028 op = GDA_SERVER_OPERATION (obj);
1029 use_xml_spec (op, doc, NULL);
1030
1031 if (!op->priv->topnodes && op->priv->xml_spec_doc && op->priv->cnc_set && op->priv->prov_set) {
1032 /* load XML file */
1033 GError *lerror = NULL;
1034 op->priv->topnodes = load_xml_spec (op, xmlDocGetRootElement (op->priv->xml_spec_doc), NULL, &lerror);
1035 if (!op->priv->topnodes) {
1036 g_warning (_("Could not load XML specifications: %s"),
1037 lerror && lerror->message ? lerror->message : _("No detail"));
1038 if (lerror)
1039 g_error_free (lerror);
1040 }
1041 }
1042
1043 return op;
1044 }
1045
1046
1047 /**
1048 * gda_server_operation_new:
1049 * @op_type: type of operation
1050 * @xml_file: a file which has the specifications for the GdaServerOperation object to create
1051 *
1052 * IMPORTANT NOTE: Using this funtion is not the recommended way of creating a #GdaServerOperation object, the
1053 * correct way is to use gda_server_provider_create_operation(); this method is reserved for the database provider's
1054 * implementation.
1055 *
1056 * Creates a new #GdaServerOperation object from the @xml_file specifications
1057 *
1058 * The @xml_file must respect the DTD described in the "libgda-server-operation.dtd" file: its top
1059 * node must be a <serv_op> tag.
1060 *
1061 * Returns: a new #GdaServerOperation object
1062 */
1063 GdaServerOperation *
gda_server_operation_new(GdaServerOperationType op_type,const gchar * xml_file)1064 gda_server_operation_new (GdaServerOperationType op_type, const gchar *xml_file)
1065 {
1066 GObject *obj;
1067
1068 obj = g_object_new (GDA_TYPE_SERVER_OPERATION, "op-type", op_type,
1069 "spec-filename", xml_file, NULL);
1070 #ifdef GDA_DEBUG_NO
1071 {
1072 g_print ("New GdaServerOperation:\n");
1073 xmlNodePtr node;
1074 node = gda_server_operation_save_data_to_xml ((GdaServerOperation *) obj, NULL);
1075 xmlDocPtr doc;
1076 doc = xmlNewDoc ("1.0");
1077 xmlDocSetRootElement (doc, node);
1078 xmlDocDump (stdout, doc);
1079 xmlFreeDoc (doc);
1080 }
1081 #endif
1082 return (GdaServerOperation *) obj;
1083 }
1084
1085 /**
1086 * gda_server_operation_get_node_info:
1087 * @op: a #GdaServerOperation object
1088 * @path_format: a complete path to a node (starting with "/") as a format string, similar to g_strdup_printf()'s argument
1089 * @...: the arguments to insert into the format string
1090 *
1091 * Get information about the node identified by @path. The returned #GdaServerOperationNode structure can be
1092 * copied but not modified; it may change or cease to exist if @op changes
1093 *
1094 * Returns: (transfer none) (nullable): a #GdaServerOperationNode structure, or %NULL if the node was not found
1095 */
1096 GdaServerOperationNode *
gda_server_operation_get_node_info(GdaServerOperation * op,const gchar * path_format,...)1097 gda_server_operation_get_node_info (GdaServerOperation *op, const gchar *path_format, ...)
1098 {
1099 GdaServerOperationNode *info_node;
1100 Node *node;
1101 gchar *path;
1102 va_list args;
1103
1104 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL);
1105 g_return_val_if_fail (op->priv, NULL);
1106
1107 /* build path */
1108 va_start (args, path_format);
1109 path = g_strdup_vprintf (path_format, args);
1110 va_end (args);
1111
1112 /* use path */
1113 info_node = g_hash_table_lookup (op->priv->info_hash, path);
1114 if (info_node) {
1115 g_free (path);
1116 return info_node;
1117 }
1118
1119 /* compute a new GdaServerOperationNode */
1120 node = node_find (op, path);
1121 if (node) {
1122 info_node = g_new0 (GdaServerOperationNode, 1);
1123 info_node->priv = node;
1124 info_node->type = node->type;
1125 info_node->status = node->status;
1126 switch (node->type) {
1127 case GDA_SERVER_OPERATION_NODE_PARAMLIST:
1128 info_node->plist = node->d.plist;
1129 break;
1130 case GDA_SERVER_OPERATION_NODE_DATA_MODEL:
1131 info_node->model = node->d.model;
1132 break;
1133 case GDA_SERVER_OPERATION_NODE_PARAM:
1134 info_node->param = node->d.param;
1135 break;
1136 default:
1137 break;
1138 }
1139 }
1140 else {
1141 /* try to see if the "parent" is a real node */
1142 gchar *str;
1143 gchar *extension;
1144
1145 str = gda_server_operation_get_node_parent (op, path);
1146 if (str) {
1147 node = node_find (op, str);
1148 if (node && (node->type != GDA_SERVER_OPERATION_NODE_PARAMLIST) &&
1149 (node->type != GDA_SERVER_OPERATION_NODE_DATA_MODEL))
1150 node = NULL; /* ignore node */
1151 g_free (str);
1152 }
1153 if (node && (node->type == GDA_SERVER_OPERATION_NODE_PARAMLIST)) {
1154 GdaHolder *param;
1155 extension = gda_server_operation_get_node_path_portion (op, path);
1156 param = gda_set_get_holder (node->d.plist, extension);
1157 g_free (extension);
1158
1159 if (param) {
1160 info_node = g_new0 (GdaServerOperationNode, 1);
1161 info_node->type = GDA_SERVER_OPERATION_NODE_PARAM;
1162 info_node->status = node->status;
1163 info_node->param = param;
1164 }
1165 }
1166 if (node && (node->type == GDA_SERVER_OPERATION_NODE_DATA_MODEL)) {
1167 GdaColumn *column = NULL;
1168
1169 extension = gda_server_operation_get_node_path_portion (op, path);
1170 if (extension && (*extension == '@')) {
1171 gint i, nbcols;
1172 GdaDataModel *model;
1173
1174 model = node->d.model;
1175 nbcols = gda_data_model_get_n_columns (model);
1176 for (i = 0; (i<nbcols) && !column; i++) {
1177 gchar *colid = NULL;
1178 column = gda_data_model_describe_column (model, i);
1179 g_object_get (G_OBJECT (column), "id", &colid, NULL);
1180 if (!colid || strcmp (colid, extension +1))
1181 column = NULL;
1182 g_free(colid);
1183 }
1184 }
1185 g_free (extension);
1186 if (column) {
1187 info_node = g_new0 (GdaServerOperationNode, 1);
1188 info_node->type = GDA_SERVER_OPERATION_NODE_DATA_MODEL_COLUMN;
1189 info_node->status = node->status;
1190 info_node->column = column;
1191 info_node->model = node->d.model;
1192 }
1193 }
1194 }
1195
1196 if (info_node)
1197 g_hash_table_insert (op->priv->info_hash, g_strdup (path), info_node);
1198
1199 g_free (path);
1200 return info_node;
1201 }
1202
1203 /**
1204 * gda_server_operation_get_op_type:
1205 * @op: a #GdaServerOperation object
1206 *
1207 * Get the type of operation @op is for
1208 *
1209 * Returns: a #GdaServerOperationType enum
1210 */
1211 GdaServerOperationType
gda_server_operation_get_op_type(GdaServerOperation * op)1212 gda_server_operation_get_op_type (GdaServerOperation *op)
1213 {
1214 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), 0);
1215 g_return_val_if_fail (op->priv, 0);
1216
1217 return op->priv->op_type;
1218 }
1219
1220 /**
1221 * gda_server_operation_op_type_to_string:
1222 * @type: a #GdaServerOperationType value
1223 *
1224 * Get a string version of @type
1225 *
1226 * Returns: (transfer none): a non %NULL string (do not free or modify)
1227 */
1228 const gchar *
gda_server_operation_op_type_to_string(GdaServerOperationType type)1229 gda_server_operation_op_type_to_string (GdaServerOperationType type)
1230 {
1231 switch (type) {
1232 case GDA_SERVER_OPERATION_CREATE_DB:
1233 return "CREATE_DB";
1234 case GDA_SERVER_OPERATION_DROP_DB:
1235 return "DROP_DB";
1236 case GDA_SERVER_OPERATION_CREATE_TABLE:
1237 return "CREATE_TABLE";
1238 case GDA_SERVER_OPERATION_DROP_TABLE:
1239 return "DROP_TABLE";
1240 case GDA_SERVER_OPERATION_CREATE_INDEX:
1241 return "CREATE_INDEX";
1242 case GDA_SERVER_OPERATION_DROP_INDEX:
1243 return "DROP_INDEX";
1244 case GDA_SERVER_OPERATION_RENAME_TABLE:
1245 return "RENAME_TABLE";
1246 case GDA_SERVER_OPERATION_COMMENT_TABLE:
1247 return "COMMENT_TABLE";
1248 case GDA_SERVER_OPERATION_ADD_COLUMN:
1249 return "ADD_COLUMN";
1250 case GDA_SERVER_OPERATION_DROP_COLUMN:
1251 return "DROP_COLUMN";
1252 case GDA_SERVER_OPERATION_COMMENT_COLUMN:
1253 return "COMMENT_COLUMN";
1254 case GDA_SERVER_OPERATION_CREATE_VIEW:
1255 return "CREATE_VIEW";
1256 case GDA_SERVER_OPERATION_DROP_VIEW:
1257 return "DROP_VIEW";
1258 case GDA_SERVER_OPERATION_CREATE_USER:
1259 return "CREATE_USER";
1260 case GDA_SERVER_OPERATION_DROP_USER:
1261 return "DROP_USER";
1262 case GDA_SERVER_OPERATION_ALTER_USER:
1263 return "ALTER_USER";
1264 default:
1265 g_error (_("Non handled GdaServerOperationType, please report error to "
1266 "http://bugzilla.gnome.org/ for the \"libgda\" product"));
1267 return "";
1268 }
1269 }
1270
1271 /**
1272 * gda_server_operation_string_to_op_type:
1273 * @str: a string
1274 *
1275 * Performs the reverse of gda_server_operation_op_type_to_string()
1276 *
1277 * Returns: the #GdaServerOperationType represented by @str, or #G_MAXINT if @str is not a valid representation
1278 * of a #GdaServerOperationType
1279 *
1280 * Since: 4.2
1281 */
1282 GdaServerOperationType
gda_server_operation_string_to_op_type(const gchar * str)1283 gda_server_operation_string_to_op_type (const gchar *str)
1284 {
1285 GdaServerOperationType operation_type = G_MAXINT;
1286 g_return_val_if_fail (str && *str, G_MAXINT);
1287
1288 if (! g_ascii_strcasecmp (str, "CREATE_DB"))
1289 operation_type = GDA_SERVER_OPERATION_CREATE_DB;
1290 else if (! g_ascii_strcasecmp (str, "DROP_DB"))
1291 operation_type = GDA_SERVER_OPERATION_DROP_DB;
1292 else if (! g_ascii_strcasecmp (str, "CREATE_TABLE"))
1293 operation_type = GDA_SERVER_OPERATION_CREATE_TABLE;
1294 else if (! g_ascii_strcasecmp (str, "DROP_TABLE"))
1295 operation_type = GDA_SERVER_OPERATION_DROP_TABLE;
1296 else if (! g_ascii_strcasecmp (str, "CREATE_INDEX"))
1297 operation_type = GDA_SERVER_OPERATION_CREATE_INDEX;
1298 else if (! g_ascii_strcasecmp (str, "DROP_INDEX"))
1299 operation_type = GDA_SERVER_OPERATION_DROP_INDEX;
1300 else if (! g_ascii_strcasecmp (str, "RENAME_TABLE"))
1301 operation_type = GDA_SERVER_OPERATION_RENAME_TABLE;
1302 else if (! g_ascii_strcasecmp (str, "COMMENT_TABLE"))
1303 operation_type = GDA_SERVER_OPERATION_COMMENT_TABLE;
1304 else if (! g_ascii_strcasecmp (str, "ADD_COLUMN"))
1305 operation_type = GDA_SERVER_OPERATION_ADD_COLUMN;
1306 else if (! g_ascii_strcasecmp (str, "DROP_COLUMN"))
1307 operation_type = GDA_SERVER_OPERATION_DROP_COLUMN;
1308 else if (! g_ascii_strcasecmp (str, "COMMENT_COLUMN"))
1309 operation_type = GDA_SERVER_OPERATION_COMMENT_COLUMN;
1310 else if (! g_ascii_strcasecmp (str, "CREATE_VIEW"))
1311 operation_type = GDA_SERVER_OPERATION_CREATE_VIEW;
1312 else if (! g_ascii_strcasecmp (str, "DROP_VIEW"))
1313 operation_type = GDA_SERVER_OPERATION_DROP_VIEW;
1314 else if (! g_ascii_strcasecmp (str, "CREATE_USER"))
1315 operation_type = GDA_SERVER_OPERATION_CREATE_USER;
1316 else if (! g_ascii_strcasecmp (str, "DROP_USER"))
1317 operation_type = GDA_SERVER_OPERATION_DROP_USER;
1318 else if (! g_ascii_strcasecmp (str, "ALTER_USER"))
1319 operation_type = GDA_SERVER_OPERATION_ALTER_USER;
1320
1321 return operation_type;
1322 }
1323
1324 static gboolean node_save (GdaServerOperation *op, Node *opnode, xmlNodePtr parent);
1325
1326 /**
1327 * gda_server_operation_save_data_to_xml: (skip)
1328 * @op: a #GdaServerOperation object
1329 * @error: (nullable): a place to store errors or %NULL
1330 *
1331 * Creates a new #xmlNodePtr tree which can be used to save the #op object. This
1332 * XML structure can then be saved to disk if necessary. Use xmlFreeNode to free
1333 * the associated memory when not needed anymore.
1334 *
1335 * Returns: (transfer full): a new #xmlNodePtr structure, or %NULL
1336 */
1337 xmlNodePtr
gda_server_operation_save_data_to_xml(GdaServerOperation * op,G_GNUC_UNUSED GError ** error)1338 gda_server_operation_save_data_to_xml (GdaServerOperation *op, G_GNUC_UNUSED GError **error)
1339 {
1340 xmlNodePtr topnode = NULL;
1341 GSList *list;
1342
1343 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL);
1344 g_return_val_if_fail (op->priv, NULL);
1345
1346 topnode = xmlNewNode (NULL, BAD_CAST "serv_op_data");
1347 xmlSetProp (topnode, BAD_CAST "type",
1348 BAD_CAST gda_server_operation_op_type_to_string (gda_server_operation_get_op_type (op)));
1349
1350 for (list = op->priv->topnodes; list; list = list->next) {
1351 if (!node_save (op, NODE (list->data), topnode)) {
1352 xmlFreeNode (topnode);
1353 topnode = NULL;
1354 break;
1355 }
1356 }
1357
1358 return topnode;
1359 }
1360
1361 static gboolean
node_save(GdaServerOperation * op,Node * opnode,xmlNodePtr parent)1362 node_save (GdaServerOperation *op, Node *opnode, xmlNodePtr parent)
1363 {
1364 gboolean retval = TRUE;
1365 xmlNodePtr node;
1366 GSList *list;
1367 gchar *complete_path;
1368 g_assert (opnode);
1369
1370 complete_path = node_get_complete_path (op, opnode);
1371 switch (opnode->type) {
1372 case GDA_SERVER_OPERATION_NODE_PARAMLIST:
1373 for (list = opnode->d.plist->holders; list; list = list->next) {
1374 gchar *path;
1375 const GValue *value;
1376 gchar *str;
1377
1378 value = gda_holder_get_value (GDA_HOLDER (list->data));
1379 if (!value || gda_value_is_null ((GValue *) value))
1380 str = NULL;
1381 else {
1382 if (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN)
1383 str = g_strdup (g_value_get_boolean (value) ? "TRUE" : "FALSE");
1384 else
1385 str = gda_value_stringify (value);
1386 }
1387 node = xmlNewTextChild (parent, NULL, BAD_CAST "op_data", (xmlChar*)str);
1388 g_free (str);
1389
1390 path = g_strdup_printf ("%s/%s", complete_path, gda_holder_get_id (GDA_HOLDER (list->data)));
1391 xmlSetProp(node, (xmlChar*)"path", (xmlChar*)path);
1392 g_free (path);
1393 }
1394 break;
1395 case GDA_SERVER_OPERATION_NODE_DATA_MODEL:
1396 node = xmlNewChild (parent, NULL, BAD_CAST "op_data", NULL);
1397 xmlSetProp(node, (xmlChar*)"path", (xmlChar*)complete_path);
1398 if (!gda_utility_data_model_dump_data_to_xml (opnode->d.model, node, NULL, 0, NULL, 0, TRUE))
1399 retval = FALSE;
1400 break;
1401 case GDA_SERVER_OPERATION_NODE_PARAM: {
1402 const GValue *value;
1403 gchar *str;
1404
1405 value = gda_holder_get_value (opnode->d.param);
1406 if (!value || gda_value_is_null ((GValue *) value))
1407 str = NULL;
1408 else {
1409 if (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN)
1410 str = g_strdup (g_value_get_boolean (value) ? "TRUE" : "FALSE");
1411 else
1412 str = gda_value_stringify (value);
1413 }
1414 node = xmlNewTextChild (parent, NULL, BAD_CAST "op_data", (xmlChar*)str);
1415 g_free (str);
1416 xmlSetProp(node, (xmlChar*)"path", (xmlChar*)complete_path);
1417 break;
1418 }
1419 case GDA_SERVER_OPERATION_NODE_SEQUENCE: {
1420 GSList *list;
1421
1422 for (list = opnode->d.seq.seq_items; list; list = list->next)
1423 if (!node_save (op, NODE (list->data), parent)) {
1424 retval = FALSE;
1425 break;
1426 }
1427 break;
1428 }
1429 case GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM: {
1430 GSList *list;
1431
1432 for (list = opnode->d.seq_item_nodes; list; list = list->next)
1433 if (! node_save (op, NODE (list->data), parent)) {
1434 retval = FALSE;
1435 break;
1436 }
1437 break;
1438 }
1439 default:
1440 g_assert_not_reached ();
1441 }
1442
1443 g_free (complete_path);
1444 return retval;
1445 }
1446
1447 /**
1448 * gda_server_operation_load_data_from_xml:
1449 * @op: a #GdaServerOperation object
1450 * @node: a #xmlNodePtr
1451 * @error: (nullable): a place to store errors or %NULL
1452 *
1453 * Loads the contents of @node into @op. The XML tree passed through the @node
1454 * argument must correspond to an XML tree saved using gda_server_operation_save_data_to_xml().
1455 *
1456 * Returns: %TRUE if no error occurred
1457 */
1458 gboolean
gda_server_operation_load_data_from_xml(GdaServerOperation * op,xmlNodePtr node,GError ** error)1459 gda_server_operation_load_data_from_xml (GdaServerOperation *op, xmlNodePtr node, GError **error)
1460 {
1461 xmlNodePtr cur;
1462
1463 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE);
1464 g_return_val_if_fail (op->priv, FALSE);
1465 if (!node)
1466 return FALSE;
1467
1468 /* remove any sequence items */
1469 GSList *list;
1470 list = op->priv->allnodes;
1471 while (list) {
1472 Node *node = NODE (list->data);
1473 if ((node->type == GDA_SERVER_OPERATION_NODE_SEQUENCE) && node->d.seq.seq_items) {
1474 gchar *seq_path;
1475
1476 seq_path = node_get_complete_path (op, node);
1477 while (node->d.seq.seq_items) {
1478 #ifdef GDA_DEBUG_signal
1479 g_print (">> 'SEQUENCE_ITEM_REMOVE' from %s\n", __FUNCTION__);
1480 #endif
1481 g_signal_emit (G_OBJECT (op), gda_server_operation_signals [SEQUENCE_ITEM_REMOVE], 0,
1482 seq_path, 0);
1483 #ifdef GDA_DEBUG_signal
1484 g_print ("<< 'SEQUENCE_ITEM_REMOVE' from %s\n", __FUNCTION__);
1485 #endif
1486 node_destroy (op, NODE (node->d.seq.seq_items->data));
1487 node->d.seq.seq_items = g_slist_delete_link (node->d.seq.seq_items, node->d.seq.seq_items);
1488 }
1489 g_free (seq_path);
1490 list = op->priv->allnodes;
1491 }
1492 else
1493 list = list->next;
1494 }
1495
1496 /* actual data loading */
1497 if (strcmp ((gchar*)node->name, "serv_op_data")) {
1498 g_set_error (error, GDA_SERVER_OPERATION_ERROR,
1499 GDA_SERVER_OPERATION_XML_ERROR,
1500 _("Expected tag <%s>, got <%s>"), "serv_op_data", node->name);
1501 return FALSE;
1502 }
1503
1504 cur = node->children;
1505 while (cur) {
1506 xmlChar *prop;
1507 if (xmlNodeIsText (cur)) {
1508 cur = cur->next;
1509 continue;
1510 }
1511
1512 if (strcmp ((gchar*)cur->name, "op_data")) {
1513 g_set_error (error, GDA_SERVER_OPERATION_ERROR,
1514 GDA_SERVER_OPERATION_XML_ERROR,
1515 _("Expected tag <%s>, got <%s>"), "op_data", cur->name);
1516 return FALSE;
1517 }
1518
1519 prop = xmlGetProp(cur, (xmlChar*)"path");
1520 if (prop) {
1521 Node *opnode;
1522 gchar *extension = NULL;
1523 gboolean allok = TRUE;
1524
1525 opnode = node_find_or_create (op, (gchar*)prop);
1526 if (!opnode) {
1527 /* try to see if the "parent" is a real node */
1528 gchar *str;
1529
1530 str = gda_server_operation_get_node_parent (op, (gchar*)prop);
1531 if (str) {
1532 opnode = node_find (op, str);
1533 if (opnode && (opnode->type != GDA_SERVER_OPERATION_NODE_PARAMLIST))
1534 opnode = NULL; /* ignore opnode */
1535 g_free (str);
1536 }
1537 if (opnode)
1538 extension = gda_server_operation_get_node_path_portion (op, (gchar*)prop);
1539 }
1540
1541 if (opnode) {
1542 switch (opnode->type) {
1543 case GDA_SERVER_OPERATION_NODE_PARAMLIST:
1544 if (!extension) {
1545 g_set_error (error,
1546 GDA_SERVER_OPERATION_ERROR,
1547 GDA_SERVER_OPERATION_XML_ERROR,
1548 "%s",
1549 _("Parameterlist values can only be set for individual parameters within it"));
1550 allok = FALSE;
1551 }
1552 else {
1553 xmlNodePtr contents;
1554
1555 contents = cur->children;
1556 if (contents && xmlNodeIsText (contents)) {
1557 GdaHolder *param;
1558 param = gda_set_get_holder (opnode->d.plist, extension);
1559 if (param) {
1560 GValue *v;
1561 v = gda_value_new_from_string ((gchar*)contents->content,
1562 gda_holder_get_g_type (param));
1563 if (!gda_holder_take_value (param, v, error))
1564 allok = FALSE;
1565 }
1566 }
1567 }
1568 break;
1569 case GDA_SERVER_OPERATION_NODE_DATA_MODEL:
1570 gda_data_model_array_clear (GDA_DATA_MODEL_ARRAY (opnode->d.model));
1571 if (cur->children &&
1572 ! gda_data_model_add_data_from_xml_node (opnode->d.model,
1573 cur->children, error))
1574 allok = FALSE;
1575 break;
1576 case GDA_SERVER_OPERATION_NODE_PARAM: {
1577 xmlNodePtr contents;
1578
1579 contents = cur->children;
1580 if (contents && xmlNodeIsText (contents)) {
1581 GValue *v;
1582 v = gda_value_new_from_string ((gchar*)contents->content,
1583 gda_holder_get_g_type (opnode->d.param));
1584 if (!gda_holder_take_value (opnode->d.param, v, error))
1585 allok = FALSE;
1586 }
1587 break;
1588 }
1589 case GDA_SERVER_OPERATION_NODE_SEQUENCE:
1590 break;
1591 case GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM:
1592 break;
1593 default:
1594 g_assert_not_reached ();
1595 }
1596 }
1597
1598 g_free (extension);
1599 xmlFree (prop);
1600
1601 if (!allok)
1602 return FALSE;
1603 }
1604 else {
1605 g_set_error (error, GDA_SERVER_OPERATION_ERROR,
1606 GDA_SERVER_OPERATION_XML_ERROR,
1607 "%s", _("Missing attribute named 'path'"));
1608 return FALSE;
1609 }
1610
1611 cur = cur->next;
1612 }
1613
1614 return TRUE;
1615 }
1616
1617 /**
1618 * gda_server_operation_get_root_nodes:
1619 * @op: a #GdaServerOperation object
1620 *
1621 * Get an array of strings containing the paths of nodes situated at the root of @op.
1622 *
1623 * Returns: (transfer full): a new array, which must be freed with g_strfreev().
1624 */
1625 gchar**
gda_server_operation_get_root_nodes(GdaServerOperation * op)1626 gda_server_operation_get_root_nodes (GdaServerOperation *op)
1627 {
1628 gchar **retval;
1629 GSList *list;
1630 gint i = 0;
1631
1632 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL);
1633 g_return_val_if_fail (op->priv, NULL);
1634
1635 retval = g_new0 (gchar *, g_slist_length (op->priv->topnodes) + 1);
1636 for (list = op->priv->topnodes; list; list = list->next)
1637 retval [i++] = node_get_complete_path (op, NODE (list->data));
1638
1639 return retval;
1640 }
1641
1642 /**
1643 * gda_server_operation_get_node_type:
1644 * @op: a #GdaServerOperation object
1645 * @path: a complete path to a node (starting with "/")
1646 * @status: (nullable): a place to store the status of the node, or %NULL
1647 *
1648 * Convenience function to get the type of a node.
1649 *
1650 * Returns: the type of node, or GDA_SERVER_OPERATION_NODE_UNKNOWN if the node was not found
1651 */
1652 GdaServerOperationNodeType
gda_server_operation_get_node_type(GdaServerOperation * op,const gchar * path,GdaServerOperationNodeStatus * status)1653 gda_server_operation_get_node_type (GdaServerOperation *op, const gchar *path,
1654 GdaServerOperationNodeStatus *status)
1655 {
1656 GdaServerOperationNode *node_info;
1657
1658 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), GDA_SERVER_OPERATION_NODE_UNKNOWN);
1659 g_return_val_if_fail (op->priv, GDA_SERVER_OPERATION_NODE_UNKNOWN);
1660
1661 node_info = gda_server_operation_get_node_info (op, path);
1662 if (node_info) {
1663 if (status)
1664 *status = node_info->status;
1665 return node_info->type;
1666 }
1667 return GDA_SERVER_OPERATION_NODE_UNKNOWN;
1668 }
1669
1670 /**
1671 * gda_server_operation_get_node_parent:
1672 * @op: a #GdaServerOperation object
1673 * @path: a complete path to a node (starting with "/")
1674 *
1675 * Get the complete path to the parent of the node defined by @path
1676 *
1677 * Returns: (transfer full): a new string or %NULL if the node does not have any parent or does not exist.
1678 */
1679 gchar *
gda_server_operation_get_node_parent(GdaServerOperation * op,const gchar * path)1680 gda_server_operation_get_node_parent (GdaServerOperation *op, const gchar *path)
1681 {
1682 Node *node;
1683
1684 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL);
1685 g_return_val_if_fail (op->priv, NULL);
1686 g_return_val_if_fail (path && (*path == '/'), NULL);
1687
1688 node = node_find (op, path);
1689
1690 if (node) {
1691 if (! node->parent)
1692 return NULL;
1693 else
1694 return node_get_complete_path (op, node->parent);
1695 }
1696 else {
1697 gchar *path2 = g_strdup (path);
1698 gchar *ptr;
1699
1700 ptr = path2 + strlen (path2) - 1;
1701 while (*ptr != '/') {
1702 *ptr = 0;
1703 ptr --;
1704 }
1705 *ptr = 0;
1706
1707 return path2;
1708 }
1709 }
1710
1711 /**
1712 * gda_server_operation_get_node_path_portion:
1713 * @op: a #GdaServerOperation object
1714 * @path: a complete path to a node (starting with "/")
1715 *
1716 * Get the last part of @path
1717 *
1718 * Returns: (transfer full): a new string, or %NULL if an error occurred
1719 */
1720 gchar *
gda_server_operation_get_node_path_portion(GdaServerOperation * op,const gchar * path)1721 gda_server_operation_get_node_path_portion (GdaServerOperation *op, const gchar *path)
1722 {
1723 Node *node;
1724
1725 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL);
1726 g_return_val_if_fail (op->priv, NULL);
1727 g_return_val_if_fail (path && (*path == '/'), NULL);
1728
1729 node = node_find (op, path);
1730 if (!node) {
1731 gchar *path2 = g_strdup (path);
1732 gchar *ptr, *retval = NULL;
1733
1734 ptr = path2 + strlen (path2) - 1;
1735 while (*ptr != '/')
1736 ptr --;
1737 retval = g_strdup (ptr + 1);
1738 g_free (path2);
1739 return retval;
1740 }
1741 else {
1742 if (node->type == GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM) {
1743 g_assert (node->parent);
1744 g_assert (node->parent->type == GDA_SERVER_OPERATION_NODE_SEQUENCE);
1745 return g_strdup_printf ("%d", g_slist_index (node->parent->d.seq.seq_items, node));
1746 }
1747 else
1748 return g_strdup (node->path_name);
1749 }
1750 }
1751
1752 /**
1753 * gda_server_operation_get_sequence_item_names:
1754 * @op: a #GdaServerOperation object
1755 * @path: a complete path to a sequence node (starting with "/")
1756 *
1757 * Fetch the contents of a sequence. @path can describe either a sequence (for example "/SEQNAME") or an item in a sequence
1758 * (for example "/SEQNAME/3")
1759 *
1760 * Returns: (transfer full): a array of strings containing the complete paths of the nodes contained at @path (free with g_strfreev())
1761 */
1762 gchar **
gda_server_operation_get_sequence_item_names(GdaServerOperation * op,const gchar * path)1763 gda_server_operation_get_sequence_item_names (GdaServerOperation *op, const gchar *path)
1764 {
1765 Node *node;
1766 gchar **retval;
1767 gint i;
1768 GSList *list;
1769
1770 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL);
1771 g_return_val_if_fail (op->priv, NULL);
1772
1773 node = node_find (op, path);
1774 if (!node || ((node->type != GDA_SERVER_OPERATION_NODE_SEQUENCE) &&
1775 (node->type != GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM)))
1776 return NULL;
1777
1778 if (node->type == GDA_SERVER_OPERATION_NODE_SEQUENCE)
1779 list = node->d.seq.seq_tmpl;
1780 else
1781 list = node->d.seq_item_nodes;
1782 i = 0;
1783 retval = g_new0 (gchar *, g_slist_length (list) + 1);
1784 for (; list; list = list->next, i++)
1785 retval [i] = node_get_complete_path (op, NODE (list->data));
1786
1787 return retval;
1788 }
1789
1790 /**
1791 * gda_server_operation_get_sequence_name:
1792 * @op: a #GdaServerOperation object
1793 * @path: a complete path to a sequence node (starting with "/")
1794 *
1795 * Returns: (transfer none): the name of the sequence at @path
1796 */
1797 const gchar *
gda_server_operation_get_sequence_name(GdaServerOperation * op,const gchar * path)1798 gda_server_operation_get_sequence_name (GdaServerOperation *op, const gchar *path)
1799 {
1800 Node *node;
1801
1802 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL);
1803 g_return_val_if_fail (op->priv, NULL);
1804
1805 node = node_find (op, path);
1806 if (!node || (node->type != GDA_SERVER_OPERATION_NODE_SEQUENCE))
1807 return NULL;
1808
1809 return node->d.seq.name;
1810 }
1811
1812 /**
1813 * gda_server_operation_get_sequence_size:
1814 * @op: a #GdaServerOperation object
1815 * @path: a complete path to a sequence node (starting with "/")
1816 *
1817 * Returns: the number of items in the sequence at @path, or 0 if @path is not a sequence node
1818 */
1819 guint
gda_server_operation_get_sequence_size(GdaServerOperation * op,const gchar * path)1820 gda_server_operation_get_sequence_size (GdaServerOperation *op, const gchar *path)
1821 {
1822 Node *node;
1823
1824 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), 0);
1825 g_return_val_if_fail (op->priv, 0);
1826
1827 node = node_find (op, path);
1828 if (!node || (node->type != GDA_SERVER_OPERATION_NODE_SEQUENCE))
1829 return 0;
1830
1831 return g_slist_length (node->d.seq.seq_items);
1832 }
1833
1834 /**
1835 * gda_server_operation_get_sequence_max_size:
1836 * @op: a #GdaServerOperation object
1837 * @path: a complete path to a sequence node (starting with "/")
1838 *
1839 * Returns: the maximum number of items in the sequence at @path, or 0 if @path is not a sequence node
1840 */
1841 guint
gda_server_operation_get_sequence_max_size(GdaServerOperation * op,const gchar * path)1842 gda_server_operation_get_sequence_max_size (GdaServerOperation *op, const gchar *path)
1843 {
1844 Node *node;
1845
1846 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), 0);
1847 g_return_val_if_fail (op->priv, 0);
1848
1849 node = node_find (op, path);
1850 if (!node || (node->type != GDA_SERVER_OPERATION_NODE_SEQUENCE))
1851 return 0;
1852
1853 return node->d.seq.max_items;
1854 }
1855
1856 /**
1857 * gda_server_operation_get_sequence_min_size:
1858 * @op: a #GdaServerOperation object
1859 * @path: a complete path to a sequence node (starting with "/")
1860 *
1861 * Returns: the minimum number of items in the sequence at @path, or 0 if @path is not a sequence node
1862 */
1863 guint
gda_server_operation_get_sequence_min_size(GdaServerOperation * op,const gchar * path)1864 gda_server_operation_get_sequence_min_size (GdaServerOperation *op, const gchar *path)
1865 {
1866 Node *node;
1867
1868 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), 0);
1869 g_return_val_if_fail (op->priv, 0);
1870
1871 node = node_find (op, path);
1872 if (!node || (node->type != GDA_SERVER_OPERATION_NODE_SEQUENCE))
1873 return 0;
1874
1875 return node->d.seq.min_items;
1876 }
1877
1878
1879 #ifdef GDA_DEBUG_NO
1880 static void
dump(GdaServerOperation * op)1881 dump (GdaServerOperation *op)
1882 {
1883 xmlNodePtr node;
1884 node = gda_server_operation_save_data_to_xml (op, NULL);
1885 if (node) {
1886 xmlDocPtr doc;
1887 xmlChar *buffer;
1888
1889 doc = xmlNewDoc ("1.0");
1890 xmlDocSetRootElement (doc, node);
1891 xmlIndentTreeOutput = 1;
1892 xmlKeepBlanksDefault (0);
1893 xmlDocDumpFormatMemory (doc, &buffer, NULL, 1);
1894 g_print ("%s\n", buffer);
1895 xmlFree (buffer);
1896 xmlFreeDoc (doc);
1897 }
1898 else
1899 g_warning ("Saving to XML failed!");
1900 }
1901 #endif
1902
1903 /**
1904 * gda_server_operation_add_item_to_sequence:
1905 * @op: a #GdaServerOperation object
1906 * @seq_path: the path to the sequence to which an item must be added (like "/SEQ_NAME" for instance)
1907 *
1908 * Returns: the index of the new entry in the sequence (like 5 for example if a 6th item has
1909 * been added to the sequence.
1910 */
1911 guint
gda_server_operation_add_item_to_sequence(GdaServerOperation * op,const gchar * seq_path)1912 gda_server_operation_add_item_to_sequence (GdaServerOperation *op, const gchar *seq_path)
1913 {
1914 Node *node;
1915
1916 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), 0);
1917 g_return_val_if_fail (op->priv, 0);
1918
1919 node = node_find (op, seq_path);
1920 if (!node || (node->type != GDA_SERVER_OPERATION_NODE_SEQUENCE))
1921 return 0;
1922
1923 if (g_slist_length (node->d.seq.seq_items) == node->d.seq.max_items)
1924 return 0;
1925
1926 sequence_add_item (op, node);
1927
1928 #ifdef GDA_DEBUG_NO
1929 dump (op);
1930 #endif
1931
1932 return g_slist_length (node->d.seq.seq_items);
1933 }
1934
1935 /**
1936 * gda_server_operation_del_item_from_sequence:
1937 * @op: a #GdaServerOperation object
1938 * @item_path: the path to the sequence's item to remove (like "/SEQ_NAME/5" for instance)
1939 *
1940 * Returns: TRUE if the specified node has been removed from the sequence
1941 */
1942 gboolean
gda_server_operation_del_item_from_sequence(GdaServerOperation * op,const gchar * item_path)1943 gda_server_operation_del_item_from_sequence (GdaServerOperation *op, const gchar *item_path)
1944 {
1945 Node *node, *item_node;
1946 gchar *seq_path, *ptr;
1947
1948 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE);
1949 g_return_val_if_fail (op->priv, FALSE);
1950
1951 seq_path = g_strdup (item_path);
1952 ptr = seq_path + strlen (seq_path) - 1;
1953 while ((ptr >= seq_path) &&
1954 (((*ptr >= '0') && (*ptr <= '9')) || (*ptr == '/'))) {
1955 *ptr = 0;
1956 ptr--;
1957 }
1958
1959 node = node_find (op, seq_path);
1960 if (!node ||
1961 (node->type != GDA_SERVER_OPERATION_NODE_SEQUENCE) ||
1962 (g_slist_length (node->d.seq.seq_items) == node->d.seq.min_items)) {
1963 g_free (seq_path);
1964 return FALSE;
1965 }
1966
1967 item_node = node_find (op, item_path);
1968 if (!item_node || (item_node->type != GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM)) {
1969 g_free (seq_path);
1970 return FALSE;
1971 }
1972
1973 clean_nodes_info_cache (op);
1974 #ifdef GDA_DEBUG_signal
1975 g_print (">> 'SEQUENCE_ITEM_REMOVE' from %s\n", __FUNCTION__);
1976 #endif
1977 g_signal_emit (G_OBJECT (op), gda_server_operation_signals [SEQUENCE_ITEM_REMOVE], 0,
1978 seq_path, g_slist_index (node->d.seq.seq_items, item_node));
1979 #ifdef GDA_DEBUG_signal
1980 g_print ("<< 'SEQUENCE_ITEM_REMOVE' from %s\n", __FUNCTION__);
1981 #endif
1982
1983 g_free (seq_path);
1984 node_destroy (op, item_node);
1985 node->d.seq.seq_items = g_slist_remove (node->d.seq.seq_items, item_node);
1986
1987 #ifdef GDA_DEBUG_NO
1988 dump (op);
1989 #endif
1990
1991 return FALSE;
1992 }
1993
1994 /**
1995 * gda_server_operation_get_value_at_path: (rename-to gda_server_operation_get_value_at)
1996 * @op: a #GdaServerOperation object
1997 * @path: a complete path to a node (starting with "/")
1998 *
1999 * Get the value for the node at the @path path
2000 *
2001 * Returns: (transfer none) (nullable): a constant #GValue if a value has been defined, or %NULL if the value is undefined or if the @path is not defined or @path does not hold any value.
2002 *
2003 * Since: 4.2.6
2004 *
2005 */
2006 const GValue *
gda_server_operation_get_value_at_path(GdaServerOperation * op,const gchar * path)2007 gda_server_operation_get_value_at_path (GdaServerOperation *op, const gchar *path)
2008 {
2009 const GValue *value = NULL;
2010 GdaServerOperationNode *node_info;
2011
2012 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL);
2013 g_return_val_if_fail (op->priv, NULL);
2014 g_return_val_if_fail (path && *path, NULL);
2015
2016 /* use path */
2017 node_info = gda_server_operation_get_node_info (op, path);
2018 if (node_info) {
2019 switch (node_info->type) {
2020 case GDA_SERVER_OPERATION_NODE_PARAM:
2021 value = gda_holder_get_value (node_info->param);
2022 break;
2023 case GDA_SERVER_OPERATION_NODE_PARAMLIST:
2024 case GDA_SERVER_OPERATION_NODE_DATA_MODEL:
2025 case GDA_SERVER_OPERATION_NODE_SEQUENCE:
2026 case GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM:
2027 case GDA_SERVER_OPERATION_NODE_DATA_MODEL_COLUMN:
2028 break;
2029 default:
2030 g_assert_not_reached ();
2031 }
2032 }
2033 else {
2034 /* specific syntax which does not yield to a GdaServerOperationNode */
2035 gchar *str;
2036 str = gda_server_operation_get_node_parent (op, path);
2037 if (str) {
2038 node_info = gda_server_operation_get_node_info (op, str);
2039 if (node_info && (node_info->type == GDA_SERVER_OPERATION_NODE_DATA_MODEL_COLUMN)) {
2040 gchar *extension, *ptr;
2041 gint row;
2042 extension = gda_server_operation_get_node_path_portion (op, path);
2043
2044 row = strtol (extension, &ptr, 10);
2045 if (ptr && *ptr)
2046 row = -1;
2047 if (row >= 0)
2048 value = gda_data_model_get_value_at (node_info->model,
2049 gda_column_get_position (node_info->column),
2050 row, NULL);
2051 g_free(extension);
2052 }
2053 g_free (str);
2054 }
2055 }
2056
2057 return value;
2058 }
2059
2060 /**
2061 * gda_server_operation_get_value_at: (rename-to gda_server_operation_get_value_at_format)
2062 * @op: a #GdaServerOperation object
2063 * @path_format: a complete path to a node (starting with "/")
2064 * @...: arguments to use with @path_format to make a complete path
2065 *
2066 * Get the value for the node at the path formed using @path_format and ... (the rules are the same as
2067 * for g_strdup_printf())
2068 *
2069 * Returns: (transfer none): a constant #GValue if a value has been defined, or %NULL if the value is undefined or
2070 * if the @path is not defined or @path does not hold any value.
2071 */
2072 const GValue *
gda_server_operation_get_value_at(GdaServerOperation * op,const gchar * path_format,...)2073 gda_server_operation_get_value_at (GdaServerOperation *op, const gchar *path_format, ...)
2074 {
2075 const GValue *value = NULL;
2076 gchar *path;
2077 va_list args;
2078
2079 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL);
2080 g_return_val_if_fail (op->priv, NULL);
2081
2082 /* build path */
2083 va_start (args, path_format);
2084 path = g_strdup_vprintf (path_format, args);
2085 va_end (args);
2086
2087 value = gda_server_operation_get_value_at_path (op, path);
2088 g_free (path);
2089
2090 return value;
2091 }
2092
2093 /**
2094 * gda_server_operation_get_sql_identifier_at: (skip)
2095 * @op: a #GdaServerOperation object
2096 * @cnc: (nullable): a #GdaConnection, or %NULL
2097 * @prov: (nullable): a #GdaServerProvider, or %NULL
2098 * @path_format: a complete path to a node (starting with "/")
2099 * @...: arguments to use with @path_format to make a complete path
2100 *
2101 * This method is similar to gda_server_operation_get_value_at(), but for SQL identifiers: a new string
2102 * is returned instead of a #GValue. Also the returned string is assumed to represents an SQL identifier
2103 * and will correctly be quoted to be used with @cnc, or @prov if @cnc is %NULL (a generic quoting rule
2104 * will be applied if both are %NULL).
2105 *
2106 * Returns: (transfer full): a new string, or %NULL if the value is undefined or
2107 * if the @path is not defined or @path does not hold any value, or if the value held is not a string
2108 * (in that last case a warning is shown).
2109 *
2110 * Since: 4.0.3
2111 */
2112 gchar *
gda_server_operation_get_sql_identifier_at(GdaServerOperation * op,GdaConnection * cnc,GdaServerProvider * prov,const gchar * path_format,...)2113 gda_server_operation_get_sql_identifier_at (GdaServerOperation *op, GdaConnection *cnc, GdaServerProvider *prov,
2114 const gchar *path_format, ...)
2115 {
2116 gchar *path, *ret;
2117 va_list args;
2118
2119 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL);
2120
2121 /* build path */
2122 va_start (args, path_format);
2123 path = g_strdup_vprintf (path_format, args);
2124 va_end (args);
2125
2126 ret = gda_server_operation_get_sql_identifier_at_path (op, cnc, prov, path);
2127 g_free (path);
2128
2129 return ret;
2130 }
2131
2132 /**
2133 * gda_server_operation_get_sql_identifier_at_path: (rename-to gda_server_operation_get_sql_identifier_at)
2134 * @op: a #GdaServerOperation object
2135 * @cnc: (nullable): a #GdaConnection, or %NULL
2136 * @prov: (nullable): a #GdaServerProvider, or %NULL
2137 * @path: a complete path to a node (starting with "/")
2138 *
2139 * This method is similar to gda_server_operation_get_value_at(), but for SQL identifiers: a new string
2140 * is returned instead of a #GValue. Also the returned string is assumed to represents an SQL identifier
2141 * and will correctly be quoted to be used with @cnc, or @prov if @cnc is %NULL (a generic quoting rule
2142 * will be applied if both are %NULL).
2143 *
2144 * Returns: (transfer full): a new string, or %NULL if the value is undefined or
2145 * if the @path is not defined or @path does not hold any value, or if the value held is not a string
2146 * (in that last case a warning is shown).
2147 *
2148 * Since: 4.2.6
2149 *
2150 */
2151 gchar *
gda_server_operation_get_sql_identifier_at_path(GdaServerOperation * op,GdaConnection * cnc,GdaServerProvider * prov,const gchar * path)2152 gda_server_operation_get_sql_identifier_at_path (GdaServerOperation *op, GdaConnection *cnc, GdaServerProvider *prov,
2153 const gchar *path)
2154 {
2155 const GValue *value = NULL;
2156 GdaConnectionOptions cncoptions = 0;
2157
2158 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), NULL);
2159
2160 value = gda_server_operation_get_value_at_path (op, path);
2161
2162 if (!value || (G_VALUE_TYPE (value) == GDA_TYPE_NULL))
2163 return NULL;
2164 g_return_val_if_fail (G_VALUE_TYPE (value) == G_TYPE_STRING, NULL);
2165
2166 if (cnc)
2167 g_object_get (G_OBJECT (cnc), "options", &cncoptions, NULL);
2168 return gda_sql_identifier_quote (g_value_get_string (value), cnc, prov, FALSE,
2169 cncoptions & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE);
2170 }
2171
2172 /**
2173 * gda_server_operation_set_value_at_path: (rename-to gda_server_operation_set_value_at)
2174 * @op: a #GdaServerOperation object
2175 * @value: (nullable): a string
2176 * @path: a complete path to a node (starting with "/")
2177 * @error: a place to store errors or %NULL
2178 *
2179 * Set the value for the node at the path formed using @path_format and the ... ellipse (the rules are the same as
2180 * for g_strdup_printf()).
2181 *
2182 * Note that trying to set a value for a path which is not used by the current
2183 * provider, such as "/TABLE_OPTIONS_P/TABLE_ENGINE" for a PostgreSQL connection (this option is only supported for MySQL),
2184 * will <emphasis>not</emphasis> generate
2185 * any error; this allows one to give values to a superset of the parameters and thus use the same code for several providers.
2186 *
2187 * Here are the possible formats of @path_format:
2188 * <itemizedlist>
2189 * <listitem><para>If the path corresponds to a #GdaHolder, then the parameter is set to <![CDATA["@value"]]></para></listitem>
2190 * <listitem><para>If the path corresponds to a sequence item like for example "/SEQUENCE_NAME/5/NAME" for
2191 * the "NAME" value of the 6th item of the "SEQUENCE_NAME" sequence then:
2192 * <itemizedlist>
2193 * <listitem><para>if the sequence already has 6 or more items, then the value is just set to the corresponding
2194 * value in the 6th item of the sequence</para></listitem>
2195 * <listitem><para>if the sequence has less then 6 items, then items are added up to the 6th one before setting
2196 * the value to the corresponding in the 6th item of the sequence</para></listitem>
2197 * </itemizedlist>
2198 * </para></listitem>
2199 * <listitem><para>If the path corresponds to a #GdaDataModel, like for example "/ARRAY/@@COLUMN/5" for the value at the
2200 * 6th row of the "COLUMN" column of the "ARRAY" data model, then:
2201 * <itemizedlist>
2202 * <listitem><para>if the data model already contains 6 or more rows, then the value is just set</para></listitem>
2203 * <listitem><para>if the data model has less than 6 rows, then rows are added up to the 6th one before setting
2204 * the value</para></listitem>
2205 * </itemizedlist>
2206 * </para></listitem>
2207 * </itemizedlist>
2208 *
2209 * Returns: %TRUE if no error occurred
2210 *
2211 * Since: 4.2.6
2212 *
2213 */
2214 gboolean
gda_server_operation_set_value_at_path(GdaServerOperation * op,const gchar * value,const gchar * path,GError ** error)2215 gda_server_operation_set_value_at_path (GdaServerOperation *op, const gchar *value,
2216 const gchar *path, GError **error)
2217 {
2218 Node *opnode;
2219 gchar *extension = NULL;
2220 gchar *colname = NULL;
2221 gboolean allok = TRUE;
2222
2223 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE);
2224 g_return_val_if_fail (op->priv, FALSE);
2225
2226 /* set the value */
2227 opnode = node_find_or_create (op, path);
2228 if (!opnode) {
2229 /* try to see if the "parent" is a real node */
2230 gchar *str;
2231
2232 str = gda_server_operation_get_node_parent (op, path);
2233 if (str) {
2234 opnode = node_find (op, str);
2235 if (opnode) {
2236 if (opnode->type != GDA_SERVER_OPERATION_NODE_PARAMLIST)
2237 opnode = NULL; /* ignore opnode */
2238 }
2239 else {
2240 gchar *str2;
2241
2242 str2 = gda_server_operation_get_node_parent (op, str);
2243 opnode = node_find (op, str2);
2244 if (opnode) {
2245 if (opnode->type != GDA_SERVER_OPERATION_NODE_DATA_MODEL)
2246 opnode = NULL; /* ignore opnode */
2247 else
2248 colname = gda_server_operation_get_node_path_portion (op, str);
2249 }
2250 g_free (str2);
2251 }
2252 g_free (str);
2253 }
2254 if (opnode)
2255 extension = gda_server_operation_get_node_path_portion (op, path);
2256 }
2257
2258 if (opnode) {
2259 switch (opnode->type) {
2260 case GDA_SERVER_OPERATION_NODE_PARAMLIST:
2261 if (!extension) {
2262 g_set_error (error, GDA_SERVER_OPERATION_ERROR,
2263 GDA_SERVER_OPERATION_XML_ERROR,
2264 "%s",
2265 _("Parameterlist values can only be set for individual parameters within it"));
2266 allok = FALSE;
2267 }
2268 else {
2269 GdaHolder *param;
2270 param = gda_set_get_holder (opnode->d.plist, extension);
2271 if (param) {
2272 GValue *v;
2273 if (value)
2274 v = gda_value_new_from_string (value,
2275 gda_holder_get_g_type (param));
2276 else
2277 v = gda_value_new_null ();
2278 if (!gda_holder_take_value (param, v, error))
2279 allok = FALSE;
2280 }
2281 }
2282 break;
2283 case GDA_SERVER_OPERATION_NODE_DATA_MODEL: {
2284 GdaColumn *column = NULL;
2285
2286 if (colname && (*colname == '@')) {
2287 gint i, nbcols;
2288
2289 nbcols = gda_data_model_get_n_columns (opnode->d.model);
2290 for (i = 0; (i<nbcols) && !column; i++) {
2291 gchar *colid = NULL;
2292 column = gda_data_model_describe_column (opnode->d.model, i);
2293 g_object_get (G_OBJECT (column), "id", &colid, NULL);
2294 if (!colid || strcmp (colid, colname +1))
2295 column = NULL;
2296 g_free(colid);
2297 }
2298 if (column) {
2299 gchar *ptr;
2300 gint row;
2301 row = strtol (extension, &ptr, 10);
2302 if (ptr && *ptr)
2303 row = -1;
2304 if (row >= 0) {
2305 gint i = gda_data_model_get_n_rows (opnode->d.model);
2306
2307 if (i <= row) {
2308 for (; allok && (i <= row); i++)
2309 if (gda_data_model_append_row (opnode->d.model, error) < 0)
2310 allok = FALSE;
2311 }
2312
2313 if (allok) {
2314 GValue *gvalue;
2315 if (value)
2316 gvalue = gda_value_new_from_string (value,
2317 gda_column_get_g_type (column));
2318 else
2319 gvalue = gda_value_new_null ();
2320 allok = gda_data_model_set_value_at (opnode->d.model,
2321 gda_column_get_position (column),
2322 row, gvalue, error);
2323 gda_value_free (gvalue);
2324 }
2325 }
2326 }
2327 }
2328 break;
2329 }
2330 case GDA_SERVER_OPERATION_NODE_PARAM: {
2331 GValue *v;
2332 if (value)
2333 v = gda_value_new_from_string (value,
2334 gda_holder_get_g_type (opnode->d.param));
2335 else
2336 v = gda_value_new_null ();
2337 if (!gda_holder_take_value (opnode->d.param, v, error))
2338 allok = FALSE;
2339 break;
2340 }
2341 case GDA_SERVER_OPERATION_NODE_SEQUENCE:
2342 break;
2343 case GDA_SERVER_OPERATION_NODE_SEQUENCE_ITEM:
2344 break;
2345 default:
2346 g_assert_not_reached ();
2347 }
2348 }
2349
2350 g_free (extension);
2351 g_free (colname);
2352 return allok;
2353 }
2354
2355 /**
2356 * gda_server_operation_set_value_at: (skip)
2357 * @op: a #GdaServerOperation object
2358 * @value: (nullable): a string
2359 * @error: a place to store errors or %NULL
2360 * @path_format: a complete path to a node (starting with "/")
2361 * @...: arguments to use with @path_format to make a complete path
2362 *
2363 * Set the value for the node at the path formed using @path_format and the ... ellipse (the rules are the same as
2364 * for g_strdup_printf()).
2365 *
2366 * Note that trying to set a value for a path which is not used by the current
2367 * provider, such as "/TABLE_OPTIONS_P/TABLE_ENGINE" for a PostgreSQL connection (this option is only supported for MySQL),
2368 * will <emphasis>not</emphasis> generate
2369 * any error; this allows one to give values to a superset of the parameters and thus use the same code for several providers.
2370 *
2371 * Here are the possible formats of @path_format:
2372 * <itemizedlist>
2373 * <listitem><para>If the path corresponds to a #GdaHolder, then the parameter is set to <![CDATA["@value"]]></para></listitem>
2374 * <listitem><para>If the path corresponds to a sequence item like for example "/SEQUENCE_NAME/5/NAME" for
2375 * the "NAME" value of the 6th item of the "SEQUENCE_NAME" sequence then:
2376 * <itemizedlist>
2377 * <listitem><para>if the sequence already has 6 or more items, then the value is just set to the corresponding
2378 * value in the 6th item of the sequence</para></listitem>
2379 * <listitem><para>if the sequence has less then 6 items, then items are added up to the 6th one before setting
2380 * the value to the corresponding in the 6th item of the sequence</para></listitem>
2381 * </itemizedlist>
2382 * </para></listitem>
2383 * <listitem><para>If the path corresponds to a #GdaDataModel, like for example "/ARRAY/@@COLUMN/5" for the value at the
2384 * 6th row of the "COLUMN" column of the "ARRAY" data model, then:
2385 * <itemizedlist>
2386 * <listitem><para>if the data model already contains 6 or more rows, then the value is just set</para></listitem>
2387 * <listitem><para>if the data model has less than 6 rows, then rows are added up to the 6th one before setting
2388 * the value</para></listitem>
2389 * </itemizedlist>
2390 * </para></listitem>
2391 * </itemizedlist>
2392 *
2393 * Returns: %TRUE if no error occurred
2394 */
2395 gboolean
gda_server_operation_set_value_at(GdaServerOperation * op,const gchar * value,GError ** error,const gchar * path_format,...)2396 gda_server_operation_set_value_at (GdaServerOperation *op, const gchar *value, GError **error,
2397 const gchar *path_format, ...)
2398 {
2399 gchar *path;
2400 va_list args;
2401 gboolean ret;
2402
2403 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE);
2404 g_return_val_if_fail (op->priv, FALSE);
2405
2406 /* build path */
2407 va_start (args, path_format);
2408 path = g_strdup_vprintf (path_format, args);
2409 va_end (args);
2410
2411 ret = gda_server_operation_set_value_at_path (op, value, path, error);
2412 g_free (path);
2413
2414 return ret;
2415 }
2416
2417 /**
2418 * gda_server_operation_is_valid:
2419 * @op: a #GdaServerOperation widget
2420 * @xml_file: (nullable): an XML specification file (see gda_server_operation_new()) or %NULL
2421 * @error: a place to store an error, or %NULL
2422 *
2423 * Tells if all the required values in @op have been defined.
2424 *
2425 * if @xml_file is not %NULL, the validity of @op is tested against that specification,
2426 * and not against the current @op's specification.
2427 *
2428 * Returns: %TRUE if @op is valid
2429 */
2430 gboolean
gda_server_operation_is_valid(GdaServerOperation * op,const gchar * xml_file,GError ** error)2431 gda_server_operation_is_valid (GdaServerOperation *op, const gchar *xml_file, GError **error)
2432 {
2433 gboolean valid = TRUE;
2434 GSList *list;
2435
2436 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE);
2437 g_return_val_if_fail (op->priv, FALSE);
2438
2439 if (!xml_file) {
2440 /* basic validity test */
2441 for (list = op->priv->allnodes; list; list = list->next) {
2442 Node *node;
2443
2444 node = NODE (list->data);
2445 if (node->status == GDA_SERVER_OPERATION_STATUS_REQUIRED) {
2446 if (node->type == GDA_SERVER_OPERATION_NODE_PARAM) {
2447 const GValue *value;
2448 gchar *path;
2449
2450 path = node_get_complete_path (op, node);
2451 value = gda_server_operation_get_value_at (op, path);
2452 if (!value) {
2453 valid = FALSE;
2454 g_set_error (error,
2455 GDA_SERVER_OPERATION_ERROR,
2456 GDA_SERVER_OPERATION_INCORRECT_VALUE_ERROR,
2457 _("Missing required value for '%s'"), path);
2458 break;
2459 }
2460 g_free (path);
2461 }
2462 else if (node->type == GDA_SERVER_OPERATION_NODE_PARAMLIST) {
2463 valid = gda_set_is_valid (node->d.plist, error);
2464 if (!valid)
2465 break;
2466 }
2467 }
2468 }
2469 }
2470 else {
2471 /* use @xml_file */
2472 xmlNodePtr save;
2473
2474 save = gda_server_operation_save_data_to_xml (op, error);
2475 if (save) {
2476 GdaServerOperation *op2;
2477 op2 = gda_server_operation_new (op->priv->op_type, xml_file);
2478 if (gda_server_operation_load_data_from_xml (op2, save, error))
2479 valid = gda_server_operation_is_valid (op2, NULL, error);
2480 else
2481 valid = FALSE;
2482 xmlFreeNode (save);
2483 g_object_unref (op2);
2484 }
2485 else
2486 valid = FALSE;
2487 }
2488
2489 return valid;
2490 }
2491
2492 /**
2493 * gda_server_operation_prepare_create_database:
2494 * @provider: the database provider to use
2495 * @db_name: (nullable): the name of the database to create, or %NULL
2496 * @error: a place to store errors, or %NULL
2497 *
2498 * Creates a new #GdaServerOperation object which contains the specifications required
2499 * to create a database. Once these specifications provided, use
2500 * gda_server_operation_perform_create_database() to perform the database creation.
2501 *
2502 * If @db_name is left %NULL, then the name of the database to create will have to be set in the
2503 * returned #GdaServerOperation using gda_server_operation_set_value_at().
2504 *
2505 * Returns: (transfer full) (nullable): new #GdaServerOperation object, or %NULL if the provider does not support database
2506 * creation
2507 *
2508 * Since: 4.2.3
2509 */
2510 GdaServerOperation *
gda_server_operation_prepare_create_database(const gchar * provider,const gchar * db_name,GError ** error)2511 gda_server_operation_prepare_create_database (const gchar *provider, const gchar *db_name, GError **error)
2512 {
2513 GdaServerProvider *prov;
2514
2515 g_return_val_if_fail (provider && *provider, NULL);
2516
2517 prov = gda_config_get_provider (provider, error);
2518 if (prov) {
2519 GdaServerOperation *op;
2520 op = gda_server_provider_create_operation (prov, NULL, GDA_SERVER_OPERATION_CREATE_DB,
2521 NULL, error);
2522 if (op) {
2523 g_object_set_data_full (G_OBJECT (op), "_gda_provider_obj", g_object_ref (prov), g_object_unref);
2524 if (db_name)
2525 gda_server_operation_set_value_at (op, db_name, NULL, "/DB_DEF_P/DB_NAME");
2526 }
2527 return op;
2528 }
2529 else
2530 return NULL;
2531 }
2532
2533 /**
2534 * gda_server_operation_perform_create_database:
2535 * @provider: (nullable): the database provider to use, or %NULL if @op has been created using gda_server_operation_prepare_create_database()
2536 * @op: a #GdaServerOperation object obtained using gda_server_operation_prepare_create_database()
2537 * @error: a place to store en error, or %NULL
2538 *
2539 * Creates a new database using the specifications in @op. @op can be obtained using
2540 * gda_server_provider_create_operation(), or gda_server_operation_prepare_create_database().
2541 *
2542 * Returns: TRUE if no error occurred and the database has been created, FALSE otherwise
2543 *
2544 * Since: 4.2.3
2545 */
2546 gboolean
gda_server_operation_perform_create_database(GdaServerOperation * op,const gchar * provider,GError ** error)2547 gda_server_operation_perform_create_database (GdaServerOperation *op, const gchar *provider, GError **error)
2548 {
2549 GdaServerProvider *prov;
2550
2551 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE);
2552 if (provider)
2553 prov = gda_config_get_provider (provider, error);
2554 else
2555 prov = g_object_get_data (G_OBJECT (op), "_gda_provider_obj");
2556 if (prov)
2557 return gda_server_provider_perform_operation (prov, NULL, op, error);
2558 else {
2559 g_warning ("Could not find operation's associated provider, "
2560 "did you use gda_server_operation_prepare_create_database() ?");
2561 return FALSE;
2562 }
2563 }
2564
2565 /**
2566 * gda_server_operation_prepare_drop_database:
2567 * @provider: the database provider to use
2568 * @db_name: (nullable): the name of the database to drop, or %NULL
2569 * @error: a place to store errors, or %NULL
2570 *
2571 * Creates a new #GdaServerOperation object which contains the specifications required
2572 * to drop a database. Once these specifications provided, use
2573 * gda_server_operation_perform_drop_database() to perform the database creation.
2574 *
2575 * If @db_name is left %NULL, then the name of the database to drop will have to be set in the
2576 * returned #GdaServerOperation using gda_server_operation_set_value_at().
2577 *
2578 * Returns: (transfer full) (nullable): new #GdaServerOperation object, or %NULL if the provider does not support database
2579 * destruction
2580 *
2581 * Since: 4.2.3
2582 */
2583 GdaServerOperation *
gda_server_operation_prepare_drop_database(const gchar * provider,const gchar * db_name,GError ** error)2584 gda_server_operation_prepare_drop_database (const gchar *provider, const gchar *db_name, GError **error)
2585 {
2586 GdaServerProvider *prov;
2587
2588 g_return_val_if_fail (provider && *provider, NULL);
2589
2590 prov = gda_config_get_provider (provider, error);
2591 if (prov) {
2592 GdaServerOperation *op;
2593 op = gda_server_provider_create_operation (prov, NULL, GDA_SERVER_OPERATION_DROP_DB,
2594 NULL, error);
2595 if (op) {
2596 g_object_set_data_full (G_OBJECT (op), "_gda_provider_obj", g_object_ref (prov), g_object_unref);
2597 if (db_name)
2598 gda_server_operation_set_value_at (op, db_name, NULL, "/DB_DESC_P/DB_NAME");
2599 }
2600 return op;
2601 }
2602 else
2603 return NULL;
2604 }
2605
2606 /**
2607 * gda_server_operation_perform_drop_database:
2608 * @provider: (nullable): the database provider to use, or %NULL if @op has been created using gda_server_operation_prepare_drop_database()
2609 * @op: a #GdaServerOperation object obtained using gda_server_operation_prepare_drop_database()
2610 * @error: a place to store en error, or %NULL
2611 *
2612 * Destroys an existing database using the specifications in @op. @op can be obtained using
2613 * gda_server_provider_create_operation(), or gda_server_operation_prepare_drop_database().
2614 *
2615 * Returns: TRUE if no error occurred and the database has been destroyed
2616 *
2617 * Since: 4.2.3
2618 */
2619 gboolean
gda_server_operation_perform_drop_database(GdaServerOperation * op,const gchar * provider,GError ** error)2620 gda_server_operation_perform_drop_database (GdaServerOperation *op, const gchar *provider, GError **error)
2621 {
2622 GdaServerProvider *prov;
2623
2624 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE);
2625 g_return_val_if_fail (gda_server_operation_get_op_type (op) == GDA_SERVER_OPERATION_DROP_DB, FALSE);
2626 if (provider)
2627 prov = gda_config_get_provider (provider, error);
2628 else
2629 prov = g_object_get_data (G_OBJECT (op), "_gda_provider_obj");
2630 if (prov)
2631 return gda_server_provider_perform_operation (prov, NULL, op, error);
2632 else {
2633 g_warning ("Could not find operation's associated provider, "
2634 "did you use gda_server_operation_prepare_drop_database() ?");
2635 return FALSE;
2636 }
2637 }
2638
2639 /**
2640 * gda_server_operation_prepare_create_table:
2641 * @cnc: an opened connection
2642 * @table_name: name of the table to create
2643 * @error: a place to store errors, or %NULL
2644 * @...: group of three arguments for column's name, column's #GType
2645 * and a #GdaServerOperationCreateTableFlag flag, finished with %NULL
2646 *
2647 * Add more arguments if the flag needs them:
2648 *
2649 * GDA_SERVER_OPERATION_CREATE_TABLE_FKEY_FLAG:
2650 * <itemizedlist>
2651 * <listitem><para>string with the table's name referenced</para></listitem>
2652 * <listitem><para>an integer with the number pairs "local_field", "referenced_field"
2653 * used in the reference</para></listitem>
2654 * <listitem><para>Pairs of "local_field", "referenced_field" to use, must match
2655 * the number specified above.</para></listitem>
2656 * <listitem><para>a string with the action for ON DELETE; can be: "RESTRICT", "CASCADE",
2657 * "NO ACTION", "SET NULL" and "SET DEFAULT". Example: "ON UPDATE CASCADE".</para></listitem>
2658 * <listitem><para>a string with the action for ON UPDATE (see above).</para></listitem>
2659 * </itemizedlist>
2660 *
2661 * Create a #GdaServerOperation object using an opened connection, taking three
2662 * arguments, a column's name the column's GType and #GdaServerOperationCreateTableFlag
2663 * flag, you need to finish the list using %NULL.
2664 *
2665 * You'll be able to modify the #GdaServerOperation object to add custom options * to the operation. When finished call #gda_server_operation_perform_create_table
2666 * or #gda_server_provider_perform_operation
2667 * in order to execute the operation.
2668 *
2669 * Returns: (transfer full) (nullable): a #GdaServerOperation if no errors; NULL and set @error otherwise
2670 *
2671 * Since: 4.2.3
2672 */
2673 G_GNUC_NULL_TERMINATED
2674 GdaServerOperation*
gda_server_operation_prepare_create_table(GdaConnection * cnc,const gchar * table_name,GError ** error,...)2675 gda_server_operation_prepare_create_table (GdaConnection *cnc, const gchar *table_name, GError **error, ...)
2676 {
2677 GdaServerOperation *op;
2678 GdaServerProvider *server;
2679
2680 g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE);
2681
2682 server = gda_connection_get_provider (cnc);
2683
2684 if (!table_name) {
2685 g_set_error (error, GDA_SERVER_OPERATION_ERROR, GDA_SERVER_OPERATION_OBJECT_NAME_ERROR,
2686 "%s", _("Unspecified table name"));
2687 return NULL;
2688 }
2689
2690 if (gda_server_provider_supports_operation (server, cnc, GDA_SERVER_OPERATION_CREATE_TABLE, NULL)) {
2691 va_list args;
2692 gchar *arg;
2693 GType type;
2694 gchar *dbms_type;
2695 GdaServerOperationCreateTableFlag flag;
2696 gint i;
2697 gint refs;
2698
2699 op = gda_server_provider_create_operation (server, cnc,
2700 GDA_SERVER_OPERATION_CREATE_TABLE, NULL, error);
2701 if (!GDA_IS_SERVER_OPERATION(op))
2702 return NULL;
2703 if(!gda_server_operation_set_value_at (op, table_name, error, "/TABLE_DEF_P/TABLE_NAME")) {
2704 g_object_unref (op);
2705 return NULL;
2706 }
2707
2708 va_start (args, error);
2709 type = 0;
2710 arg = NULL;
2711 i = 0;
2712 refs = -1;
2713
2714 while ((arg = va_arg (args, gchar*))) {
2715 /* First argument for Column's name */
2716 if(!gda_server_operation_set_value_at (op, arg, error, "/FIELDS_A/@COLUMN_NAME/%d", i)){
2717 g_object_unref (op);
2718 va_end (args);
2719 return NULL;
2720 }
2721
2722 /* Second to Define column's type */
2723 type = va_arg (args, GType);
2724 if (type == 0) {
2725 g_set_error (error, GDA_SERVER_OPERATION_ERROR, GDA_SERVER_OPERATION_INCORRECT_VALUE_ERROR,
2726 "%s", _("Invalid type"));
2727 g_object_unref (op);
2728 va_end (args);
2729 return NULL;
2730 }
2731 dbms_type = (gchar *) gda_server_provider_get_default_dbms_type (server,
2732 cnc, type);
2733 if (!gda_server_operation_set_value_at (op, dbms_type, error, "/FIELDS_A/@COLUMN_TYPE/%d", i)){
2734 g_object_unref (op);
2735 va_end (args);
2736 return NULL;
2737 }
2738
2739 /* Third for column's flags */
2740 flag = va_arg (args, GdaServerOperationCreateTableFlag);
2741 if (flag & GDA_SERVER_OPERATION_CREATE_TABLE_PKEY_FLAG)
2742 if(!gda_server_operation_set_value_at (op, "TRUE", error, "/FIELDS_A/@COLUMN_PKEY/%d", i)){
2743 g_object_unref (op);
2744 va_end (args);
2745 return NULL;
2746 }
2747 if (flag & GDA_SERVER_OPERATION_CREATE_TABLE_NOT_NULL_FLAG)
2748 if(!gda_server_operation_set_value_at (op, "TRUE", error, "/FIELDS_A/@COLUMN_NNUL/%d", i)){
2749 g_object_unref (op);
2750 va_end (args);
2751 return NULL;
2752 }
2753 if (flag & GDA_SERVER_OPERATION_CREATE_TABLE_AUTOINC_FLAG)
2754 if (!gda_server_operation_set_value_at (op, "TRUE", error, "/FIELDS_A/@COLUMN_AUTOINC/%d", i)){
2755 g_object_unref (op);
2756 va_end (args);
2757 return NULL;
2758 }
2759 if (flag & GDA_SERVER_OPERATION_CREATE_TABLE_UNIQUE_FLAG)
2760 if(!gda_server_operation_set_value_at (op, "TRUE", error, "/FIELDS_A/@COLUMN_UNIQUE/%d", i)){
2761 g_object_unref (op);
2762 va_end (args);
2763 return NULL;
2764 }
2765 if (flag & GDA_SERVER_OPERATION_CREATE_TABLE_FKEY_FLAG) {
2766 gint j;
2767 gint fields;
2768 gchar *fkey_table;
2769 gchar *fkey_ondelete;
2770 gchar *fkey_onupdate;
2771
2772 refs++;
2773
2774 fkey_table = va_arg (args, gchar*);
2775 if (!gda_server_operation_set_value_at (op, fkey_table, error,
2776 "/FKEY_S/%d/FKEY_REF_TABLE", refs)){
2777 g_object_unref (op);
2778 va_end (args);
2779 return NULL;
2780 }
2781
2782 fields = va_arg (args, gint);
2783
2784 for (j = 0; j < fields; j++) {
2785 gchar *field, *rfield;
2786
2787 field = va_arg (args, gchar*);
2788 if(!gda_server_operation_set_value_at (op, field, error,
2789 "/FKEY_S/%d/FKEY_FIELDS_A/@FK_FIELD/%d", refs, j)){
2790 g_object_unref (op);
2791 va_end (args);
2792 return NULL;
2793 }
2794
2795 rfield = va_arg (args, gchar*);
2796 if(!gda_server_operation_set_value_at (op, rfield, error,
2797 "/FKEY_S/%d/FKEY_FIELDS_A/@FK_REF_PK_FIELD/%d", refs, j)){
2798 g_object_unref (op);
2799 va_end (args);
2800 return NULL;
2801 }
2802 }
2803
2804 fkey_ondelete = va_arg (args, gchar*);
2805 if (!gda_server_operation_set_value_at (op, fkey_ondelete, error,
2806 "/FKEY_S/%d/FKEY_ONDELETE", refs)){
2807 g_object_unref (op);
2808 va_end (args);
2809 return NULL;
2810 }
2811 fkey_onupdate = va_arg (args, gchar*);
2812 if(!gda_server_operation_set_value_at (op, fkey_onupdate, error,
2813 "/FKEY_S/%d/FKEY_ONUPDATE", refs)){
2814 g_object_unref (op);
2815 va_end (args);
2816 return NULL;
2817 }
2818 }
2819
2820 i++;
2821 }
2822
2823 va_end (args);
2824
2825 g_object_set_data_full (G_OBJECT (op), "_gda_connection", g_object_ref (cnc), g_object_unref);
2826
2827 return op;
2828 }
2829 else {
2830 g_set_error (error, GDA_SERVER_OPERATION_ERROR, GDA_SERVER_OPERATION_OBJECT_NAME_ERROR,
2831 "%s", _("CREATE TABLE operation is not supported by the database server"));
2832 return NULL;
2833 }
2834 }
2835
2836
2837 /**
2838 * gda_server_operation_perform_create_table:
2839 * @op: a valid #GdaServerOperation
2840 * @error: a place to store errors, or %NULL
2841 *
2842 * Performs a prepared #GdaServerOperation to create a table. This could perform
2843 * an operation created by #gda_server_operation_prepare_create_table or any other using the
2844 * the #GdaServerOperation API.
2845 *
2846 * Returns: TRUE if the table was created; FALSE and set @error otherwise
2847 *
2848 * Since: 4.2.3
2849 */
2850 gboolean
gda_server_operation_perform_create_table(GdaServerOperation * op,GError ** error)2851 gda_server_operation_perform_create_table (GdaServerOperation *op, GError **error)
2852 {
2853 GdaConnection *cnc;
2854
2855 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE);
2856 g_return_val_if_fail (gda_server_operation_get_op_type (op) == GDA_SERVER_OPERATION_CREATE_TABLE, FALSE);
2857
2858 cnc = g_object_get_data (G_OBJECT (op), "_gda_connection");
2859 if (cnc)
2860 return gda_server_provider_perform_operation (gda_connection_get_provider (cnc), cnc, op, error);
2861 else {
2862 g_warning ("Could not find operation's associated connection, "
2863 "did you use gda_connection_prepare_create_table() ?");
2864 return FALSE;
2865 }
2866 }
2867
2868 /**
2869 * gda_server_operation_prepare_drop_table:
2870 * @cnc: an opened connection
2871 * @table_name: name of the table to drop
2872 * @error: a place to store errors, or %NULL
2873 *
2874 * This is just a convenient function to create a #GdaServerOperation to drop a
2875 * table in an opened connection.
2876 *
2877 * Returns: (transfer full) (nullable): a new #GdaServerOperation or %NULL if couldn't create the opereration.
2878 *
2879 * Since: 4.2.3
2880 */
2881 GdaServerOperation*
gda_server_operation_prepare_drop_table(GdaConnection * cnc,const gchar * table_name,GError ** error)2882 gda_server_operation_prepare_drop_table (GdaConnection *cnc, const gchar *table_name, GError **error)
2883 {
2884 GdaServerOperation *op;
2885 GdaServerProvider *server;
2886
2887 server = gda_connection_get_provider (cnc);
2888
2889 op = gda_server_provider_create_operation (server, cnc,
2890 GDA_SERVER_OPERATION_DROP_TABLE, NULL, error);
2891
2892 if (GDA_IS_SERVER_OPERATION (op)) {
2893 g_return_val_if_fail (table_name != NULL
2894 || GDA_IS_CONNECTION (cnc)
2895 || !gda_connection_is_opened (cnc), NULL);
2896
2897 if (gda_server_operation_set_value_at (op, table_name,
2898 error, "/TABLE_DESC_P/TABLE_NAME")) {
2899 g_object_set_data_full (G_OBJECT (op), "_gda_connection", g_object_ref (cnc), g_object_unref);
2900 return op;
2901 }
2902 else
2903 return NULL;
2904 }
2905 else
2906 return NULL;
2907 }
2908
2909
2910 /**
2911 * gda_server_operation_perform_drop_table:
2912 * @op: a #GdaServerOperation object
2913 * @error: a place to store errors, or %NULL
2914 *
2915 * This is just a convenient function to perform a drop a table operation.
2916 *
2917 * Returns: TRUE if the table was dropped
2918 *
2919 * Since: 4.2.3
2920 */
2921 gboolean
gda_server_operation_perform_drop_table(GdaServerOperation * op,GError ** error)2922 gda_server_operation_perform_drop_table (GdaServerOperation *op, GError **error)
2923 {
2924 GdaConnection *cnc;
2925
2926 g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE);
2927 g_return_val_if_fail (gda_server_operation_get_op_type (op) == GDA_SERVER_OPERATION_DROP_TABLE, FALSE);
2928
2929 cnc = g_object_get_data (G_OBJECT (op), "_gda_connection");
2930 if (cnc)
2931 return gda_server_provider_perform_operation (gda_connection_get_provider (cnc), cnc, op, error);
2932 else {
2933 g_warning ("Could not find operation's associated connection, "
2934 "did you use gda_server_operation_prepare_drop_table() ?");
2935 return FALSE;
2936 }
2937 }
2938