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 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 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 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 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 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 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 * 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 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 * 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 * 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 * 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 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 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 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 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 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 * 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 * 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 * 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 * 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 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 * 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 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 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 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 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** 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 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 * 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 * 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 ** 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 * 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 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 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 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 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 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 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 * 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 * 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 * 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 * 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 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 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 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 * 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 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 * 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 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* 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 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* 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 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