1 /*
2 * Copyright (C) 2001 - 2003 Rodrigo Moya <rodrigo@gnome-db.org>
3 * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier <gonzalo@gnome-db.org>
4 * Copyright (C) 2003 - 2004 Laurent Sansonetti <lrz@gnome.org>
5 * Copyright (C) 2003 Paisa Seeluangsawat <paisa@users.sf.net>
6 * Copyright (C) 2004 Caolan McNamara <caolanm@redhat.com>
7 * Copyright (C) 2004 Jürg Billeter <j@bitron.ch>
8 * Copyright (C) 2004 - 2011 Murray Cumming <murrayc@murrayc.com>
9 * Copyright (C) 2005 - 2013 Vivien Malerba <malerba@gnome-db.org>
10 * Copyright (C) 2007 - 2009 Armin Burgmeier <armin@openismus.com>
11 * Copyright (C) 2008 - 2009 Bas Driessen <bas.driessen@xobas.com>
12 * Copyright (C) 2008 Phil Longstaff <plongstaff@rogers.com>
13 * Copyright (C) 2008 Przemysław Grzegorczyk <pgrzegorczyk@gmail.com>
14 * Copyright (C) 2010 David King <davidk@openismus.com>
15 * Copyright (C) 2010 Jonh Wendell <jwendell@gnome.org>
16 * Copyright (C) 2011 Daniel Espinosa <esodan@gmail.com>
17 *
18 * This library is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU Lesser General Public
20 * License as published by the Free Software Foundation; either
21 * version 2 of the License, or (at your option) any later version.
22 *
23 * This library is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 * Lesser General Public License for more details.
27 *
28 * You should have received a copy of the GNU Lesser General Public
29 * License along with this library; if not, write to the
30 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
31 * Boston, MA 02110-1301, USA.
32 */
33
34 #undef GDA_DISABLE_DEPRECATED
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <ctype.h>
40 #include <string.h>
41 #include <glib/gi18n-lib.h>
42 #include <libgda/gda-log.h>
43 #include <libgda/gda-util.h>
44 #include <libgda/gda-server-provider.h>
45 #include <libgda/gda-column.h>
46 #include <libgda/gda-data-model-iter.h>
47 #ifdef HAVE_LOCALE_H
48 #include <locale.h>
49 #endif
50 #include <libgda/sql-parser/gda-sql-statement.h>
51 #include <sql-parser/gda-statement-struct-util.h>
52 #include <libgda/gda-set.h>
53 #include <libgda/gda-blob-op.h>
54 #include <libgda/gda-statement-priv.h>
55 #include <libgda/gda-debug-macros.h>
56 #include <libgda/binreloc/gda-binreloc.h>
57
58 #define KEYWORDS_HASH_NO_STATIC
59 #include <libgda/sqlite/keywords_hash.h>
60 #include "keywords_hash.c" /* this one is dynamically generated */
61
62 extern gchar *gda_lang_locale;
63 extern GdaAttributesManager *gda_holder_attributes_manager;
64
65 #define PROV_CLASS(provider) (GDA_SERVER_PROVIDER_CLASS (G_OBJECT_GET_CLASS (provider)))
66
67 /**
68 * gda_g_type_to_string:
69 * @type: Type to convert from.
70 *
71 * Converts a GType to its string representation (use gda_g_type_from_string() for the
72 * operation in the other direction).
73 *
74 * This function wraps g_type_name() but for common types it provides an easier to
75 * understand and remember name. For Example the G_TYPE_STRING is converted to "string"
76 * whereas g_type_name() converts it to "gchararray".
77 *
78 * Returns: the GDA's string representing the given #GType or the name
79 * returned by #g_type_name.
80 */
81 const gchar *
gda_g_type_to_string(GType type)82 gda_g_type_to_string (GType type)
83 {
84 if (type == GDA_TYPE_NULL)
85 return "null";
86 else if (type == G_TYPE_INT)
87 return "int";
88 else if (type == G_TYPE_STRING)
89 return "string";
90 else if (type == G_TYPE_DATE)
91 return "date";
92 else if (type == GDA_TYPE_TIME)
93 return "time";
94 else if (type == GDA_TYPE_TIMESTAMP)
95 return "timestamp";
96 else if (type == G_TYPE_BOOLEAN)
97 return "boolean";
98 else if (type == GDA_TYPE_BLOB)
99 return "blob";
100 else if (type == GDA_TYPE_BINARY)
101 return "binary";
102 else
103 return g_type_name (type);
104 }
105
106 /**
107 * gda_g_type_from_string:
108 * @str: the name of a #GType, as returned by gda_g_type_to_string().
109 *
110 * Converts a named type to ts GType type (also see the gda_g_type_to_string() function).
111 *
112 * This function is a wrapper around the g_type_from_name() function, but also recognizes
113 * some type synonyms such as:
114 * <itemizedlist>
115 * <listitem><para>"int" for G_TYPE_INT</para></listitem>
116 * <listitem><para>"uint" for G_TYPE_UINT</para></listitem>
117 * <listitem><para>"int64" for G_TYPE_INT64</para></listitem>
118 * <listitem><para>"uint64" for G_TYPE_UINT64</para></listitem>
119 * <listitem><para>"char" for G_TYPE_CHAR</para></listitem>
120 * <listitem><para>"uchar" for G_TYPE_UCHAR</para></listitem>
121 * <listitem><para>"short" for GDA_TYPE_SHORT</para></listitem>
122 * <listitem><para>"ushort" for GDA_TYPE_USHORT</para></listitem>
123 * <listitem><para>"string" for G_TYPE_STRING</para></listitem>
124 * <listitem><para>"date" for G_TYPE_DATE</para></listitem>
125 * <listitem><para>"time" for GDA_TYPE_TIME</para></listitem>
126 * <listitem><para>"timestamp" for GDA_TYPE_TIMESTAMP</para></listitem>
127 * <listitem><para>"boolean" for G_TYPE_BOOLEAN</para></listitem>
128 * <listitem><para>"blob" for GDA_TYPE_BLOB</para></listitem>
129 * <listitem><para>"binary" for GDA_TYPE_BINARY</para></listitem>
130 * <listitem><para>"null" for GDA_TYPE_NULL</para></listitem>
131 * </itemizedlist>
132 *
133 * Returns: the #GType represented by the given @str, or #G_TYPE_INVALID if not found
134 */
135 GType
gda_g_type_from_string(const gchar * str)136 gda_g_type_from_string (const gchar *str)
137 {
138 GType type;
139 g_return_val_if_fail (str != NULL, G_TYPE_INVALID);
140
141 type = g_type_from_name (str);
142 if (type == 0) {
143 if (!g_ascii_strcasecmp (str, "int"))
144 type = G_TYPE_INT;
145 else if (!g_ascii_strcasecmp (str, "uint"))
146 type = G_TYPE_UINT;
147 else if (!g_ascii_strcasecmp (str, "string"))
148 type = G_TYPE_STRING;
149 else if (!g_ascii_strcasecmp (str, "date"))
150 type = G_TYPE_DATE;
151 else if (!g_ascii_strcasecmp (str, "time"))
152 type = GDA_TYPE_TIME;
153 else if (!g_ascii_strcasecmp (str, "timestamp"))
154 type = GDA_TYPE_TIMESTAMP;
155 else if (!strcmp (str, "boolean"))
156 type = G_TYPE_BOOLEAN;
157 else if (!strcmp (str, "blob"))
158 type = GDA_TYPE_BLOB;
159 else if (!strcmp (str, "binary"))
160 type = GDA_TYPE_BINARY;
161 else if (!strcmp (str, "null"))
162 type = GDA_TYPE_NULL;
163 else if (!strcmp (str, "short"))
164 type = GDA_TYPE_SHORT;
165 else if (!strcmp (str, "ushort"))
166 type = GDA_TYPE_USHORT;
167 else if (!g_ascii_strcasecmp (str, "int64"))
168 type = G_TYPE_INT64;
169 else if (!g_ascii_strcasecmp (str, "uint64"))
170 type = G_TYPE_UINT64;
171 else if (!g_ascii_strcasecmp (str, "char"))
172 type = G_TYPE_CHAR;
173 else if (!g_ascii_strcasecmp (str, "uchar"))
174 type = G_TYPE_UCHAR;
175 else if (!g_ascii_strcasecmp (str, "gshort"))
176 type = GDA_TYPE_SHORT;
177 else if (!g_ascii_strcasecmp (str, "gushort"))
178 type = GDA_TYPE_USHORT;
179 else
180 /* could not find a valid GType for @str */
181 type = G_TYPE_INVALID;
182 }
183
184 return type;
185 }
186
187 /**
188 * gda_default_escape_string:
189 * @string: string to escape
190 *
191 * Escapes @string to make it understandable by a DBMS. The escape method is very common and replaces any
192 * occurrence of "'" with "''" and "\" with "\\"
193 *
194 * Returns: a new string
195 */
196 gchar *
gda_default_escape_string(const gchar * string)197 gda_default_escape_string (const gchar *string)
198 {
199 gchar *ptr, *ret, *retptr;
200 gint size;
201
202 if (!string)
203 return NULL;
204
205 /* determination of the new string size */
206 ptr = (gchar *) string;
207 size = 1;
208 while (*ptr) {
209 if ((*ptr == '\'') ||(*ptr == '\\'))
210 size += 2;
211 else
212 size += 1;
213 ptr++;
214 }
215
216 ptr = (gchar *) string;
217 ret = g_new0 (gchar, size);
218 retptr = ret;
219 while (*ptr) {
220 if (*ptr == '\'') {
221 *retptr = '\'';
222 *(retptr+1) = *ptr;
223 retptr += 2;
224 }
225 else if (*ptr == '\\') {
226 *retptr = '\\';
227 *(retptr+1) = *ptr;
228 retptr += 2;
229 }
230 else {
231 *retptr = *ptr;
232 retptr ++;
233 }
234 ptr++;
235 }
236 *retptr = '\0';
237
238 return ret;
239 }
240
241 /**
242 * gda_default_unescape_string:
243 * @string: string to unescape
244 *
245 * Do the reverse of gda_default_escape_string(): transforms any "''" into "'", any
246 * "\\" into "\" and any "\'" into "'".
247 *
248 * Returns: a new unescaped string, or %NULL in an error was found in @string
249 */
250 gchar *
gda_default_unescape_string(const gchar * string)251 gda_default_unescape_string (const gchar *string)
252 {
253 glong total;
254 gchar *ptr;
255 gchar *retval;
256 glong offset = 0;
257
258 if (!string)
259 return NULL;
260
261 total = strlen (string);
262 retval = g_memdup (string, total+1);
263 ptr = (gchar *) retval;
264 while (offset < total) {
265 /* we accept the "''" as a synonym of "\'" */
266 if (*ptr == '\'') {
267 if (*(ptr+1) == '\'') {
268 memmove (ptr+1, ptr+2, total - offset);
269 offset += 2;
270 }
271 else {
272 g_free (retval);
273 return NULL;
274 }
275 }
276 if (*ptr == '\\') {
277 if (*(ptr+1) == '\\') {
278 memmove (ptr+1, ptr+2, total - offset);
279 offset += 2;
280 }
281 else {
282 if (*(ptr+1) == '\'') {
283 *ptr = '\'';
284 memmove (ptr+1, ptr+2, total - offset);
285 offset += 2;
286 }
287 else {
288 g_free (retval);
289 return NULL;
290 }
291 }
292 }
293 else
294 offset ++;
295
296 ptr++;
297 }
298
299 return retval;
300 }
301
302 /**
303 * gda_utility_check_data_model_v: (rename-to gda_utility_check_data_model)
304 * @model: a #GdaDataModel object
305 * @nbcols: the minimum requested number of columns
306 * @types: (array length=nbcols): array with @nbcols length of type GType or null (if any data type is accepted)
307 *
308 * Check the column types of a GdaDataModel.
309 *
310 * Returns: %TRUE if the data model's columns match the provided data types and number
311 *
312 * Since: 4.2.6
313 *
314 */
315 gboolean
gda_utility_check_data_model_v(GdaDataModel * model,gint nbcols,GType * types)316 gda_utility_check_data_model_v (GdaDataModel *model, gint nbcols, GType* types)
317 {
318 gboolean retval = TRUE;
319 gint i;
320
321 g_return_val_if_fail (model && GDA_IS_DATA_MODEL (model), FALSE);
322
323 /* number of columns */
324 if (gda_data_model_get_n_columns (model) < nbcols)
325 return FALSE;
326
327 /* type of each column */
328 if (nbcols > 0) {
329 GdaColumn *att;
330 GType mtype, rtype;
331 i = 0;
332 while ((i<nbcols) && retval) {
333 att = gda_data_model_describe_column (model, i);
334 mtype = gda_column_get_g_type (att);
335
336 rtype = types [i];
337 if (mtype != rtype) {
338 retval = FALSE;
339 #ifdef GDA_DEBUG_NO
340 g_print ("Column %d: Expected %s, got %s\n",
341 i, gda_g_type_to_string (rtype), gda_g_type_to_string (mtype));
342 #endif
343 }
344 i++;
345 }
346 }
347
348 return retval;
349 }
350
351
352 /**
353 * gda_utility_check_data_model:
354 * @model: a #GdaDataModel object
355 * @nbcols: the minimum requested number of columns
356 * @...: @nbcols arguments of type GType or -1 (if any data type is accepted)
357 *
358 * Check the column types of a GdaDataModel.
359 *
360 * Returns: %TRUE if the data model's columns match the provided data types and number
361 */
362 gboolean
gda_utility_check_data_model(GdaDataModel * model,gint nbcols,...)363 gda_utility_check_data_model (GdaDataModel *model, gint nbcols, ...)
364 {
365 gboolean retval = TRUE;
366 gint i;
367
368 g_return_val_if_fail (model && GDA_IS_DATA_MODEL (model), FALSE);
369
370 /* number of columns */
371 if (gda_data_model_get_n_columns (model) < nbcols)
372 return FALSE;
373
374 /* type of each column */
375 if (nbcols > 0) {
376 GdaColumn *att;
377 GType mtype, rtype;
378 gint argtype;
379 va_list ap;
380
381 va_start (ap, nbcols);
382 i = 0;
383 while ((i<nbcols) && retval) {
384 att = gda_data_model_describe_column (model, i);
385 mtype = gda_column_get_g_type (att);
386
387 argtype = va_arg (ap, GType);
388 if (argtype >= 0) {
389 rtype = (GType) argtype;
390 if (mtype != rtype) {
391 retval = FALSE;
392 #ifdef GDA_DEBUG
393 g_print ("Column %d: Expected %s, got %s\n",
394 i, gda_g_type_to_string (rtype), gda_g_type_to_string (mtype));
395 #endif
396 }
397 }
398
399 i++;
400 }
401 va_end (ap);
402 }
403
404 return retval;
405
406 }
407
408 /**
409 * gda_utility_data_model_dump_data_to_xml:
410 * @model: a #GdaDataModel
411 * @parent: the parent XML node
412 * @cols: (nullable) (array length=nb_cols): an array containing which columns of @model will be exported, or %NULL for all columns
413 * @nb_cols: the number of columns in @cols
414 * @rows: (nullable) (array length=nb_rows): an array containing which rows of @model will be exported, or %NULL for all rows
415 * @nb_rows: the number of rows in @rows
416 * @use_col_ids: set to %TRUE to add column ID information
417 *
418 * Dump the data in a #GdaDataModel into a xmlNodePtr (as used in libxml).
419 *
420 * Warning: this function uses a #GdaDataModelIter iterator, and if @model does not offer a random access
421 * (check using gda_data_model_get_access_flags()), the iterator will be the same as normally used
422 * to access data in @model previously to calling this method, and this iterator will be moved (point to
423 * another row).
424 *
425 * Returns: %TRUE if no error occurred
426 */
427 gboolean
gda_utility_data_model_dump_data_to_xml(GdaDataModel * model,xmlNodePtr parent,const gint * cols,gint nb_cols,const gint * rows,gint nb_rows,gboolean use_col_ids)428 gda_utility_data_model_dump_data_to_xml (GdaDataModel *model, xmlNodePtr parent,
429 const gint *cols, gint nb_cols,
430 const gint *rows, gint nb_rows,
431 gboolean use_col_ids)
432 {
433 gboolean retval = TRUE;
434 gint *rcols, rnb_cols;
435 gchar **col_ids = NULL;
436 xmlNodePtr data = NULL;
437 GdaDataModelIter *iter;
438
439 /* compute columns if not provided */
440 if (!cols) {
441 gint i;
442 rnb_cols = gda_data_model_get_n_columns (model);
443 rcols = g_new (gint, rnb_cols);
444 for (i = 0; i < rnb_cols; i++)
445 rcols [i] = i;
446 }
447 else {
448 rcols = (gint *) cols;
449 rnb_cols = nb_cols;
450 }
451
452 if (use_col_ids) {
453 gint c;
454 col_ids = g_new0 (gchar *, rnb_cols);
455 for (c = 0; c < rnb_cols; c++) {
456 GdaColumn *column;
457 gchar *id;
458
459 column = gda_data_model_describe_column (model, rcols [c]);
460 g_object_get (G_OBJECT (column), "id", &id, NULL);
461
462 if (id && *id)
463 col_ids [c] = g_strdup (id);
464 else
465 col_ids [c] = g_strdup_printf ("_%d", c);
466
467 g_free (id);
468 }
469 }
470
471 /* add the model data to the XML output */
472 iter = gda_data_model_create_iter (model);
473 if (iter && (gda_data_model_iter_get_row (iter) == -1) && ! gda_data_model_iter_move_next (iter)) {
474 g_object_unref (iter);
475 iter = NULL;
476 }
477 if (iter) {
478 xmlNodePtr row;
479
480 data = xmlNewChild (parent, NULL, (xmlChar*)"gda_array_data", NULL);
481 for (; retval && gda_data_model_iter_is_valid (iter); gda_data_model_iter_move_next (iter)) {
482 gint c;
483 if (rows) {
484 gint r;
485 for (r = 0; r < nb_rows; r++) {
486 if (gda_data_model_iter_get_row (iter) == rows[r])
487 break;
488 }
489 if (r == nb_rows)
490 continue;
491 }
492
493 row = xmlNewChild (data, NULL, (xmlChar*)"gda_array_row", NULL);
494 for (c = 0; c < rnb_cols; c++) {
495 GValue *value;
496 gchar *str = NULL;
497 xmlNodePtr field = NULL;
498
499 value = (GValue*) gda_data_model_iter_get_value_at (iter, rcols[c]);
500 if (!value) {
501 retval = FALSE;
502 break;
503 }
504 if (value && !gda_value_is_null ((GValue *) value)) {
505 if (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN)
506 str = g_strdup (g_value_get_boolean (value) ? "TRUE" : "FALSE");
507 else if (G_VALUE_TYPE (value) == G_TYPE_STRING) {
508 if (g_value_get_string (value))
509 str = gda_value_stringify (value);
510 }
511 else if (G_VALUE_TYPE (value) == GDA_TYPE_BLOB) {
512 /* force reading the whole blob */
513 const GdaBlob *blob = gda_value_get_blob (value);
514 if (blob) {
515 const GdaBinary *bin = &(blob->data);
516 if (blob->op &&
517 (bin->binary_length != gda_blob_op_get_length (blob->op)))
518 gda_blob_op_read_all (blob->op, (GdaBlob*) blob);
519 }
520 str = gda_value_stringify (value);
521 }
522 else
523 str = gda_value_stringify (value);
524 }
525 if (!use_col_ids) {
526 if (str && *str)
527 field = xmlNewTextChild (row, NULL, (xmlChar*)"gda_value", (xmlChar*)str);
528 else
529 field = xmlNewChild (row, NULL, (xmlChar*)"gda_value", NULL);
530 }
531 else {
532 field = xmlNewTextChild (row, NULL, (xmlChar*)"gda_array_value", (xmlChar*)str);
533 xmlSetProp(field, (xmlChar*)"colid", (xmlChar*)col_ids [c]);
534 }
535
536 if (!str)
537 xmlSetProp(field, (xmlChar*)"isnull", (xmlChar*)"t");
538
539 g_free (str);
540 }
541 }
542 g_object_unref (iter);
543 }
544
545 if (!cols)
546 g_free (rcols);
547
548 if (use_col_ids) {
549 gint c;
550 for (c = 0; c < rnb_cols; c++)
551 g_free (col_ids [c]);
552 g_free (col_ids);
553 }
554
555 if (!retval) {
556 xmlUnlinkNode (data);
557 xmlFreeNode (data);
558 }
559
560 return retval;
561 }
562
563
564 /**
565 * gda_utility_data_model_find_column_description:
566 * @model: a #GdaDataSelect data model
567 * @field_name: field name
568 *
569 * Finds the description of a field into Metadata from a #GdaDataModel.
570 *
571 * Returns: The field's description, or NULL if description is not set
572 */
573 const gchar *
gda_utility_data_model_find_column_description(GdaDataSelect * model,const gchar * field_name)574 gda_utility_data_model_find_column_description (GdaDataSelect *model, const gchar *field_name)
575 {
576 g_return_val_if_fail (GDA_IS_DATA_SELECT (model), NULL);
577 g_return_val_if_fail (field_name, NULL);
578
579 GdaConnection *connection = gda_data_select_get_connection ((GdaDataSelect *) model);
580
581 GdaStatement *statement;
582 g_object_get (G_OBJECT (model), "select-stmt", &statement, NULL);
583 if (!statement)
584 return NULL;
585
586 GdaSqlStatement *sql_statement;
587 g_object_get (G_OBJECT (statement), "structure", &sql_statement, NULL);
588 g_object_unref (statement);
589
590 if (!gda_sql_statement_check_validity (sql_statement, connection, NULL)) {
591 gda_sql_statement_free (sql_statement);
592 return NULL;
593 }
594
595 GSList *fields;
596 for (fields = ((GdaSqlStatementSelect *) sql_statement->contents)->expr_list;
597 fields;
598 fields = fields->next) {
599
600 GdaSqlSelectField *select_field = fields->data;
601 if (select_field->validity_meta_table_column) {
602 GdaMetaTableColumn *meta_table_column = select_field->validity_meta_table_column;
603
604 if (! strcmp (meta_table_column->column_name, field_name)) {
605 const GValue *gvalue = gda_meta_table_column_get_attribute
606 (meta_table_column, GDA_ATTRIBUTE_DESCRIPTION);
607
608 gda_sql_statement_free (sql_statement);
609 return gvalue ? g_value_get_string (gvalue) : NULL;
610 }
611 }
612 }
613
614 gda_sql_statement_free (sql_statement);
615 return NULL;
616 }
617
618 /**
619 * gda_utility_holder_load_attributes:
620 * @holder: a #GdaHolder
621 * @node: an xmlNodePtr with a <parameter> tag
622 * @sources: (element-type Gda.DataModel): a list of #GdaDataModel
623 * @error: a place to store errors, or %NULL
624 *
625 * Note: this method may set the "source" custom string property
626 *
627 * Returns: %TRUE if no error occurred
628 */
629 gboolean
gda_utility_holder_load_attributes(GdaHolder * holder,xmlNodePtr node,GSList * sources,GError ** error)630 gda_utility_holder_load_attributes (GdaHolder *holder, xmlNodePtr node, GSList *sources, GError **error)
631 {
632 xmlChar *str;
633 xmlNodePtr vnode;
634 gboolean retval = TRUE;
635
636 /* set properties from the XML spec */
637 str = xmlGetProp (node, BAD_CAST "id");
638 if (str) {
639 g_object_set (G_OBJECT (holder), "id", (gchar*)str, NULL);
640 xmlFree (str);
641 }
642
643 str = xmlGetProp (node, BAD_CAST "name");
644 if (str) {
645 g_object_set (G_OBJECT (holder), "name", (gchar*)str, NULL);
646 xmlFree (str);
647 }
648 str = xmlGetProp (node, BAD_CAST "descr");
649 if (str) {
650 g_object_set (G_OBJECT (holder), "description", (gchar*)str, NULL);
651 xmlFree (str);
652 }
653 str = xmlGetProp (node, BAD_CAST "nullok");
654 if (str) {
655 gda_holder_set_not_null (holder, (*str == 'T') || (*str == 't') ? FALSE : TRUE);
656 xmlFree (str);
657 }
658 else
659 gda_holder_set_not_null (holder, FALSE);
660
661 str = xmlGetProp (node, BAD_CAST "plugin");
662 if (str) {
663 GValue *value;
664 #define GDAUI_ATTRIBUTE_PLUGIN "__gdaui_attr_plugin"
665 value = gda_value_new_from_string ((gchar*) str, G_TYPE_STRING);
666 gda_holder_set_attribute_static (holder, GDAUI_ATTRIBUTE_PLUGIN, value);
667 gda_value_free (value);
668 xmlFree (str);
669 }
670
671 str = xmlGetProp (node, BAD_CAST "source");
672 if (str)
673 g_object_set_data_full (G_OBJECT (holder), "source", str, xmlFree);
674
675 /* set restricting source if specified */
676 if (str && sources) {
677 gchar *ptr1, *ptr2 = NULL, *tok = NULL;
678 gchar *source;
679
680 source = g_strdup ((gchar*)str);
681 ptr1 = strtok_r (source, ":", &tok);
682 if (ptr1)
683 ptr2 = strtok_r (NULL, ":", &tok);
684
685 if (ptr1 && ptr2) {
686 GSList *tmp = sources;
687 GdaDataModel *model = NULL;
688 while (tmp && !model) {
689 gchar *mname = g_object_get_data (G_OBJECT (tmp->data), "name");
690 if (mname && !strcmp (mname, ptr1))
691 model = GDA_DATA_MODEL (tmp->data);
692 tmp = g_slist_next (tmp);
693 }
694
695 if (model) {
696 gint fno;
697
698 fno = atoi (ptr2); /* Flawfinder: ignore */
699 if ((fno < 0) ||
700 (fno >= gda_data_model_get_n_columns (model)))
701 g_warning (_("Field number %d not found in source named '%s'"), fno, ptr1);
702 else {
703 if (gda_holder_set_source_model (holder, model, fno, error)) {
704 gchar *str;
705 /* rename the wrapper with the current holder's name */
706 g_object_get (G_OBJECT (holder), "name", &str, NULL);
707 g_object_set_data_full (G_OBJECT (model), "newname", str, g_free);
708 g_object_get (G_OBJECT (holder), "description", &str, NULL);
709 g_object_set_data_full (G_OBJECT (model), "newdescr", str, g_free);
710 }
711 else
712 retval = FALSE;
713 }
714 }
715 }
716 g_free (source);
717 }
718
719 /* specified value */
720 vnode = node->children;
721 if (vnode) {
722 xmlChar *this_lang, *isnull;
723 const gchar *lang = gda_lang_locale;
724
725 while (vnode) {
726 if (xmlNodeIsText (vnode)) {
727 vnode = vnode->next;
728 continue;
729 }
730
731 if (!strcmp ((gchar*)vnode->name, "attribute")) {
732 xmlChar *att_name;
733 att_name = xmlGetProp (vnode, (xmlChar*) "name");
734 if (att_name) {
735 GValue *value;
736 g_value_set_string ((value = gda_value_new (G_TYPE_STRING)),
737 (gchar*) xmlNodeGetContent (vnode));
738 gda_attributes_manager_set_full (gda_holder_attributes_manager,
739 (gpointer) holder,
740 (gchar*) att_name, value,
741 (GDestroyNotify) xmlFree);
742 gda_value_free (value);
743 }
744 vnode = vnode->next;
745 continue;
746 }
747 if (strcmp ((gchar*)vnode->name, "gda_value")) {
748 vnode = vnode->next;
749 continue;
750 }
751
752 /* don't care about entries for the wrong locale */
753 this_lang = xmlGetProp (vnode, (xmlChar*)"lang");
754 if (this_lang && strncmp ((gchar*)this_lang, lang, strlen ((gchar*)this_lang))) {
755 xmlFree (this_lang);
756 vnode = vnode->next;
757 continue;
758 }
759
760 isnull = xmlGetProp(vnode, (xmlChar*)"isnull");
761 if (isnull) {
762 if ((*isnull == 'f') || (*isnull == 'F')) {
763 xmlFree (isnull);
764 isnull = NULL;
765 }
766 }
767
768 if (!isnull) {
769 gchar* nodeval = (gchar*)xmlNodeGetContent (vnode);
770
771 if (! gda_holder_set_value_str (holder, NULL, nodeval, error))
772 retval = FALSE;
773 xmlFree(nodeval);
774 }
775 else {
776 xmlFree (isnull);
777 if (! gda_holder_set_value (holder, NULL, error))
778 retval = FALSE;
779 }
780
781 vnode = vnode->next;
782 }
783 }
784
785 return retval;
786 }
787
788
789 #define GDA_PARAM_ENCODE_TOKEN "__gda"
790 /**
791 * gda_text_to_alphanum:
792 * @text: the text to convert
793 *
794 * The "encoding" consists in replacing non
795 * alphanumeric character with the string "__gdaXX" where XX is the hex. representation
796 * of the non alphanumeric char.
797 *
798 * Returns: a new string
799 */
800 gchar *
gda_text_to_alphanum(const gchar * text)801 gda_text_to_alphanum (const gchar *text)
802 {
803 GString *string;
804 const gchar* ptr = text;
805 gchar *ret;
806
807 /*g_print ("%s (%s) ", __FUNCTION__, text);*/
808 string = g_string_new ("");
809 for (ptr = text; ptr && *ptr; ptr++) {
810 if (! (((*ptr >= '0') && (*ptr <= '9')) ||
811 ((*ptr >= 'A') && (*ptr <= 'Z')) ||
812 ((*ptr >= 'a') && (*ptr <= 'z')))) {
813 g_string_append (string, GDA_PARAM_ENCODE_TOKEN);
814 g_string_append_printf (string, "%0x", *ptr);
815 }
816 else
817 g_string_append_c (string, *ptr);
818 }
819 ret = string->str;
820 g_string_free (string, FALSE);
821 /*g_print ("=>#%s#\n", ret);*/
822 return ret;
823 }
824
825 /**
826 * gda_alphanum_to_text:
827 * @text: a string
828 *
829 * Does the opposite of gda_text_to_alphanum(), in the same string
830 *
831 * Returns: @text if conversion succeeded or %NULL if an error occurred
832 */
833 gchar *
gda_alphanum_to_text(gchar * text)834 gda_alphanum_to_text (gchar *text)
835 {
836 gchar* ptr = text;
837 gint length = strlen (text);
838 static gint toklength = 0;
839
840 if (toklength == 0)
841 toklength = strlen (GDA_PARAM_ENCODE_TOKEN);
842 /*g_print ("%s (%s) ", __FUNCTION__, text);*/
843 for (ptr = text; ptr && *ptr; ) {
844 if ((length >= toklength + 2) && !strncmp (ptr, GDA_PARAM_ENCODE_TOKEN, toklength)) {
845 gchar *ptr2 = ptr + toklength;
846 char c = *ptr2;
847 gchar val;
848 if ((c >= 'a') && (c <= 'f'))
849 val = (c - 'a' + 10) * 16;
850 else if ((c >= '0') && (c <= '9'))
851 val = (c - '0') * 16;
852 else
853 return NULL;
854 c = *(ptr2+1);
855 if ((c >= 'a') && (c <= 'f'))
856 val += c - 'a' + 10;
857 else if ((c >= '0') && (c <= '9'))
858 val += c - '0';
859 else
860 return NULL;
861 *ptr = val;
862 ptr++;
863 length -= toklength + 1;
864 memmove (ptr, ptr + toklength + 1, length);
865 }
866 else {
867 ptr ++;
868 length --;
869 }
870 }
871 /*g_print ("=>#%s#\n", text);*/
872 return text;
873 }
874
875 /*
876 * Checks related to the structure of the SELECT statement before computing the INSERT, UPDATE and DELETE
877 * corresponding statements.
878 */
879 static gboolean
dml_statements_check_select_structure(GdaConnection * cnc,GdaSqlStatement * sel_struct,GError ** error)880 dml_statements_check_select_structure (GdaConnection *cnc, GdaSqlStatement *sel_struct, GError **error)
881 {
882 GdaSqlStatementSelect *stsel;
883 stsel = (GdaSqlStatementSelect*) sel_struct->contents;
884 if (!stsel->from) {
885 g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
886 "%s", _("SELECT statement has no FROM part"));
887 return FALSE;
888 }
889 if (stsel->from->targets && stsel->from->targets->next) {
890 g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
891 "%s", _("SELECT statement involves more than one table or expression"));
892 return FALSE;
893 }
894 GdaSqlSelectTarget *target;
895 target = (GdaSqlSelectTarget*) stsel->from->targets->data;
896 if (!target->table_name) {
897 g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
898 "%s", _("SELECT statement involves more than one table or expression"));
899 return FALSE;
900 }
901 if (!gda_sql_statement_check_validity (sel_struct, cnc, error))
902 return FALSE;
903
904 /* check that we want to modify a table */
905 g_assert (target->validity_meta_object); /* because gda_sql_statement_check_validity() returned TRUE */
906 if (target->validity_meta_object->obj_type != GDA_META_DB_TABLE) {
907 g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
908 "%s", _("Can only build modification statement for tables"));
909 return FALSE;
910 }
911
912 return TRUE;
913 }
914
915 /**
916 * gda_compute_unique_table_row_condition_with_cnc: (skip)
917 * @cnc: (nullable): a #GdaConnection, or %NULL
918 * @stsel: a #GdaSqlSelectStatement
919 * @mtable: a #GdaMetaTable
920 * @require_pk: set to %TRUE if a primary key is required
921 * @error: a place to store errors, or %NULL
922 *
923 * Computes a #GdaSqlExpr expression which can be used in the WHERE clause of an UPDATE
924 * or DELETE statement when a row from the result of the @stsel statement has to be modified.
925 *
926 * If @require_pk is %TRUE then this function will return a non %NULL #GdaSqlExpr only if it can
927 * use a primary key of @mtable. If @require_pk is %FALSE, then it will try to use a primary key of @mtable,
928 * and if none is available, it will use all the columns of @mtable to compute a condition statement.
929 *
930 * Returns: a new #GdaSqlExpr, or %NULL if an error occurred.
931 *
932 * Since: 4.0.3
933 */
934 GdaSqlExpr*
gda_compute_unique_table_row_condition_with_cnc(GdaConnection * cnc,GdaSqlStatementSelect * stsel,GdaMetaTable * mtable,gboolean require_pk,GError ** error)935 gda_compute_unique_table_row_condition_with_cnc (GdaConnection *cnc, GdaSqlStatementSelect *stsel,
936 GdaMetaTable *mtable, gboolean require_pk, GError **error)
937 {
938 gint i;
939 GdaSqlExpr *expr;
940 GdaSqlOperation *and_cond = NULL;
941
942 g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
943
944 expr = gda_sql_expr_new (NULL); /* no parent */
945
946 if (mtable->pk_cols_nb == 0) {
947 g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
948 "%s", _("Table does not have any primary key"));
949 if (require_pk)
950 goto onerror;
951 else
952 goto allcolums;
953 }
954 else if (mtable->pk_cols_nb > 1) {
955 and_cond = gda_sql_operation_new (GDA_SQL_ANY_PART (expr));
956 and_cond->operator_type = GDA_SQL_OPERATOR_TYPE_AND;
957 expr->cond = and_cond;
958 }
959 for (i = 0; i < mtable->pk_cols_nb; i++) {
960 GdaSqlSelectField *sfield = NULL;
961 GdaMetaTableColumn *tcol;
962 GSList *list;
963 gint index;
964
965 tcol = (GdaMetaTableColumn *) g_slist_nth_data (mtable->columns, mtable->pk_cols_array[i]);
966 for (index = 0, list = stsel->expr_list;
967 list;
968 index++, list = list->next) {
969 sfield = (GdaSqlSelectField *) list->data;
970 if (sfield->validity_meta_table_column == tcol)
971 break;
972 else
973 sfield = NULL;
974 }
975 if (!sfield) {
976 g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
977 "%s", _("Table's primary key is not part of SELECT"));
978 if (require_pk)
979 goto onerror;
980 else
981 goto allcolums;
982 }
983 else {
984 GdaSqlOperation *op;
985 GdaSqlExpr *opexpr;
986 GdaSqlParamSpec *pspec;
987
988 /* equal condition */
989 if (and_cond) {
990 opexpr = gda_sql_expr_new (GDA_SQL_ANY_PART (and_cond));
991 op = gda_sql_operation_new (GDA_SQL_ANY_PART (opexpr));
992 opexpr->cond = op;
993 and_cond->operands = g_slist_append (and_cond->operands, opexpr);
994 }
995 else {
996 op = gda_sql_operation_new (GDA_SQL_ANY_PART (expr));
997 expr->cond = op;
998 }
999 op->operator_type = GDA_SQL_OPERATOR_TYPE_EQ;
1000 /* left operand */
1001 gchar *str;
1002 opexpr = gda_sql_expr_new (GDA_SQL_ANY_PART (op));
1003 str = gda_sql_identifier_quote (tcol->column_name, cnc, NULL, FALSE, FALSE);
1004 g_value_take_string (opexpr->value = gda_value_new (G_TYPE_STRING), str);
1005
1006 op->operands = g_slist_append (op->operands, opexpr);
1007
1008 /* right operand */
1009 opexpr = gda_sql_expr_new (GDA_SQL_ANY_PART (op));
1010 pspec = g_new0 (GdaSqlParamSpec, 1);
1011 pspec->name = g_strdup_printf ("-%d", index);
1012 pspec->g_type = (tcol->gtype != GDA_TYPE_NULL) ? tcol->gtype: G_TYPE_STRING;
1013 pspec->nullok = tcol->nullok;
1014 opexpr->param_spec = pspec;
1015 op->operands = g_slist_append (op->operands, opexpr);
1016 }
1017 }
1018 return expr;
1019
1020 allcolums:
1021
1022 gda_sql_expr_free (expr);
1023 expr = gda_sql_expr_new (NULL); /* no parent */
1024
1025 GSList *columns;
1026 if (! mtable->columns) {
1027 g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
1028 "%s", _("Table does not have any column"));
1029 goto onerror;
1030 }
1031 else if (mtable->columns->next) {
1032 and_cond = gda_sql_operation_new (GDA_SQL_ANY_PART (expr));
1033 and_cond->operator_type = GDA_SQL_OPERATOR_TYPE_AND;
1034 expr->cond = and_cond;
1035 }
1036 for (columns = mtable->columns; columns; columns = columns->next) {
1037 GdaSqlSelectField *sfield = NULL;
1038 GdaMetaTableColumn *tcol;
1039 GSList *list;
1040 gint index;
1041
1042 tcol = (GdaMetaTableColumn *) columns->data;
1043 for (index = 0, list = stsel->expr_list;
1044 list;
1045 index++, list = list->next) {
1046 sfield = (GdaSqlSelectField *) list->data;
1047 if (sfield->validity_meta_table_column == tcol)
1048 break;
1049 else
1050 sfield = NULL;
1051 }
1052 if (!sfield) {
1053 g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
1054 _("Table's column '%s' is not part of SELECT"),
1055 tcol->column_name);
1056 goto onerror;
1057 }
1058 else {
1059 GdaSqlOperation *op;
1060 GdaSqlExpr *opexpr;
1061 GdaSqlParamSpec *pspec;
1062
1063 /* equal condition */
1064 if (and_cond) {
1065 opexpr = gda_sql_expr_new (GDA_SQL_ANY_PART (and_cond));
1066 op = gda_sql_operation_new (GDA_SQL_ANY_PART (opexpr));
1067 opexpr->cond = op;
1068 and_cond->operands = g_slist_append (and_cond->operands, opexpr);
1069 }
1070 else {
1071 op = gda_sql_operation_new (GDA_SQL_ANY_PART (expr));
1072 expr->cond = op;
1073 }
1074 op->operator_type = GDA_SQL_OPERATOR_TYPE_EQ;
1075 /* left operand */
1076 gchar *str;
1077 opexpr = gda_sql_expr_new (GDA_SQL_ANY_PART (op));
1078 str = gda_sql_identifier_quote (tcol->column_name, cnc, NULL, FALSE, FALSE);
1079 g_value_take_string (opexpr->value = gda_value_new (G_TYPE_STRING), str);
1080
1081 op->operands = g_slist_append (op->operands, opexpr);
1082
1083 /* right operand */
1084 opexpr = gda_sql_expr_new (GDA_SQL_ANY_PART (op));
1085 pspec = g_new0 (GdaSqlParamSpec, 1);
1086 pspec->name = g_strdup_printf ("-%d", index);
1087 pspec->g_type = (tcol->gtype != GDA_TYPE_NULL) ? tcol->gtype: G_TYPE_STRING;
1088 pspec->nullok = tcol->nullok;
1089 opexpr->param_spec = pspec;
1090 op->operands = g_slist_append (op->operands, opexpr);
1091 }
1092 }
1093 return expr;
1094
1095 onerror:
1096 gda_sql_expr_free (expr);
1097 return NULL;
1098 }
1099
1100 /**
1101 * gda_compute_unique_table_row_condition: (skip)
1102 * @stsel: a #GdaSqlSelectStatement
1103 * @mtable: a #GdaMetaTable
1104 * @require_pk: set to TRUE if a primary key ir required
1105 * @error: a place to store errors, or %NULL
1106 *
1107 * Computes a #GdaSqlExpr expression which can be used in the WHERE clause of an UPDATE
1108 * or DELETE statement when a row from the result of the @stsel statement has to be modified.
1109 *
1110 * Returns: a new #GdaSqlExpr, or %NULL if an error occurred.
1111 */
1112 GdaSqlExpr*
gda_compute_unique_table_row_condition(GdaSqlStatementSelect * stsel,GdaMetaTable * mtable,gboolean require_pk,GError ** error)1113 gda_compute_unique_table_row_condition (GdaSqlStatementSelect *stsel, GdaMetaTable *mtable, gboolean require_pk, GError **error)
1114 {
1115 return gda_compute_unique_table_row_condition_with_cnc (NULL, stsel, mtable, require_pk, error);
1116 }
1117
1118 /**
1119 * gda_compute_dml_statements:
1120 * @cnc: a #GdaConnection
1121 * @select_stmt: a SELECT #GdaStatement (compound statements not handled)
1122 * @require_pk: TRUE if the created statement have to use a primary key
1123 * @insert_stmt: (nullable) (transfer full): a place to store the created INSERT statement, or %NULL
1124 * @update_stmt: (nullable) (transfer full): a place to store the created UPDATE statement, or %NULL
1125 * @delete_stmt: (nullable) (transfer full): a place to store the created DELETE statement, or %NULL
1126 * @error: (nullable): a place to store errors, or %NULL
1127 *
1128 * Creates an INSERT, an UPDATE and a DELETE statement from a SELECT statement
1129 * using the database metadata available in @cnc's meta store. Each statements are computed only if
1130 * the corresponding place to store the created statement is not %NULL.
1131 *
1132 * returns: %TRUE if no error occurred
1133 */
1134 gboolean
gda_compute_dml_statements(GdaConnection * cnc,GdaStatement * select_stmt,gboolean require_pk,GdaStatement ** insert_stmt,GdaStatement ** update_stmt,GdaStatement ** delete_stmt,GError ** error)1135 gda_compute_dml_statements (GdaConnection *cnc, GdaStatement *select_stmt, gboolean require_pk,
1136 GdaStatement **insert_stmt, GdaStatement **update_stmt, GdaStatement **delete_stmt, GError **error)
1137 {
1138 GdaSqlStatement *sel_struct;
1139 GdaSqlStatementSelect *stsel;
1140 GdaStatement *ret_insert = NULL;
1141 GdaStatement *ret_update = NULL;
1142 GdaStatement *ret_delete = NULL;
1143 GdaMetaStruct *mstruct;
1144 gboolean retval = TRUE;
1145 GdaSqlSelectTarget *target;
1146
1147 GdaSqlStatement *sql_ist = NULL;
1148 GdaSqlStatementInsert *ist = NULL;
1149 GdaSqlStatement *sql_ust = NULL;
1150 GdaSqlStatementUpdate *ust = NULL;
1151 GdaSqlStatement *sql_dst = NULL;
1152 GdaSqlStatementDelete *dst = NULL;
1153
1154 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1155 g_return_val_if_fail (GDA_IS_STATEMENT (select_stmt), FALSE);
1156 g_return_val_if_fail (gda_statement_get_statement_type (select_stmt) == GDA_SQL_STATEMENT_SELECT, FALSE);
1157
1158 /*g_print ("*** %s\n", gda_statement_serialize (select_stmt));*/
1159
1160 g_object_get (G_OBJECT (select_stmt), "structure", &sel_struct, NULL);
1161 if (!dml_statements_check_select_structure (cnc, sel_struct, error)) {
1162 retval = FALSE;
1163 goto cleanup;
1164 }
1165
1166 /* normalize the statement */
1167 if (!gda_sql_statement_normalize (sel_struct, cnc, error)) {
1168 retval = FALSE;
1169 goto cleanup;
1170 }
1171
1172 mstruct = sel_struct->validity_meta_struct;
1173 g_assert (mstruct); /* because gda_sql_statement_check_validity() returned TRUE */
1174
1175 /* check that the condition will be buildable */
1176 stsel = (GdaSqlStatementSelect*) sel_struct->contents;
1177 target = (GdaSqlSelectTarget*) stsel->from->targets->data;
1178
1179 /* actual statement structure's computation */
1180 gchar *tmp;
1181 tmp = gda_sql_identifier_quote (target->table_name, cnc, NULL, FALSE, FALSE);
1182 if (insert_stmt) {
1183 sql_ist = gda_sql_statement_new (GDA_SQL_STATEMENT_INSERT);
1184 ist = (GdaSqlStatementInsert*) sql_ist->contents;
1185 g_assert (GDA_SQL_ANY_PART (ist)->type == GDA_SQL_ANY_STMT_INSERT);
1186
1187 ist->table = gda_sql_table_new (GDA_SQL_ANY_PART (ist));
1188 ist->table->table_name = g_strdup ((gchar *) target->table_name);
1189 }
1190
1191 if (update_stmt) {
1192 sql_ust = gda_sql_statement_new (GDA_SQL_STATEMENT_UPDATE);
1193 ust = (GdaSqlStatementUpdate*) sql_ust->contents;
1194 g_assert (GDA_SQL_ANY_PART (ust)->type == GDA_SQL_ANY_STMT_UPDATE);
1195
1196 ust->table = gda_sql_table_new (GDA_SQL_ANY_PART (ust));
1197 ust->table->table_name = g_strdup (tmp);
1198 ust->cond = gda_compute_unique_table_row_condition_with_cnc (cnc, stsel,
1199 GDA_META_TABLE (target->validity_meta_object),
1200 require_pk, error);
1201 if (!ust->cond) {
1202 retval = FALSE;
1203 *update_stmt = NULL;
1204 update_stmt = NULL; /* don't try anymore to build UPDATE statement */
1205 }
1206 else
1207 GDA_SQL_ANY_PART (ust->cond)->parent = GDA_SQL_ANY_PART (ust);
1208 }
1209
1210 if (retval && delete_stmt) {
1211 sql_dst = gda_sql_statement_new (GDA_SQL_STATEMENT_DELETE);
1212 dst = (GdaSqlStatementDelete*) sql_dst->contents;
1213 g_assert (GDA_SQL_ANY_PART (dst)->type == GDA_SQL_ANY_STMT_DELETE);
1214
1215 dst->table = gda_sql_table_new (GDA_SQL_ANY_PART (dst));
1216 dst->table->table_name = g_strdup (tmp);
1217 if (update_stmt && ust->cond)
1218 dst->cond = gda_sql_expr_copy (ust->cond);
1219 else
1220 dst->cond = gda_compute_unique_table_row_condition_with_cnc (cnc, stsel,
1221 GDA_META_TABLE (target->validity_meta_object),
1222 require_pk, error);
1223 if (!dst->cond) {
1224 retval = FALSE;
1225 *delete_stmt = NULL;
1226 delete_stmt = NULL; /* don't try anymore to build DELETE statement */
1227 }
1228 else
1229 GDA_SQL_ANY_PART (dst->cond)->parent = GDA_SQL_ANY_PART (dst);
1230 }
1231 g_free (tmp);
1232 if (!retval)
1233 goto cleanup;
1234
1235 GSList *expr_list;
1236 gint colindex;
1237 GSList *insert_values_list = NULL;
1238 GHashTable *fields_hash; /* key = a table's field's name, value = we don't care */
1239 fields_hash = g_hash_table_new ((GHashFunc) gda_identifier_hash, (GEqualFunc) gda_identifier_equal);
1240 for (expr_list = stsel->expr_list, colindex = 0;
1241 expr_list;
1242 expr_list = expr_list->next, colindex++) {
1243 GdaSqlSelectField *selfield = (GdaSqlSelectField *) expr_list->data;
1244 if ((selfield->validity_meta_object != target->validity_meta_object) ||
1245 !selfield->validity_meta_table_column)
1246 continue;
1247
1248 /* field to insert into */
1249 if (g_hash_table_lookup (fields_hash, selfield->field_name))
1250 continue;
1251 g_hash_table_insert (fields_hash, selfield->field_name, GINT_TO_POINTER (1));
1252
1253 if (insert_stmt) {
1254 GdaSqlField *field;
1255 field = gda_sql_field_new (GDA_SQL_ANY_PART (ist));
1256 field->field_name = g_strdup (selfield->field_name);
1257 ist->fields_list = g_slist_append (ist->fields_list, field);
1258 }
1259 if (update_stmt) {
1260 GdaSqlField *field;
1261 field = gda_sql_field_new (GDA_SQL_ANY_PART (ust));
1262 field->field_name = g_strdup (selfield->field_name);
1263 ust->fields_list = g_slist_append (ust->fields_list, field);
1264 }
1265
1266 /* parameter for the inserted value */
1267 GdaSqlExpr *expr;
1268 GdaMetaTableColumn *tcol;
1269
1270 tcol = selfield->validity_meta_table_column;
1271 if (insert_stmt) {
1272 GdaSqlParamSpec *pspec = g_new0 (GdaSqlParamSpec, 1);
1273 pspec->name = g_strdup_printf ("+%d", colindex);
1274 pspec->g_type = (tcol->gtype != GDA_TYPE_NULL) ? tcol->gtype: G_TYPE_STRING;
1275 pspec->nullok = tcol->nullok;
1276 expr = gda_sql_expr_new (GDA_SQL_ANY_PART (ist));
1277 if (tcol->default_value)
1278 g_value_set_string ((expr->value = gda_value_new (G_TYPE_STRING)),
1279 tcol->default_value);
1280 else if (gda_meta_table_column_get_attribute (tcol, GDA_ATTRIBUTE_AUTO_INCREMENT))
1281 expr->value = gda_value_new_default (GDA_EXTRA_AUTO_INCREMENT);
1282
1283 expr->param_spec = pspec;
1284 insert_values_list = g_slist_append (insert_values_list, expr);
1285 }
1286 if (update_stmt) {
1287 GdaSqlParamSpec *pspec = g_new0 (GdaSqlParamSpec, 1);
1288 pspec->name = g_strdup_printf ("+%d", colindex);
1289 pspec->g_type = (tcol->gtype != GDA_TYPE_NULL) ? tcol->gtype: G_TYPE_STRING;
1290 pspec->nullok = tcol->nullok;
1291 expr = gda_sql_expr_new (GDA_SQL_ANY_PART (ust));
1292 if (tcol->default_value)
1293 g_value_set_string ((expr->value = gda_value_new (G_TYPE_STRING)),
1294 tcol->default_value);
1295 else if (gda_meta_table_column_get_attribute (tcol, GDA_ATTRIBUTE_AUTO_INCREMENT))
1296 expr->value = gda_value_new_default (GDA_EXTRA_AUTO_INCREMENT);
1297 expr->param_spec = pspec;
1298 ust->expr_list = g_slist_append (ust->expr_list, expr);
1299 }
1300 }
1301 g_hash_table_destroy (fields_hash);
1302
1303 /* finish the statements */
1304 if (insert_stmt) {
1305 if (!ist->fields_list) {
1306 /* nothing to insert => don't create statement */
1307 /* To translators: this error message occurs when no "INSERT INTO <table> (field1, ...)..."
1308 * SQL statement can be computed because no table field can be used */
1309 g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
1310 "%s", _("Could not compute any field to insert into"));
1311 retval = FALSE;
1312 }
1313 else {
1314 ist->values_list = g_slist_append (NULL, insert_values_list);
1315 ret_insert = g_object_new (GDA_TYPE_STATEMENT, "structure", sql_ist, NULL);
1316 }
1317 }
1318 if (update_stmt)
1319 ret_update = g_object_new (GDA_TYPE_STATEMENT, "structure", sql_ust, NULL);
1320 if (delete_stmt)
1321 ret_delete = g_object_new (GDA_TYPE_STATEMENT, "structure", sql_dst, NULL);
1322
1323 cleanup:
1324 gda_sql_statement_free (sel_struct);
1325 if (sql_ist)
1326 gda_sql_statement_free (sql_ist);
1327 if (sql_ust)
1328 gda_sql_statement_free (sql_ust);
1329 if (sql_dst)
1330 gda_sql_statement_free (sql_dst);
1331
1332 if (insert_stmt)
1333 *insert_stmt = ret_insert;
1334 if (update_stmt)
1335 *update_stmt = ret_update;
1336 if (delete_stmt)
1337 *delete_stmt = ret_delete;
1338 return retval;
1339 }
1340
1341 /**
1342 * gda_compute_select_statement_from_update: (skip)
1343 * @update_stmt: an UPDATE statement
1344 * @error: a place to store errors, or %NULL
1345 *
1346 * Computes a SELECT statement which selects all the rows the @update_stmt would update. Beware
1347 * however that this #GdaSqlStatement does not select anything (ie it would be rendered as "SELECT FROM ... WHERE ...")
1348 * and before being usable, one needs to add some fields to actually select.
1349 *
1350 * Returns: a new #GdaStatement if no error occurred, or %NULL otherwise
1351 */
1352 GdaSqlStatement *
gda_compute_select_statement_from_update(GdaStatement * update_stmt,GError ** error)1353 gda_compute_select_statement_from_update (GdaStatement *update_stmt, GError **error)
1354 {
1355 GdaSqlStatement *upd_stmt;
1356 GdaSqlStatement *sel_stmt;
1357 GdaSqlStatementUpdate *ust;
1358 GdaSqlStatementSelect *sst;
1359
1360 g_return_val_if_fail (update_stmt, NULL);
1361 g_object_get (G_OBJECT (update_stmt), "structure", &upd_stmt, NULL);
1362 g_return_val_if_fail (upd_stmt, NULL);
1363 g_return_val_if_fail (upd_stmt->stmt_type == GDA_SQL_STATEMENT_UPDATE, NULL);
1364
1365 ust = (GdaSqlStatementUpdate*) upd_stmt->contents;
1366
1367 sel_stmt = gda_sql_statement_new (GDA_SQL_STATEMENT_SELECT);
1368 sst = (GdaSqlStatementSelect*) sel_stmt->contents;
1369 g_assert (GDA_SQL_ANY_PART (sst)->type == GDA_SQL_ANY_STMT_SELECT);
1370
1371 if (!ust->table || !ust->table->table_name) {
1372 g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
1373 "%s", _("Missing table name in UPDATE statement"));
1374 return NULL;
1375 }
1376
1377 /* FROM */
1378 GdaSqlSelectTarget *target;
1379 sst->from = gda_sql_select_from_new (GDA_SQL_ANY_PART (sst));
1380 target = gda_sql_select_target_new (GDA_SQL_ANY_PART (sst->from));
1381 sst->from->targets = g_slist_prepend (NULL, target);
1382 target->expr = gda_sql_expr_new (GDA_SQL_ANY_PART (target));
1383 g_value_set_string ((target->expr->value = gda_value_new (G_TYPE_STRING)), ust->table->table_name);
1384
1385 /* WHERE */
1386 if (ust->cond) {
1387 sst->where_cond = gda_sql_expr_copy (ust->cond);
1388 GDA_SQL_ANY_PART (sst->where_cond)->parent = GDA_SQL_ANY_PART (sst);
1389 }
1390
1391 gda_sql_statement_free (upd_stmt);
1392
1393 return sel_stmt;
1394 }
1395
1396 typedef struct {
1397 GdaSqlAnyPart *contents;
1398 GdaSet *params;
1399 GSList *expr_list; /* contains a list of #GdaSqlExpr after
1400 * gda_sql_any_part_foreach has been called */
1401 } NullData;
1402
1403 static gboolean
null_param_foreach_func(GdaSqlAnyPart * part,NullData * data,GError ** error)1404 null_param_foreach_func (GdaSqlAnyPart *part, NullData *data , GError **error)
1405 {
1406 if ((part->type != GDA_SQL_ANY_EXPR) || !((GdaSqlExpr*) part)->param_spec)
1407 return TRUE;
1408
1409 if (!part->parent ||
1410 (part->parent->type != GDA_SQL_ANY_SQL_OPERATION) ||
1411 ((((GdaSqlOperation*) part->parent)->operator_type != GDA_SQL_OPERATOR_TYPE_EQ) &&
1412 (((GdaSqlOperation*) part->parent)->operator_type != GDA_SQL_OPERATOR_TYPE_DIFF)))
1413 return TRUE;
1414
1415 GdaHolder *holder;
1416 GdaSqlParamSpec *pspec = ((GdaSqlExpr*) part)->param_spec;
1417 holder = gda_set_get_holder (data->params, pspec->name);
1418 if (!holder)
1419 return TRUE;
1420
1421 const GValue *cvalue;
1422 cvalue = gda_holder_get_value (holder);
1423 if (!cvalue || (G_VALUE_TYPE (cvalue) != GDA_TYPE_NULL))
1424 return TRUE;
1425
1426 GdaSqlOperation *op;
1427 GdaSqlExpr *oexpr = NULL;
1428 op = (GdaSqlOperation*) part->parent;
1429 if (op->operands->data == part) {
1430 if (op->operands->next)
1431 oexpr = (GdaSqlExpr*) op->operands->next->data;
1432 }
1433 else
1434 oexpr = (GdaSqlExpr*) op->operands->data;
1435 if (oexpr && !g_slist_find (data->expr_list, oexpr)) /* handle situations where ##p1==##p2
1436 * and both p1 and p2 are set to NULL */
1437 data->expr_list = g_slist_prepend (data->expr_list, part);
1438 return TRUE;
1439 }
1440
1441 static GdaSqlExpr *
get_prev_expr(GSList * expr_list,GdaSqlAnyPart * expr)1442 get_prev_expr (GSList *expr_list, GdaSqlAnyPart *expr)
1443 {
1444 GSList *list;
1445 for (list = expr_list; list && list->next; list = list->next) {
1446 if ((GdaSqlAnyPart*) list->next->data == expr)
1447 return (GdaSqlExpr*) list->data;
1448 }
1449 return NULL;
1450 }
1451
1452 static gboolean
null_param_unknown_foreach_func(GdaSqlAnyPart * part,NullData * data,GError ** error)1453 null_param_unknown_foreach_func (GdaSqlAnyPart *part, NullData *data, GError **error)
1454 {
1455 GdaSqlExpr *expr;
1456 if ((part->type != GDA_SQL_ANY_EXPR) || !((GdaSqlExpr*) part)->param_spec)
1457 return TRUE;
1458
1459 if (!part->parent || part->parent != data->contents)
1460 return TRUE;
1461
1462 GdaHolder *holder;
1463 GdaSqlParamSpec *pspec = ((GdaSqlExpr*) part)->param_spec;
1464 holder = gda_set_get_holder (data->params, pspec->name);
1465 if (!holder)
1466 return TRUE;
1467
1468 const GValue *cvalue;
1469 cvalue = gda_holder_get_value (holder);
1470 if (!cvalue || (G_VALUE_TYPE (cvalue) != GDA_TYPE_NULL))
1471 return TRUE;
1472
1473 GSList *tmplist = NULL;
1474 for (expr = get_prev_expr (((GdaSqlStatementUnknown*) data->contents)->expressions, part);
1475 expr;
1476 expr = get_prev_expr (((GdaSqlStatementUnknown*) data->contents)->expressions, (GdaSqlAnyPart*) expr)) {
1477 gchar *str, *tmp;
1478 if (!expr->value || (G_VALUE_TYPE (expr->value) != G_TYPE_STRING))
1479 goto out;
1480
1481 str = (gchar*) g_value_get_string (expr->value);
1482 if (!str || !*str) {
1483 tmplist = g_slist_prepend (tmplist, expr);
1484 continue;
1485 }
1486 for (tmp = str + strlen (str) - 1; tmp >= str; tmp --) {
1487 if ((*tmp == ' ') || (*tmp == '\t') || (*tmp == '\n') || (*tmp == '\r'))
1488 continue;
1489 if (*tmp == '=') {
1490 gchar *dup;
1491 if ((tmp > str) && (*(tmp-1) == '!')) {
1492 *(tmp-1) = 0;
1493 dup = g_strdup_printf ("%s IS NOT NULL", str);
1494 }
1495 else {
1496 *tmp = 0;
1497 dup = g_strdup_printf ("%s IS NULL", str);
1498 }
1499 g_value_take_string (expr->value, dup);
1500 if (tmplist) {
1501 data->expr_list = g_slist_concat (tmplist, data->expr_list);
1502 tmplist = NULL;
1503 }
1504 data->expr_list = g_slist_prepend (data->expr_list, part);
1505 goto out;
1506 }
1507 else
1508 goto out;
1509 }
1510 tmplist = g_slist_prepend (tmplist, expr);
1511 }
1512 out:
1513 g_slist_free (tmplist);
1514
1515 return TRUE;
1516 }
1517
1518 /**
1519 * gda_rewrite_sql_statement_for_null_parameters: (skip)
1520 * @sqlst: (transfer full): a #GdaSqlStatement
1521 * @params: a #GdaSet to be used as parameters when executing @stmt
1522 * @out_modified: (nullable): a place to store the boolean which tells if @stmt has been modified or not, or %NULL
1523 * @error: a place to store errors, or %NULL
1524 *
1525 * Modifies @sqlst to take into account any parameter which might be %NULL: if @sqlst contains the
1526 * equivalent of "xxx = <parameter definition>" and if that parameter is in @params and
1527 * its value is of type GDA_TYPE_NUL, then that part is replaced with "xxx IS NULL". It also
1528 * handles the "xxx IS NOT NULL" transformation.
1529 *
1530 * If @out_modified is not %NULL, then it will be set to %TRUE if @sqlst has been modified
1531 * by this function, and to %FALSE otherwise.
1532 *
1533 * This function is used by provider's implementations to make sure one can use parameters with
1534 * NULL values in statements without having to rewrite statements, as database usually don't
1535 * consider that "xxx = NULL" is the same as "xxx IS NULL" when using parameters.
1536 *
1537 * Returns: (transfer full): the modified @sqlst statement, or %NULL if an error occurred
1538 *
1539 * Since: 4.2.9
1540 */
1541 GdaSqlStatement *
gda_rewrite_sql_statement_for_null_parameters(GdaSqlStatement * sqlst,GdaSet * params,gboolean * out_modified,GError ** error)1542 gda_rewrite_sql_statement_for_null_parameters (GdaSqlStatement *sqlst, GdaSet *params,
1543 gboolean *out_modified, GError **error)
1544 {
1545 if (out_modified)
1546 *out_modified = FALSE;
1547 g_return_val_if_fail (sqlst, sqlst);
1548
1549 if (!params)
1550 return sqlst;
1551 GSList *list;
1552 for (list = params->holders; list; list = list->next) {
1553 const GValue *cvalue;
1554 cvalue = gda_holder_get_value ((GdaHolder*) list->data);
1555 if (cvalue && (G_VALUE_TYPE (cvalue) == GDA_TYPE_NULL))
1556 break;
1557 }
1558 if (!list || (sqlst->stmt_type == GDA_SQL_STATEMENT_NONE))
1559 return sqlst; /* no modifications necessary */
1560
1561 NullData data;
1562 data.contents = GDA_SQL_ANY_PART (sqlst->contents);
1563 data.params = params;
1564 data.expr_list = NULL;
1565
1566 if (sqlst->stmt_type == GDA_SQL_STATEMENT_UNKNOWN) {
1567 if (! gda_sql_any_part_foreach (GDA_SQL_ANY_PART (sqlst->contents),
1568 (GdaSqlForeachFunc) null_param_unknown_foreach_func,
1569 &data, error)) {
1570 gda_sql_statement_free (sqlst);
1571 return NULL;
1572 }
1573 if (out_modified)
1574 *out_modified = data.expr_list ? TRUE : FALSE;
1575 for (list = data.expr_list; list; list = list->next) {
1576 ((GdaSqlStatementUnknown*) data.contents)->expressions =
1577 g_slist_remove (((GdaSqlStatementUnknown*) data.contents)->expressions,
1578 list->data);
1579 gda_sql_expr_free ((GdaSqlExpr*) list->data);
1580 }
1581 }
1582 else {
1583 if (! gda_sql_any_part_foreach (GDA_SQL_ANY_PART (sqlst->contents),
1584 (GdaSqlForeachFunc) null_param_foreach_func,
1585 &data, error)) {
1586 gda_sql_statement_free (sqlst);
1587 return NULL;
1588 }
1589 if (out_modified)
1590 *out_modified = data.expr_list ? TRUE : FALSE;
1591 for (list = data.expr_list; list; list = list->next) {
1592 GdaSqlOperation *op;
1593 op = (GdaSqlOperation*) (((GdaSqlAnyPart*) list->data)->parent);
1594 op->operands = g_slist_remove (op->operands, list->data);
1595 if (op->operator_type == GDA_SQL_OPERATOR_TYPE_EQ)
1596 op->operator_type = GDA_SQL_OPERATOR_TYPE_ISNULL;
1597 else
1598 op->operator_type = GDA_SQL_OPERATOR_TYPE_ISNOTNULL;
1599 gda_sql_expr_free ((GdaSqlExpr*) list->data);
1600 }
1601 }
1602 g_slist_free (data.expr_list);
1603 return sqlst;
1604 }
1605
1606 /**
1607 * gda_rewrite_statement_for_null_parameters:
1608 * @stmt: (transfer none): a #GdaStatement
1609 * @params: a #GdaSet to be used as parameters when executing @stmt
1610 * @out_stmt: (transfer full) (nullable): a place to store the new #GdaStatement, or %NULL
1611 * @error: a place to store errors, or %NULL
1612 *
1613 * Modifies @stmt to take into account any parameter which might be %NULL: if @stmt contains the
1614 * equivalent of "xxx = <parameter definition>" and if that parameter is in @params and
1615 * its value is of type GDA_TYPE_NUL, then that part is replaced with "xxx IS NULL". It also
1616 * handles the "xxx IS NOT NULL" transformation.
1617 *
1618 * For example the following SELECT:
1619 * <programlisting>SELECT * FROM data WHERE id = ##id::int::null AND name = ##name::string</programlisting>
1620 * in case the "id" parameter is set to NULL, is converted to:
1621 * <programlisting>SELECT * FROM data WHERE id IS NULL AND name = ##name::string</programlisting>
1622 *
1623 * if @out_stmt is not %NULL, then it will contain:
1624 * <itemizedlist>
1625 * <listitem><para>the modified statement if some modifications were required and no error occured (the function returns %TRUE)</para></listitem>
1626 * <listitem><para>%NULL if no modification to @stmt were required and no erro occurred (the function returns %FALSE)</para></listitem>
1627 * <listitem><para>%NULL if an error occured (the function returns %TRUE)</para></listitem>
1628 * </itemizedlist>
1629 *
1630 * This function is used by provider's implementations to make sure one can use parameters with
1631 * NULL values in statements without having to rewrite statements, as database usually don't
1632 * consider that "xxx = NULL" is the same as "xxx IS NULL" when using parameters.
1633 *
1634 * Returns: %TRUE if @stmt needs to be transformed to handle NULL parameters, and %FALSE otherwise
1635 *
1636 * Since: 4.2.9
1637 */
1638 gboolean
gda_rewrite_statement_for_null_parameters(GdaStatement * stmt,GdaSet * params,GdaStatement ** out_stmt,GError ** error)1639 gda_rewrite_statement_for_null_parameters (GdaStatement *stmt, GdaSet *params,
1640 GdaStatement **out_stmt, GError **error)
1641 {
1642 GdaSqlStatement *sqlst;
1643 gboolean mod;
1644 g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE);
1645 g_return_val_if_fail (!params || GDA_IS_SET (params), FALSE);
1646
1647 if (out_stmt)
1648 *out_stmt = NULL;
1649 if (!params)
1650 return FALSE;
1651
1652 g_object_get ((GObject*) stmt, "structure", &sqlst, NULL);
1653 if (gda_rewrite_sql_statement_for_null_parameters (sqlst, params, &mod, error)) {
1654 if (out_stmt) {
1655 if (mod) {
1656 *out_stmt = g_object_new (GDA_TYPE_STATEMENT, "structure", sqlst, NULL);
1657 gda_sql_statement_free (sqlst);
1658 }
1659 }
1660 return mod;
1661 }
1662 else {
1663 /* error => leave *out_stmt to %NULL */
1664 return TRUE;
1665 }
1666 }
1667
1668
1669
1670 static gboolean stmt_rewrite_insert_remove (GdaSqlStatementInsert *ins, GdaSet *params, GError **error);
1671 static gboolean stmt_rewrite_insert_default_keyword (GdaSqlStatementInsert *ins, GdaSet *params, GError **error);
1672 static gboolean stmt_rewrite_update_default_keyword (GdaSqlStatementUpdate *upd, GdaSet *params, GError **error);
1673
1674
1675 /**
1676 * gda_statement_rewrite_for_default_values: (skip)
1677 * @stmt: a #GdaStatement object
1678 * @params: a #GdaSet containing the variable's values to be bound when executing @stmt
1679 * @remove: set to %TRUE if DEFAULT fields are removed, of %FALSE if the "DEFAULT" keyword is used
1680 * @error: a place to store errors, or %NULL
1681 *
1682 * Rewrites @stmt and creates a new #GdaSqlStatement where all the variables which are to a DEFAULT value
1683 * (as returned by gda_holder_value_is_default()) are either removed from the statement (if @remove
1684 * is %TRUE) or replaced by the "DEFAULT" keyword (if @remove is %FALSE).
1685 *
1686 * This function is only useful for database providers' implementations which have to deal with default
1687 * values when executing statements, and is only relevant in the case of INSERT or UPDATE statements
1688 * (in the latter case an error is returned if @remove is %TRUE).
1689 *
1690 * For example the <programlisting><![CDATA[INSERT INTO mytable (id, name) VALUES (23, ##name::string)]]></programlisting>
1691 * is re-written into <programlisting><![CDATA[INSERT INTO mytable (id, name) VALUES (23, DEFAULT)]]></programlisting>
1692 * if @remove is %FALSE and into <programlisting><![CDATA[INSERT INTO mytable (id) VALUES (23)]]></programlisting>
1693 * if @remove is %TRUE.
1694 *
1695 * Returns: a new #GdaSqlStatement, or %NULL if an error occurred
1696 *
1697 * Since: 4.2
1698 */
1699 GdaSqlStatement *
gda_statement_rewrite_for_default_values(GdaStatement * stmt,GdaSet * params,gboolean remove,GError ** error)1700 gda_statement_rewrite_for_default_values (GdaStatement *stmt, GdaSet *params, gboolean remove, GError **error)
1701 {
1702 GdaSqlStatement *sqlst;
1703 GdaSqlStatementType type;
1704 gboolean ok = FALSE;
1705 g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
1706 g_return_val_if_fail (GDA_IS_SET (params), NULL);
1707 type = gda_statement_get_statement_type (stmt);
1708
1709 g_object_get (stmt, "structure", &sqlst, NULL);
1710 if (! gda_sql_statement_check_structure (sqlst, error)) {
1711 gda_sql_statement_free (sqlst);
1712 return NULL;
1713 }
1714
1715 switch (type) {
1716 case GDA_SQL_STATEMENT_INSERT:
1717 if (remove)
1718 ok = stmt_rewrite_insert_remove ((GdaSqlStatementInsert*) sqlst->contents,
1719 params, error);
1720 else
1721 ok = stmt_rewrite_insert_default_keyword ((GdaSqlStatementInsert*) sqlst->contents,
1722 params, error);
1723 break;
1724 case GDA_SQL_STATEMENT_UPDATE:
1725 if (remove)
1726 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
1727 GDA_SERVER_PROVIDER_DEFAULT_VALUE_HANDLING_ERROR,
1728 "%s", _("Can't rewrite UPDATE statement to handle default values"));
1729 else
1730 ok = stmt_rewrite_update_default_keyword ((GdaSqlStatementUpdate*) sqlst->contents,
1731 params, error);
1732 break;
1733 default:
1734 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
1735 GDA_SERVER_PROVIDER_DEFAULT_VALUE_HANDLING_ERROR,
1736 "%s", _("Can't rewrite statement which is not INSERT or UPDATE"));
1737 break;
1738 }
1739
1740 if (ok)
1741 return sqlst;
1742 else {
1743 gda_sql_statement_free (sqlst);
1744 return NULL;
1745 }
1746 }
1747
1748 /*
1749 * Modifies @ins
1750 * Returns: TRUE if rewrite is Ok
1751 */
1752 static gboolean
stmt_rewrite_insert_remove(GdaSqlStatementInsert * ins,GdaSet * params,GError ** error)1753 stmt_rewrite_insert_remove (GdaSqlStatementInsert *ins, GdaSet *params, GError **error)
1754 {
1755 if (!ins->values_list)
1756 /* nothing to do */
1757 return TRUE;
1758
1759 if (ins->values_list->next) {
1760 TO_IMPLEMENT;
1761 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
1762 GDA_SERVER_PROVIDER_DEFAULT_VALUE_HANDLING_ERROR,
1763 "%s", "Not yet implemented");
1764 return FALSE;
1765 }
1766
1767 GSList *fields, *values;
1768 for (fields = ins->fields_list, values = (GSList*) ins->values_list->data;
1769 fields && values; ){
1770 GdaHolder *h;
1771 GdaSqlExpr *expr = (GdaSqlExpr*) values->data;
1772 if (! expr->param_spec || ! expr->param_spec->is_param) {
1773 fields = fields->next;
1774 values = values->next;
1775 continue;
1776 }
1777 h = gda_set_get_holder (params, expr->param_spec->name);
1778 if (!h) {
1779 gchar *str;
1780 str = g_strdup_printf (_("Missing parameter '%s' to execute query"),
1781 expr->param_spec->name);
1782 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
1783 GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR,
1784 "%s", str);
1785 g_free (str);
1786 return FALSE;
1787 }
1788
1789 if (gda_holder_value_is_default (h)) {
1790 GSList *tmp;
1791
1792 gda_sql_field_free ((GdaSqlField*) fields->data);
1793 tmp = fields->next;
1794 ins->fields_list = g_slist_delete_link (ins->fields_list, fields);
1795 fields = tmp;
1796
1797 gda_sql_expr_free (expr);
1798 tmp = values->next;
1799 ins->values_list->data = g_slist_delete_link ((GSList*) ins->values_list->data,
1800 values);
1801 values = tmp;
1802 }
1803 else {
1804 fields = fields->next;
1805 values = values->next;
1806 }
1807 }
1808
1809 if (! ins->values_list->data) {
1810 g_slist_free (ins->values_list);
1811 ins->values_list = NULL;
1812 }
1813
1814 return TRUE;
1815 }
1816
1817 /*
1818 * Modifies @ins
1819 * Returns: TRUE if rewrite is Ok
1820 */
1821 static gboolean
stmt_rewrite_insert_default_keyword(GdaSqlStatementInsert * ins,GdaSet * params,GError ** error)1822 stmt_rewrite_insert_default_keyword (GdaSqlStatementInsert *ins, GdaSet *params, GError **error)
1823 {
1824 GSList *llist;
1825 for (llist = ins->values_list; llist; llist = llist->next) {
1826 GSList *values;
1827 for (values = (GSList*) llist->data;
1828 values;
1829 values = values->next){
1830 GdaHolder *h;
1831 GdaSqlExpr *expr = (GdaSqlExpr*) values->data;
1832 if (! expr->param_spec || ! expr->param_spec->is_param)
1833 continue;
1834 h = gda_set_get_holder (params, expr->param_spec->name);
1835 if (!h) {
1836 gchar *str;
1837 str = g_strdup_printf (_("Missing parameter '%s' to execute query"),
1838 expr->param_spec->name);
1839 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
1840 GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR,
1841 "%s", str);
1842 g_free (str);
1843 return FALSE;
1844 }
1845
1846 if (gda_holder_value_is_default (h)) {
1847 GdaSqlExpr *nexpr;
1848 nexpr = gda_sql_expr_new (GDA_SQL_ANY_PART (ins));
1849 g_value_set_string ((nexpr->value = gda_value_new (G_TYPE_STRING)),
1850 "DEFAULT");
1851 gda_sql_expr_free ((GdaSqlExpr*) values->data);
1852 values->data = nexpr;
1853 }
1854 }
1855 }
1856
1857 if (! ins->values_list->data) {
1858 g_slist_free (ins->values_list);
1859 ins->values_list = NULL;
1860 }
1861
1862 return TRUE;
1863 }
1864
1865 static gboolean
stmt_rewrite_update_default_keyword(GdaSqlStatementUpdate * upd,GdaSet * params,GError ** error)1866 stmt_rewrite_update_default_keyword (GdaSqlStatementUpdate *upd, GdaSet *params, GError **error)
1867 {
1868 GSList *values;
1869 for (values = upd->expr_list; values; values = values->next) {
1870 GdaHolder *h;
1871 GdaSqlExpr *expr = (GdaSqlExpr*) values->data;
1872 if (! expr->param_spec || ! expr->param_spec->is_param)
1873 continue;
1874 h = gda_set_get_holder (params, expr->param_spec->name);
1875 if (!h) {
1876 gchar *str;
1877 str = g_strdup_printf (_("Missing parameter '%s' to execute query"),
1878 expr->param_spec->name);
1879 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
1880 GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR,
1881 "%s", str);
1882 g_free (str);
1883 return FALSE;
1884 }
1885
1886 if (gda_holder_value_is_default (h)) {
1887 GdaSqlExpr *nexpr;
1888 nexpr = gda_sql_expr_new (GDA_SQL_ANY_PART (upd));
1889 g_value_set_string ((nexpr->value = gda_value_new (G_TYPE_STRING)),
1890 "DEFAULT");
1891 gda_sql_expr_free ((GdaSqlExpr*) values->data);
1892 values->data = nexpr;
1893 }
1894 }
1895
1896 return TRUE;
1897 }
1898
1899
1900 static gboolean
foreach_modify_param_type(GdaSqlAnyPart * part,GdaDataModel * model,G_GNUC_UNUSED GError ** error)1901 foreach_modify_param_type (GdaSqlAnyPart *part, GdaDataModel *model, G_GNUC_UNUSED GError **error)
1902 {
1903 if (part->type != GDA_SQL_ANY_EXPR)
1904 return TRUE;
1905
1906 GdaSqlParamSpec *pspec;
1907 pspec = ((GdaSqlExpr*) part)->param_spec;
1908 if (!pspec || !pspec->name)
1909 return TRUE;
1910
1911 if ((pspec->name [0] == '+') || (pspec->name [0] == '-')) {
1912 long int li;
1913 char *end;
1914 li = strtol ((pspec->name) + 1, &end, 10);
1915 if ((! *end) && (li <= G_MAXINT) && (li >= G_MININT) && (li < gda_data_model_get_n_columns (model))) {
1916 GdaColumn *col;
1917 col = gda_data_model_describe_column (model, (gint) li);
1918 if (col && (gda_column_get_g_type (col) != GDA_TYPE_NULL))
1919 pspec->g_type = gda_column_get_g_type (col);
1920 }
1921 }
1922 return TRUE;
1923 }
1924
1925 /*
1926 * _gda_modify_statement_param_types:
1927 * @stmt: a #GdaStatement
1928 * @model: a #GdaDataModel
1929 *
1930 * Modifies the parameters in @stmt which will be mapped to columns in @model (using the +<colindex> or
1931 * -<colindex> syntax) to map the column types of @model.
1932 *
1933 * Since: 5.2
1934 */
1935 void
_gda_modify_statement_param_types(GdaStatement * stmt,GdaDataModel * model)1936 _gda_modify_statement_param_types (GdaStatement *stmt, GdaDataModel *model)
1937 {
1938 g_return_if_fail (GDA_IS_STATEMENT (stmt));
1939 g_return_if_fail (GDA_IS_DATA_MODEL (model));
1940 GdaSqlStatement *sqlst;
1941
1942 sqlst = _gda_statement_get_internal_struct (stmt);
1943 if (!sqlst || !sqlst->contents)
1944 return;
1945
1946 if ((sqlst->stmt_type == GDA_SQL_STATEMENT_INSERT) ||
1947 (sqlst->stmt_type == GDA_SQL_STATEMENT_UPDATE) ||
1948 (sqlst->stmt_type == GDA_SQL_STATEMENT_DELETE)) {
1949 GdaSqlAnyPart *top;
1950 top = (GdaSqlAnyPart*) sqlst->contents;
1951 gda_sql_any_part_foreach (top, (GdaSqlForeachFunc) foreach_modify_param_type, model, NULL);
1952 }
1953 }
1954
1955 /**
1956 * gda_identifier_hash:
1957 * @id: an identifier string
1958 *
1959 * computes a hash string from @id, to be used in hash tables as a #GHashFunc
1960 *
1961 * Returns: a new hash
1962 */
1963 guint
gda_identifier_hash(const gchar * id)1964 gda_identifier_hash (const gchar *id)
1965 {
1966 const signed char *p = (signed char *) id;
1967 guint32 h = 0;
1968 gboolean lower = FALSE;
1969
1970 if (*p != '"') {
1971 lower = TRUE;
1972 h = g_ascii_tolower (*p);
1973 }
1974
1975 for (p += 1; *p && *p != '"'; p++) {
1976 if (lower)
1977 h = (h << 5) - h + g_ascii_tolower (*p);
1978 else
1979 h = (h << 5) - h + *p;
1980 }
1981 if (*p == '"' && *(p+1))
1982 g_warning ("Argument passed to %s() is not an SQL identifier", __FUNCTION__);
1983
1984 return h;
1985 }
1986
1987 /**
1988 * gda_identifier_equal:
1989 * @id1: an identifier string
1990 * @id2: an identifier string
1991 *
1992 * Does the same as strcmp(@id1, @id2), but handles the case where id1 and/or id2 are enclosed in double quotes.
1993 * can also be used in hash tables as a #GEqualFunc.
1994 *
1995 * Returns: %TRUE if @id1 and @id2 are equal.
1996 */
1997 gboolean
gda_identifier_equal(const gchar * id1,const gchar * id2)1998 gda_identifier_equal (const gchar *id1, const gchar *id2)
1999 {
2000 const gchar *ptr1, *ptr2;
2001 gboolean dq1 = FALSE, dq2 = FALSE;
2002
2003 if ((!id1 && id2) || (id1 && !id2))
2004 return FALSE;
2005 if (!id1 && !id2)
2006 return TRUE;
2007
2008 ptr1 = id1;
2009 if (*ptr1 == '"') {
2010 ptr1++;
2011 dq1 = TRUE;
2012 }
2013 ptr2 = id2;
2014 if (*ptr2 == '"') {
2015 ptr2++;
2016 dq2 = TRUE;
2017 }
2018 for (; *ptr1 && *ptr2; ptr1++, ptr2++) {
2019 gchar c1, c2;
2020 c1 = *ptr1;
2021 c2 = *ptr2;
2022 if (!dq1)
2023 c1 = g_ascii_tolower (c1);
2024 if (!dq2)
2025 c2 = g_ascii_tolower (c2);
2026 if (c1 != c2)
2027 return FALSE;
2028 }
2029 if (*ptr1 || *ptr2) {
2030 if (*ptr1 && (*ptr1 == '"'))
2031 return TRUE;
2032 if (*ptr2 && (*ptr2 == '"'))
2033 return TRUE;
2034 return FALSE;
2035 }
2036 return TRUE;
2037 }
2038
2039
2040 static char *concat_ident (const gchar *prefix, const gchar *ident);
2041
2042 static gchar *sql_start_words[] = {
2043 "ALTER",
2044 "SELECT",
2045 "INSERT",
2046 "DELETE",
2047 "UPDATE",
2048 "CREATE",
2049 "DROP",
2050 "ALTER",
2051 "COMMENT",
2052 "BEGIN",
2053 "COMMIT",
2054 "ROLLBACK"
2055 };
2056
2057 static gchar *sql_middle_words[] = {
2058 "FROM",
2059 "INNER",
2060 "JOIN",
2061 "LEFT",
2062 "OUTER",
2063 "RIGHT",
2064 "OUTER",
2065 "WHERE",
2066 "HAVING",
2067 "LIMIT",
2068 "AND",
2069 "OR",
2070 "NOT",
2071 "SET"
2072 };
2073
2074 static gchar *
prepare_sql_identifier_for_compare(gchar * str)2075 prepare_sql_identifier_for_compare (gchar *str)
2076 {
2077 if (!str || (*str == '"'))
2078 return str;
2079 else {
2080 gchar *ptr;
2081 for (ptr = str; *ptr; ptr++)
2082 *ptr = g_ascii_tolower (*ptr);
2083 return str;
2084 }
2085 }
2086
2087 static gint
cmp_func(gconstpointer a,gconstpointer b)2088 cmp_func (gconstpointer a, gconstpointer b)
2089 {
2090 return g_strcmp0 (*((gchar**) a), *((gchar**) b));
2091 }
2092
2093 /**
2094 * gda_completion_list_get:
2095 * @cnc: a #GdaConnection object
2096 * @sql: a partial SQL statement which is the context of the completion proposal
2097 * @start: starting position within @sql of the "token" to complete (starts at 0)
2098 * @end: ending position within @sql of the "token" to complete
2099 *
2100 * Creates an array of strings (terminated by a %NULL) corresponding to possible completions.
2101 * If no completion is available, then the returned array contains just one NULL entry, and
2102 * if it was not possible to try to compute a completions list, then %NULL is returned.
2103 *
2104 * Returns: (transfer full) (array zero-terminated=1) (nullable): a new array of strings, or %NULL (use g_strfreev() to free the returned array)
2105 */
2106 gchar **
gda_completion_list_get(GdaConnection * cnc,const gchar * sql,gint start,gint end)2107 gda_completion_list_get (GdaConnection *cnc, const gchar *sql, gint start, gint end)
2108 {
2109 GArray *compl = NULL;
2110 gchar *text;
2111 const GValue *cvalue;
2112
2113 if (!cnc)
2114 return NULL;
2115 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
2116 if (!sql || !(*sql))
2117 return NULL;
2118 if (end < start)
2119 return NULL;
2120
2121 /* init */
2122 compl = g_array_new (TRUE, TRUE, sizeof (gchar *));
2123 text = g_new (gchar, end - start + 2);
2124 memcpy (text, sql + start, end - start + 1); /* Flawfinder: ignore */
2125 text [end - start + 1] = 0;
2126
2127 if (start == 0) {
2128 /*
2129 * start of a statement => complete with SQL start of statement words
2130 */
2131 gsize len;
2132 gsize i;
2133 len = strlen (text);
2134 for (i = 0; i < (sizeof (sql_start_words) / sizeof (gchar*)); i++) {
2135 gsize clen = strlen (sql_start_words[i]);
2136 if (!g_ascii_strncasecmp (sql_start_words[i], text, MIN (clen, len))) {
2137 gchar *str;
2138 str = g_strdup (sql_start_words[i]);
2139 g_array_append_val (compl, str);
2140 }
2141 }
2142 goto compl_finished;
2143 }
2144
2145 if (!*text)
2146 goto compl_finished;
2147
2148 gchar *obj_schema, *obj_name;
2149 GValue *schema_value = NULL;
2150
2151 if (!_split_identifier_string (g_strdup (text), &obj_schema, &obj_name) &&
2152 !_split_identifier_string (g_strdup_printf ("%s\"", text), &obj_schema, &obj_name)) {
2153 if (text [strlen(text) - 1] == '.') {
2154 obj_schema = g_strdup (text);
2155 obj_schema [strlen(text) - 1] = 0;
2156 obj_name = g_strdup ("");
2157 }
2158 else
2159 goto compl_finished;
2160 }
2161
2162 prepare_sql_identifier_for_compare (obj_name);
2163 if (obj_schema)
2164 g_value_take_string ((schema_value = gda_value_new (G_TYPE_STRING)),
2165 prepare_sql_identifier_for_compare (obj_schema));
2166
2167 /*
2168 * complete with "table" or "schema.table"
2169 */
2170 GdaDataModel *model;
2171 GdaMetaStore *store;
2172 store = gda_connection_get_meta_store (cnc);
2173 if (schema_value)
2174 model = gda_meta_store_extract (store,
2175 "SELECT table_name FROM _tables WHERE table_schema = ##schema::string",
2176 NULL, "schema", schema_value, NULL);
2177 else
2178 model = gda_meta_store_extract (store,
2179 "SELECT table_name FROM _tables WHERE table_short_name != table_full_name",
2180 NULL);
2181 if (model) {
2182 gint i, nrows;
2183 gint len = strlen (obj_name);
2184
2185 nrows = gda_data_model_get_n_rows (model);
2186 for (i = 0; i < nrows; i++) {
2187 cvalue = gda_data_model_get_value_at (model, 0, i, NULL);
2188 if (cvalue) {
2189 const gchar *tname;
2190 tname = g_value_get_string (cvalue);
2191 if (!strncmp (tname, obj_name, len)) {
2192 gchar *str;
2193 if (schema_value)
2194 str = concat_ident (obj_schema, tname);
2195 else
2196 str = g_strdup (tname);
2197 g_array_append_val (compl, str);
2198 }
2199 }
2200 }
2201 g_object_unref (model);
2202 }
2203
2204 /*
2205 * complete with "table.column"
2206 */
2207 model = NULL;
2208 if (!schema_value)
2209 model = gda_meta_store_extract (store,
2210 "SELECT column_name FROM _columns", NULL);
2211 if (model) {
2212 gint i, nrows;
2213 gint len = strlen (obj_name);
2214
2215 nrows = gda_data_model_get_n_rows (model);
2216 for (i = 0; i < nrows; i++) {
2217 cvalue = gda_data_model_get_value_at (model, 0, i, NULL);
2218 if (cvalue) {
2219 const gchar *cname;
2220 cname = g_value_get_string (cvalue);
2221 if (!strncmp (cname, obj_name, len)) {
2222 gchar *str;
2223 str = g_strdup (cname);
2224 g_array_append_val (compl, str);
2225 }
2226 }
2227 }
2228 g_object_unref (model);
2229 }
2230
2231 /*
2232 * complete with "schema.table"
2233 */
2234 model = NULL;
2235 if (! schema_value)
2236 model = gda_meta_store_extract (store, "SELECT schema_name FROM _schemata", NULL);
2237 if (model) {
2238 gint i, nrows;
2239 gint len = strlen (obj_name);
2240
2241 nrows = gda_data_model_get_n_rows (model);
2242 for (i = 0; i < nrows; i++) {
2243 cvalue = gda_data_model_get_value_at (model, 0, i, NULL);
2244 if (cvalue) {
2245 const gchar *tname;
2246 tname = g_value_get_string (cvalue);
2247 if (!strncmp (tname, obj_name, len)) {
2248 char *str;
2249 GdaDataModel *m2;
2250 str = g_strdup (tname);
2251
2252 m2 = gda_meta_store_extract (store,
2253 "SELECT table_name FROM _tables WHERE table_schema = ##schema::string",
2254 NULL, "schema", cvalue, NULL);
2255 if (m2) {
2256 gint i2, nrows2;
2257 nrows2 = gda_data_model_get_n_rows (m2);
2258 for (i2 = 0; i2 < nrows2; i2++) {
2259 cvalue = gda_data_model_get_value_at (m2, 0, i2, NULL);
2260 if (cvalue) {
2261 gchar *str2;
2262 tname = g_value_get_string (cvalue);
2263 str2 = concat_ident (str, tname);
2264 g_array_append_val (compl, str2);
2265 }
2266 }
2267
2268 g_object_unref (m2);
2269 }
2270 g_free (str);
2271 }
2272 }
2273 }
2274 g_object_unref (model);
2275 if (compl->len > 0)
2276 goto compl_finished;
2277 }
2278
2279 if (schema_value)
2280 gda_value_free (schema_value);
2281 g_free (obj_name);
2282
2283 /*
2284 * middle of a statement and no completion yet => complete with SQL statement words
2285 */
2286 {
2287 gsize len;
2288 gsize i;
2289 len = strlen (text);
2290 for (i = 0; i < (sizeof (sql_middle_words) / sizeof (gchar*)); i++) {
2291 gsize clen = strlen (sql_middle_words[i]);
2292 if (!g_ascii_strncasecmp (sql_middle_words[i], text, MIN (clen, len))) {
2293 gchar *str;
2294 str = g_strdup (sql_middle_words[i]);
2295 g_array_append_val (compl, str);
2296 }
2297 }
2298 }
2299
2300 compl_finished:
2301 g_free (text);
2302 if (compl) {
2303 if (compl->len >= 1) {
2304 /* sort */
2305 gsize i;
2306 g_array_sort (compl, cmp_func);
2307
2308 /* remove duplicates if any */
2309 for (i = 1; i < compl->len; ) {
2310 gchar *current, *before;
2311 current = g_array_index (compl, gchar*, i);
2312 before = g_array_index (compl, gchar*, i - 1);
2313 if (!strcmp (current, before)) {
2314 g_free (current);
2315 g_array_remove_index (compl, i);
2316 }
2317 else
2318 i++;
2319 }
2320
2321 gchar **ptr;
2322 ptr = (gchar**) compl->data;
2323 g_array_free (compl, FALSE);
2324 return ptr;
2325 }
2326 else {
2327 g_array_free (compl, TRUE);
2328 return NULL;
2329 }
2330 }
2331 else
2332 return NULL;
2333 }
2334
2335 static char *
concat_ident(const char * prefix,const gchar * ident)2336 concat_ident (const char *prefix, const gchar *ident)
2337 {
2338 char *str;
2339 gint tlen = strlen (ident);
2340 gint plen = 0;
2341
2342 if (prefix)
2343 plen = strlen (prefix) + 1;
2344
2345 str = malloc (sizeof (char) * (plen + tlen + 1));
2346 if (prefix) {
2347 strcpy (str, prefix); /* Flawfinder: ignore */
2348 str [plen - 1] = '.';
2349 strcpy (str + plen, ident); /* Flawfinder: ignore */
2350 }
2351 else
2352 strcpy (str, ident); /* Flawfinder: ignore */
2353 return str;
2354 }
2355
2356 /**
2357 * gda_sql_identifier_split:
2358 * @id: an SQL identifier
2359 *
2360 * Splits @id into an array of it sub parts. @id's format has to be "<part>[.<part>[...]]" where
2361 * each part is either a text surrounded by double quotes which can contain upper and lower cases or
2362 * an SQL identifier in lower case.
2363 *
2364 * For example the <![CDATA["test.\"ATable\""]]> string will result in the array: <![CDATA[{"test", "\"ATable\"", NULL}]]>
2365 *
2366 * Returns: (transfer full) (array zero-terminated=1) (nullable): a new %NULL-terminated array of strings, or NULL (use g_strfreev() to free the returned array)
2367 */
2368 gchar **
gda_sql_identifier_split(const gchar * id)2369 gda_sql_identifier_split (const gchar *id)
2370 {
2371 gchar *copy;
2372 gchar *remain, *last;
2373 GArray *array = NULL;
2374
2375 g_return_val_if_fail (id && *id, NULL);
2376
2377 for (copy = g_strdup (id); copy; copy = remain) {
2378 if (_split_identifier_string (copy, &remain, &last)) {
2379 if (!array)
2380 array = g_array_new (TRUE, TRUE, sizeof (gchar *));
2381 g_array_prepend_val (array, last);
2382 }
2383 }
2384
2385 if (array)
2386 return (gchar **) g_array_free (array, FALSE);
2387 else
2388 return NULL;
2389 }
2390
2391 static gboolean _sql_identifier_needs_quotes (const gchar *str);
2392
2393 /**
2394 * gda_sql_identifier_quote:
2395 * @id: an SQL identifier
2396 * @cnc: (nullable): a #GdaConnection object, or %NULL
2397 * @prov: (nullable): a #GdaServerProvider object, or %NULL
2398 * @for_meta_store set to %TRUE if the returned string will be used in a #GdaMetaStore
2399 * @force_quotes: set to %TRUE to force the returned string to be quoted
2400 *
2401 * Use this function for any SQL identifier to make sure that:
2402 * <itemizedlist>
2403 * <listitem>
2404 * <para>it is correctly formatted
2405 * to be used with @cnc (if @cnc is %NULL, then some default SQL quoting rules will be applied,
2406 * similar to PostgreSQL's way) if @for_meta_store is %FALSE;
2407 * </para>
2408 * </listitem>
2409 * <listitem>
2410 * <para>it is correctly formatted to be used with the #GdaMetaStore's object associated to @cnc
2411 * is @for_meta_store is %TRUE.
2412 * </para>
2413 * </listitem>
2414 * </itemizedlist>
2415 *
2416 * The @force_quotes allow some control of how to interpret @id: if %FALSE, then @id will be left
2417 * unchanged most of the time (except for example if it's a reserved keyword), otherwise
2418 * if @force_quotes is %TRUE, then the returned string will most probably have quotes around it
2419 * to request that the database keep the case sensitiveness (but again, this may vary depending
2420 * on the database being accessed through @cnc).
2421 *
2422 * For example, the following table gives the result of this function depending on the arguments
2423 * when @cnc is %NULL (and @prov is also %NULL):
2424 * <table frame="all">
2425 * <tgroup cols="6" colsep="1" rowsep="1" align="justify">
2426 * <thead>
2427 * <row>
2428 * <entry>id</entry>
2429 * <entry>for_meta_store=%FALSE, force_quotes=%FALSE</entry>
2430 * <entry>for_meta_store=%TRUE, force_quotes=%FALSE</entry>
2431 * <entry>for_meta_store=%FALSE, force_quotes=%TRUE</entry>
2432 * <entry>for_meta_store=%TRUE, force_quotes=%TRUE</entry>
2433 * <entry>remark</entry>
2434 * </row>
2435 * </thead>
2436 * <tbody>
2437 * <row>
2438 * <entry>"double word"</entry>
2439 * <entry>"double word"</entry>
2440 * <entry>"double word"</entry>
2441 * <entry>"double word"</entry>
2442 * <entry>"double word"</entry>
2443 * <entry>non allowed character in SQL identifier</entry>
2444 * </row>
2445 * <row>
2446 * <entry>"CapitalTest"</entry>
2447 * <entry>"CapitalTest"</entry>
2448 * <entry>"CapitalTest"</entry>
2449 * <entry>"CapitalTest"</entry>
2450 * <entry>"CapitalTest"</entry>
2451 * <entry>Mixed case SQL identifier, already quoted</entry>
2452 * </row>
2453 * <row>
2454 * <entry>CapitalTest</entry>
2455 * <entry>CapitalTest</entry>
2456 * <entry>capitaltest</entry>
2457 * <entry>"CapitalTest"</entry>
2458 * <entry>"CapitalTest"</entry>
2459 * <entry>Mixed case SQL identifier, non quoted</entry>
2460 * </row>
2461 * <row>
2462 * <entry>"mytable"</entry>
2463 * <entry>"mytable"</entry>
2464 * <entry>mytable</entry>
2465 * <entry>"mytable"</entry>
2466 * <entry>mytable</entry>
2467 * <entry>All lowser case, quoted</entry>
2468 * </row>
2469 * <row>
2470 * <entry>mytable</entry>
2471 * <entry>mytable</entry>
2472 * <entry>mytable</entry>
2473 * <entry>"mytable"</entry>
2474 * <entry>mytable</entry>
2475 * <entry>All lowser case</entry>
2476 * </row>
2477 * <row>
2478 * <entry>MYTABLE</entry>
2479 * <entry>MYTABLE</entry>
2480 * <entry>mytable</entry>
2481 * <entry>"MYTABLE"</entry>
2482 * <entry>"MYTABLE"</entry>
2483 * <entry>All upper case</entry>
2484 * </row>
2485 * <row>
2486 * <entry>"MYTABLE"</entry>
2487 * <entry>"MYTABLE"</entry>
2488 * <entry>"MYTABLE"</entry>
2489 * <entry>"MYTABLE"</entry>
2490 * <entry>"MYTABLE"</entry>
2491 * <entry>All upper case, quoted</entry>
2492 * </row>
2493 * <row>
2494 * <entry>desc</entry>
2495 * <entry>"desc"</entry>
2496 * <entry>"desc"</entry>
2497 * <entry>"desc"</entry>
2498 * <entry>"desc"</entry>
2499 * <entry>SQL reserved keyword</entry>
2500 * </row>
2501 * <row>
2502 * <entry>5ive</entry>
2503 * <entry>"5ive"</entry>
2504 * <entry>"5ive"</entry>
2505 * <entry>"5ive"</entry>
2506 * <entry>"5ive"</entry>
2507 * <entry>SQL identifier starting with a digit</entry>
2508 * </row>
2509 * </tbody>
2510 * </tgroup>
2511 * </table>
2512 *
2513 * Here are a few examples of when and how to use this function:
2514 * <itemizedlist>
2515 * <listitem>
2516 * <para>
2517 * When creating a table, the user has entered the table name, this function can be used to
2518 * create a valid SQL identifier from the user provided table name:
2519 * <programlisting>
2520 * gchar *user_sqlid=...
2521 * gchar *valid_sqlid = gda_sql_identifier_quote (user_sqlid, cnc, NULL, FALSE, FALSE);
2522 * gchar *sql = g_strdup_printf ("CREATE TABLE %s ...", valid_sqlid);
2523 * g_free (valid_sqlid);
2524 * </programlisting>
2525 * Note that this is an illustration and creating a table should be sone using a #GdaServerOperation
2526 * object.
2527 * </para>
2528 * </listitem>
2529 * <listitem>
2530 * <para>
2531 * When updating the meta data associated to a table which has been created with the code
2532 * above:
2533 * <programlisting>
2534 * GValue table_name_value = { 0 };
2535 * gchar* column_names[] = { (gchar*)"table_name" };
2536 * GValue* column_values[] = { &table_name_value };
2537 * GdaMetaContext mcontext = { (gchar*)"_tables", 1, column_names, column_values };
2538 * g_value_init (&table_name_value, G_TYPE_STRING);
2539 * g_value_take_string (&table_name_value, gda_sql_identifier_quote (user_sqlid, cnc, NULL, TRUE, FALSE);
2540 * gda_connection_update_meta_store (cnc, &mcontext, NULL);
2541 * g_value_reset (&table_name_value);
2542 * </programlisting>
2543 * </para>
2544 * </listitem>
2545 * <listitem>
2546 * <para>
2547 * When using a #GdaMetaStruct object to fetch information about a table (which has been created with
2548 * the code above):
2549 * <programlisting>
2550 * GValue table_name_value = { 0 };
2551 * g_value_init (&table_name_value, G_TYPE_STRING);
2552 * g_value_take_string (&table_name_value, gda_sql_identifier_quote (user_sqlid, cnc, NULL, TRUE, FALSE);
2553 * GdaMetaDbObject *dbo;
2554 * dbo = gda_meta_struct_complement (mstruct, GDA_META_DB_TABLE, NULL, NULL, &table_name_value, NULL);
2555 * g_value_reset (&table_name_value);
2556 * </programlisting>
2557 * </para>
2558 * </listitem>
2559 * </itemizedlist>
2560 *
2561 *
2562 * Note that @id must not be a composed SQL identifier (such as "mytable.mycolumn" which should be
2563 * treated as the "mytable" and "mycolumn" SQL identifiers). If unsure, use gda_sql_identifier_split().
2564 *
2565 * Also note that if @cnc is %NULL, then it's possible to pass an non %NULL @prov to have a result specific
2566 * to @prov.
2567 *
2568 * For more information, see the <link linkend="gen:sql_identifiers">SQL identifiers and abstraction</link> and
2569 * <link linkend="information_schema:sql_identifiers">SQL identifiers in meta data</link> sections.
2570 *
2571 * Returns: the representation of @id ready to be used in SQL statement, as a new string,
2572 * or %NULL if @id is in a wrong format
2573 *
2574 * Since: 4.0.3
2575 */
2576 gchar *
gda_sql_identifier_quote(const gchar * id,GdaConnection * cnc,GdaServerProvider * prov,gboolean for_meta_store,gboolean force_quotes)2577 gda_sql_identifier_quote (const gchar *id, GdaConnection *cnc, GdaServerProvider *prov,
2578 gboolean for_meta_store, gboolean force_quotes)
2579 {
2580 g_return_val_if_fail (id && *id, NULL);
2581 if (prov)
2582 g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (prov), NULL);
2583 if (cnc) {
2584 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
2585 if (prov)
2586 g_return_val_if_fail (gda_connection_get_provider (cnc) == prov, NULL);
2587 else
2588 prov = gda_connection_get_provider (cnc);
2589 }
2590
2591 if ((*id == '*') && (! id [1]))
2592 return g_strdup (id);
2593
2594 if (prov && PROV_CLASS (prov)->identifier_quote)
2595 return PROV_CLASS (prov)->identifier_quote (prov, cnc, id,
2596 for_meta_store, force_quotes);
2597
2598 if (for_meta_store) {
2599 gchar *tmp, *ptr;
2600 tmp = _remove_quotes (g_strdup (id));
2601 if (is_keyword (tmp)) {
2602 ptr = gda_sql_identifier_force_quotes (tmp);
2603 g_free (tmp);
2604 return ptr;
2605 }
2606 else if (force_quotes) {
2607 /* quote if non LC characters or digits at the 1st char or non allowed characters */
2608 for (ptr = tmp; *ptr; ptr++) {
2609 if (((*ptr >= 'a') && (*ptr <= 'z')) ||
2610 ((*ptr >= '0') && (*ptr <= '9') && (ptr != tmp)) ||
2611 (*ptr == '_'))
2612 continue;
2613 else {
2614 ptr = gda_sql_identifier_force_quotes (tmp);
2615 g_free (tmp);
2616 return ptr;
2617 }
2618 }
2619 return tmp;
2620 }
2621 else {
2622 for (ptr = tmp; *ptr; ptr++) {
2623 if (*id == '"') {
2624 if (((*ptr >= 'a') && (*ptr <= 'z')) ||
2625 ((*ptr >= '0') && (*ptr <= '9') && (ptr != tmp)) ||
2626 (*ptr == '_'))
2627 continue;
2628 else {
2629 ptr = gda_sql_identifier_force_quotes (tmp);
2630 g_free (tmp);
2631 return ptr;
2632 }
2633 }
2634 else if ((*ptr >= 'A') && (*ptr <= 'Z'))
2635 *ptr += 'a' - 'A';
2636 else if ((*ptr >= '0') && (*ptr <= '9') && (ptr == tmp)) {
2637 ptr = gda_sql_identifier_force_quotes (tmp);
2638 g_free (tmp);
2639 return ptr;
2640 }
2641 }
2642 return tmp;
2643 }
2644 }
2645 else {
2646 /* default SQL standard */
2647 if (*id == '"') {
2648 /* there are already some quotes */
2649 return g_strdup (id);
2650 }
2651 if (is_keyword (id) || _sql_identifier_needs_quotes (id) || force_quotes)
2652 return gda_sql_identifier_force_quotes (id);
2653
2654 /* nothing to do */
2655 return g_strdup (id);
2656 }
2657 }
2658
2659 static gboolean
_sql_identifier_needs_quotes(const gchar * str)2660 _sql_identifier_needs_quotes (const gchar *str)
2661 {
2662 const gchar *ptr;
2663
2664 g_return_val_if_fail (str, FALSE);
2665 for (ptr = str; *ptr; ptr++) {
2666 /* quote if 1st char is a number */
2667 if ((*ptr <= '9') && (*ptr >= '0')) {
2668 if (ptr == str)
2669 return TRUE;
2670 continue;
2671 }
2672 if (((*ptr >= 'A') && (*ptr <= 'Z')) ||
2673 ((*ptr >= 'a') && (*ptr <= 'z')))
2674 continue;
2675
2676 if ((*ptr != '$') && (*ptr != '_') && (*ptr != '#'))
2677 return TRUE;
2678 }
2679 return FALSE;
2680 }
2681
2682 /*
2683 * RFC 1738 defines that these characters should be escaped, as well
2684 * any non-US-ASCII character or anything between 0x00 - 0x1F.
2685 */
2686 static char rfc1738_unsafe_chars[] =
2687 {
2688 (char) 0x3C, /* < */
2689 (char) 0x3E, /* > */
2690 (char) 0x22, /* " */
2691 (char) 0x23, /* # */
2692 (char) 0x25, /* % */
2693 (char) 0x7B, /* { */
2694 (char) 0x7D, /* } */
2695 (char) 0x7C, /* | */
2696 (char) 0x5C, /* \ */
2697 (char) 0x5E, /* ^ */
2698 (char) 0x7E, /* ~ */
2699 (char) 0x5B, /* [ */
2700 (char) 0x5D, /* ] */
2701 (char) 0x60, /* ` */
2702 (char) 0x27, /* ' */
2703 (char) 0x20 /* space */
2704 };
2705
2706 static char rfc1738_reserved_chars[] =
2707 {
2708 (char) 0x3b, /* ; */
2709 (char) 0x2f, /* / */
2710 (char) 0x3f, /* ? */
2711 (char) 0x3a, /* : */
2712 (char) 0x40, /* @ */
2713 (char) 0x3d, /* = */
2714 (char) 0x26 /* & */
2715 };
2716
2717 /**
2718 * gda_rfc1738_encode:
2719 * @string: a string to encode
2720 *
2721 * Encodes @string using the RFC 1738 recommendations: the
2722 * <constant><>"#%{}|\^~[]'`;/?:@=&</constant> and space characters are replaced by
2723 * <constant>"%%ab"</constant> where
2724 * <constant>ab</constant> is the hexadecimal number corresponding to the character.
2725 *
2726 * Returns: (transfer full): a new string
2727 */
2728 gchar *
gda_rfc1738_encode(const gchar * string)2729 gda_rfc1738_encode (const gchar *string)
2730 {
2731 gchar *ret, *wptr;
2732 const gchar *rptr;
2733 gsize i;
2734
2735 if (!string)
2736 return NULL;
2737 if (!*string)
2738 return g_strdup ("");
2739
2740 ret = g_new0 (gchar, (strlen (string) * 3) + 1);
2741 for (wptr = ret, rptr = string; *rptr; rptr++) {
2742 gboolean enc = FALSE;
2743
2744 /* RFC 1738 defines these chars as unsafe */
2745 for (i = 0; i < sizeof (rfc1738_reserved_chars) / sizeof (char); i++) {
2746 if (*rptr == rfc1738_reserved_chars [i]) {
2747 enc = TRUE;
2748 break;
2749 }
2750 }
2751 if (!enc) {
2752 for (i = 0; i < sizeof (rfc1738_unsafe_chars) / sizeof (char); i++) {
2753 if (*rptr == rfc1738_unsafe_chars [i]) {
2754 enc = TRUE;
2755 break;
2756 }
2757 }
2758 }
2759 if (!enc) {
2760 /* RFC 1738 says any control chars (0x00-0x1F) are encoded */
2761 if ((unsigned char) *rptr <= (unsigned char) 0x1F)
2762 enc = TRUE;
2763 /* RFC 1738 says 0x7f is encoded */
2764 else if (*rptr == (char) 0x7F)
2765 enc = TRUE;
2766 /* RFC 1738 says any non-US-ASCII are encoded */
2767 else if (((unsigned char) *rptr >= (unsigned char) 0x80))
2768 enc = TRUE;
2769 }
2770 if (!enc && (*rptr == '=')) {
2771 /* also encode the '=' */
2772 enc = TRUE;
2773 }
2774
2775 if (enc) {
2776 sprintf (wptr, "%%%02x", (unsigned char) *rptr); /* Flawfinder: ignore */
2777 wptr += 3;
2778 }
2779 else {
2780 *wptr = *rptr;
2781 wptr++;
2782 }
2783 }
2784 return ret;
2785 }
2786
2787 /**
2788 * gda_rfc1738_decode:
2789 * @string: a string to decode
2790 *
2791 * Decodes @string using the RFC 1738 recommendations: the
2792 * <constant><>"#%{}|\^~[]'`;/?:@=&</constant> and space characters are replaced by
2793 * <constant>"%%ab"</constant> where
2794 * <constant>ab</constant> is the hexadecimal number corresponding to the character.
2795 *
2796 * @string should respect the RFC 1738 encoding. If this is not the case (for example if there
2797 * is a "%2z" because 2z is not an hexadecimal value), then the part with the problem
2798 * is not decoded, and the function returns FALSE.
2799 *
2800 * @string is decoded in place, no new string gets created.
2801 *
2802 * Returns: %TRUE if no error occurred.
2803 */
2804 gboolean
gda_rfc1738_decode(gchar * string)2805 gda_rfc1738_decode (gchar *string)
2806 {
2807 gchar *wptr, *rptr;
2808
2809 if (!string || !*string)
2810 return TRUE;
2811
2812 for (wptr = rptr = string; *rptr; wptr++, rptr++) {
2813 *wptr = *rptr;
2814 if (*rptr == '%') {
2815 rptr++;
2816 if ((((*rptr >= 'A') && (*rptr <= 'F')) ||
2817 ((*rptr >= 'a') && (*rptr <= 'f')) ||
2818 ((*rptr >= '0') && (*rptr <= '9'))) &&
2819 (((rptr[1] >= 'A') && (rptr[1] <= 'F')) ||
2820 ((rptr[1] >= 'a') && (rptr[1] <= 'f')) ||
2821 ((rptr[1] >= '0') && (rptr[1] <= '9')))) {
2822 *wptr = 0;
2823 if ((*rptr >= 'A') && (*rptr <= 'F'))
2824 *wptr = *rptr - 'A' + 10;
2825 else if ((*rptr >= 'a') && (*rptr <= 'f'))
2826 *wptr = *rptr - 'a' + 10;
2827 else
2828 *wptr = *rptr - '0';
2829 rptr++;
2830 *wptr = *wptr << 4; /* multiply by 16 */
2831 if (((*rptr >= 'A') && (*rptr <= 'F')) ||
2832 ((*rptr >= 'a') && (*rptr <= 'f')) ||
2833 ((*rptr >= '0') && (*rptr <= '9'))) {
2834 if ((*rptr >= 'A') && (*rptr <= 'F'))
2835 *wptr += *rptr - 'A' + 10;
2836 else if ((*rptr >= 'a') && (*rptr <= 'f'))
2837 *wptr += *rptr - 'a' + 10;
2838 else
2839 *wptr += *rptr - '0';
2840 }
2841 }
2842 else {
2843 /* error */
2844 /* TODO: Actually return this? retval = FALSE; murrayc */
2845 rptr--;
2846 }
2847 }
2848 }
2849 *wptr = 0;
2850 return TRUE;
2851 }
2852
2853
2854 /**
2855 * gda_dsn_split:
2856 * @string: a string in the "[<username>[:<password>]@]<DSN>" form
2857 * @out_dsn: a place to store the new string containing the <DSN> part
2858 * @out_username: a place to store the new string containing the <username> part
2859 * @out_password: a place to store the new string containing the <password> part
2860 *
2861 * Extract the DSN, username and password from @string. in @string, the various parts are strings
2862 * which are expected to be encoded using an RFC 1738 compliant encoding. If they are specified,
2863 * the returned username and password strings are correctly decoded.
2864 *
2865 * @out_username and @out_password may be set to %NULL depending on @string's format.
2866 */
2867 void
gda_dsn_split(const gchar * string,gchar ** out_dsn,gchar ** out_username,gchar ** out_password)2868 gda_dsn_split (const gchar *string, gchar **out_dsn, gchar **out_username, gchar **out_password)
2869 {
2870 const gchar *ptr;
2871 g_return_if_fail (string);
2872 g_return_if_fail (out_dsn);
2873 g_return_if_fail (out_username);
2874 g_return_if_fail (out_password);
2875
2876 *out_dsn = NULL;
2877 *out_username = NULL;
2878 *out_password = NULL;
2879 for (ptr = string; *ptr; ptr++) {
2880 if (*ptr == '@') {
2881 const gchar *tmp = ptr;
2882 *out_dsn = g_strdup (ptr+1);
2883 for (ptr = string; ptr < tmp; ptr++) {
2884 if (*ptr == ':') {
2885 *out_username = g_strndup (string, ptr - string);
2886 *out_password = g_strndup (ptr+1, tmp - ptr - 1);
2887 }
2888 }
2889 if (!*out_username)
2890 *out_username = g_strndup (string, tmp - string);
2891 break;
2892 }
2893 }
2894 if (!*out_dsn)
2895 *out_dsn = g_strdup (string);
2896
2897 /* RFC 1738 decode username and password strings */
2898 gda_rfc1738_decode (*out_username);
2899 gda_rfc1738_decode (*out_password);
2900 }
2901
2902 /**
2903 * gda_connection_string_split:
2904 * @string: a string in the "[<provider>://][<username>[:<password>]@]<connection_params>" form
2905 * @out_cnc_params: a place to store the new string containing the <connection_params> part
2906 * @out_provider: a place to store the new string containing the <provider> part
2907 * @out_username: a place to store the new string containing the <username> part
2908 * @out_password: (nullable): a place to store the new string containing the <password> part, or %NULL
2909 *
2910 * Extract the provider, connection parameters, username and password from @string.
2911 * in @string, the various parts are strings
2912 * which are expected to be encoded using an RFC 1738 compliant encoding. If they are specified,
2913 * the returned provider, username and password strings are correctly decoded.
2914 *
2915 * For example all the following connection strings:
2916 * <programlisting><![CDATA[
2917 PostgreSQL://meme:pass@DB_NAME=mydb;HOST=server
2918 PostgreSQL://meme@DB_NAME=mydb;HOST=server;PASSWORD=pass
2919 PostgreSQL://meme@DB_NAME=mydb;PASSWORD=pass;HOST=server
2920 PostgreSQL://meme@PASSWORD=pass;DB_NAME=mydb;HOST=server
2921 PostgreSQL://DB_NAME=mydb;HOST=server;USERNAME=meme;PASSWORD=pass
2922 PostgreSQL://DB_NAME=mydb;HOST=server;PASSWORD=pass;USERNAME=meme
2923 PostgreSQL://DB_NAME=mydb;USERNAME=meme;PASSWORD=pass;HOST=server
2924 PostgreSQL://PASSWORD=pass;USERNAME=meme;DB_NAME=mydb;HOST=server
2925 PostgreSQL://:pass@USERNAME=meme;DB_NAME=mydb;HOST=server
2926 PostgreSQL://:pass@DB_NAME=mydb;HOST=server;USERNAME=meme]]></programlisting>
2927 *
2928 * will return the following new strings (double quotes added here to delimit strings):
2929 * <programlisting><![CDATA[
2930 out_cnc_params: "DB_NAME=mydb;HOST=server"
2931 out_provider: "PostgreSQL"
2932 out_username: "meme"
2933 out_password: "pass"]]></programlisting>
2934 */
2935 void
gda_connection_string_split(const gchar * string,gchar ** out_cnc_params,gchar ** out_provider,gchar ** out_username,gchar ** out_password)2936 gda_connection_string_split (const gchar *string, gchar **out_cnc_params, gchar **out_provider,
2937 gchar **out_username, gchar **out_password)
2938 {
2939 const gchar *ptr;
2940 const gchar *ap;
2941 g_return_if_fail (string);
2942 g_return_if_fail (out_cnc_params);
2943 g_return_if_fail (out_provider);
2944 g_return_if_fail (out_username);
2945
2946 *out_cnc_params = NULL;
2947 *out_provider = NULL;
2948 *out_username = NULL;
2949 if (out_password)
2950 *out_password = NULL;
2951 for (ap = ptr = string; *ptr; ptr++) {
2952 if ((ap == string) && (*ptr == '/') && (ptr[1] == '/')) {
2953 if ((ptr == string) || (ptr[-1] != ':')) {
2954 g_free (*out_cnc_params); *out_cnc_params = NULL;
2955 g_free (*out_provider); *out_provider = NULL;
2956 g_free (*out_username); *out_username = NULL;
2957 if (out_password) {
2958 g_free (*out_password);
2959 *out_password = NULL;
2960 }
2961 return;
2962 }
2963 *out_provider = g_strndup (string, ptr - string - 1);
2964 ap = ptr+2;
2965 ptr++;
2966 }
2967
2968 if (*ptr == '@') {
2969 const gchar *tmp = ptr;
2970 *out_cnc_params = g_strdup (ptr+1);
2971 for (ptr = ap; ptr < tmp; ptr++) {
2972 if (*ptr == ':') {
2973 *out_username = g_strndup (ap, ptr - ap);
2974 if (out_password)
2975 *out_password = g_strndup (ptr+1, tmp - ptr - 1);
2976 }
2977 }
2978 if (!*out_username)
2979 *out_username = g_strndup (ap, tmp - ap);
2980 break;
2981 }
2982 }
2983 if (!*out_cnc_params)
2984 *out_cnc_params = g_strdup (ap);
2985
2986 if (*out_cnc_params) {
2987 gchar *pos;
2988
2989 pos = strstr (*out_cnc_params, "USERNAME=");
2990 while (pos) {
2991 if (((pos > *out_cnc_params) && (*(pos-1) == ';')) ||
2992 (pos == *out_cnc_params)) {
2993 for (ptr = pos + 9; ptr && *ptr != '\0' && *ptr != ';'; ptr++);
2994 if (ptr != pos + 9)
2995 *out_username = g_strndup (pos + 9, ptr - (pos + 9));
2996
2997 if (*ptr)
2998 memmove (pos, ptr + 1, strlen (ptr));
2999 else
3000 *pos = 0;
3001 gchar *tmp;
3002 gint len;
3003 tmp = *out_cnc_params;
3004 len = strlen (tmp) - 1;
3005 if (tmp [len] == ';')
3006 tmp [len] = 0;
3007 break;
3008 }
3009 pos = strstr (pos + 9, "USERNAME=");
3010 }
3011
3012 pos = strstr (*out_cnc_params, "PASSWORD=");
3013 while (pos) {
3014 if (((pos > *out_cnc_params) && (*(pos-1) == ';')) ||
3015 (pos == *out_cnc_params)) {
3016 for (ptr = pos + 9; ptr && *ptr != '\0' && *ptr != ';'; ptr++);
3017 if (ptr != pos + 9) {
3018 if (out_password)
3019 *out_password = g_strndup (pos + 9, ptr - (pos + 9));
3020 }
3021
3022 if (*ptr)
3023 memmove (pos, ptr + 1, strlen (ptr));
3024 else
3025 *pos = 0;
3026 gchar *tmp;
3027 gint len;
3028 tmp = *out_cnc_params;
3029 len = strlen (tmp) - 1;
3030 if (tmp [len] == ';')
3031 tmp [len] = 0;
3032 break;
3033 }
3034 pos = strstr (pos + 9, "PASSWORD=");
3035 }
3036 }
3037
3038 /* RFC 1738 decode provider, username and password strings */
3039 gda_rfc1738_decode (*out_provider);
3040 gda_rfc1738_decode (*out_username);
3041 if (out_password)
3042 gda_rfc1738_decode (*out_password);
3043 }
3044
3045 /*
3046 * NB: @sep must not be zero
3047 */
3048 static gboolean
_parse_formatted_date(GDate * gdate,const gchar * value,GDateDMY first,GDateDMY second,GDateDMY third,gchar sep,const char ** out_endptr)3049 _parse_formatted_date (GDate *gdate, const gchar *value, GDateDMY first, GDateDMY second, GDateDMY third, gchar sep,
3050 const char **out_endptr)
3051 {
3052 GDateYear year = G_DATE_BAD_YEAR;
3053 GDateMonth month = G_DATE_BAD_MONTH;
3054 GDateDay day = G_DATE_BAD_DAY;
3055 unsigned long int tmp;
3056 const char *endptr;
3057 guint8 iter;
3058 guint16 parsed_values [3] = {0, 0, 0};
3059
3060 g_date_clear (gdate, 1);
3061
3062 /* checks */
3063 if ((first == second) || (first == third) || (second == third)) {
3064 g_warning (_("The 'first', 'second' and 'third' arguments must be different"));
3065 return FALSE;
3066 }
3067 if ((sep >= '0') && (sep <= '9')) {
3068 if (sep)
3069 g_warning (_("Invalid separator '%c'"), sep);
3070 else
3071 g_warning (_("Invalid null separator"));
3072 return FALSE;
3073 }
3074
3075 /* 1st number */
3076 for (endptr = value, tmp = 0, iter = 0; (*endptr >= '0') && (*endptr <= '9') && (iter < 4); endptr++)
3077 tmp = tmp * 10 + *endptr - '0';
3078 parsed_values[0] = tmp;
3079 if (*endptr != sep)
3080 return FALSE;
3081
3082 /* 2nd number */
3083 endptr++;
3084 for (tmp = 0, iter = 0; (*endptr >= '0') && (*endptr <= '9') && (iter < 4); endptr++)
3085 tmp = tmp * 10 + *endptr - '0';
3086 parsed_values[1] = tmp;
3087 if (*endptr != sep)
3088 return FALSE;
3089
3090 /* 3rd number */
3091 endptr++;
3092 for (tmp = 0, iter = 0; (*endptr >= '0') && (*endptr <= '9') && (iter < 4); endptr++)
3093 tmp = tmp * 10 + *endptr - '0';
3094 parsed_values[2] = tmp;
3095
3096 /* reordering */
3097 guint16 rmonth = 0, rday = 0;
3098 switch (first) {
3099 case G_DATE_YEAR:
3100 year = parsed_values[0];
3101 break;
3102 case G_DATE_MONTH:
3103 rmonth = parsed_values[0];
3104 break;
3105 case G_DATE_DAY:
3106 rday = parsed_values[0];
3107 break;
3108 default:
3109 g_warning (_("Unknown GDateDMY value %u"), first);
3110 return FALSE;
3111 }
3112
3113 switch (second) {
3114 case G_DATE_YEAR:
3115 year = parsed_values[1];
3116 break;
3117 case G_DATE_MONTH:
3118 rmonth = parsed_values[1];
3119 break;
3120 case G_DATE_DAY:
3121 rday = parsed_values[1];
3122 break;
3123 default:
3124 g_warning (_("Unknown GDateDMY value %u"), second);
3125 return FALSE;
3126 }
3127
3128 switch (third) {
3129 case G_DATE_YEAR:
3130 year = parsed_values[2];
3131 break;
3132 case G_DATE_MONTH:
3133 rmonth = parsed_values[2];
3134 break;
3135 case G_DATE_DAY:
3136 rday = parsed_values[2];
3137 break;
3138 default:
3139 g_warning (_("Unknown GDateDMY value %u"), third);
3140 return FALSE;
3141 }
3142
3143 /* checks */
3144 month = rmonth > 0 ? (rmonth <= G_DATE_DECEMBER ? rmonth : G_DATE_BAD_MONTH) : G_DATE_BAD_MONTH;
3145 if (month == G_DATE_BAD_MONTH)
3146 return FALSE;
3147 day = rday > 0 ? (rday <= G_MAXUINT8 ? rday : G_DATE_BAD_DAY) : G_DATE_BAD_DAY;
3148 if (day == G_DATE_BAD_DAY)
3149 return FALSE;
3150
3151 if (g_date_valid_dmy (day, month, year)) {
3152 g_date_set_dmy (gdate, day, month, year);
3153 if (out_endptr)
3154 *out_endptr = endptr;
3155 return TRUE;
3156 }
3157 else
3158 return FALSE;
3159 }
3160
3161 static gboolean
_parse_iso8601_date(GDate * gdate,const gchar * value,const char ** out_endptr)3162 _parse_iso8601_date (GDate *gdate, const gchar *value, const char **out_endptr)
3163 {
3164 return _parse_formatted_date (gdate, value, G_DATE_YEAR, G_DATE_MONTH, G_DATE_DAY, '-', out_endptr);
3165 }
3166
3167 /**
3168 * gda_parse_iso8601_date:
3169 * @gdate: a pointer to a #GDate structure which will be filled
3170 * @value: a string
3171 *
3172 * Extracts date parts from @value, and sets @gdate's contents
3173 *
3174 * Accepted date format is "YYYY-MM-DD" (more or less than 4 digits for years and
3175 * less than 2 digits for month and day are accepted). Years must be in the 1-65535 range,
3176 * a limitation imposed by #GDate.
3177 *
3178 * Returns: %TRUE if @value has been sucessfuly parsed as a valid date (see g_date_valid()).
3179 */
3180 gboolean
gda_parse_iso8601_date(GDate * gdate,const gchar * value)3181 gda_parse_iso8601_date (GDate *gdate, const gchar *value)
3182 {
3183 g_return_val_if_fail (gdate, FALSE);
3184
3185 const char *endptr;
3186 if (!value)
3187 return FALSE;
3188
3189 if (! _parse_iso8601_date (gdate, value, &endptr) || *endptr)
3190 return FALSE;
3191 else
3192 return TRUE;
3193 }
3194
3195 /**
3196 * gda_parse_formatted_date:
3197 * @gdate: a pointer to a #GDate structure which will be filled
3198 * @value: a string to be parsed
3199 * @first: a #GDateDMY specifying which of year, month or day appears first (in the first bytes) in @value
3200 * @second: a #GDateDMY specifying which of year, month or day appears second (in the first bytes) in @value
3201 * @third: a #GDateDMY specifying which of year, month or day appears third (in the first bytes) in @value
3202 * @sep: spcifies the expected separator character bewteen year, month and day (for example '-')
3203 *
3204 * This function is similar to gda_parse_iso8601_date() (with @first being @G_DATE_YEAR, @second being @G_DATE_MONTH,
3205 * @third being @G_DATE_DAY and @sep being '-') but allows one to specify the expected date format.
3206 *
3207 * Returns: %TRUE if @value has been sucessfuly parsed as a valid date (see g_date_valid()).
3208 *
3209 * Since: 5.2
3210 */
3211 gboolean
gda_parse_formatted_date(GDate * gdate,const gchar * value,GDateDMY first,GDateDMY second,GDateDMY third,gchar sep)3212 gda_parse_formatted_date (GDate *gdate, const gchar *value, GDateDMY first, GDateDMY second, GDateDMY third, gchar sep)
3213 {
3214 g_return_val_if_fail (gdate, FALSE);
3215
3216 const char *endptr;
3217 if (!value)
3218 return FALSE;
3219
3220 if (! _parse_formatted_date (gdate, value, first, second, third, sep, &endptr))
3221 return FALSE;
3222 if (*endptr)
3223 return FALSE;
3224 return TRUE;
3225 }
3226
3227
3228 static gboolean
_parse_iso8601_time(GdaTime * timegda,const gchar * value,gchar sep,glong timezone,const char ** out_endptr)3229 _parse_iso8601_time (GdaTime *timegda, const gchar *value, gchar sep, glong timezone, const char **out_endptr)
3230 {
3231 unsigned long int tmp;
3232 const char *endptr;
3233
3234 memset (timegda, 0, sizeof (GdaTime));
3235 timegda->timezone = timezone;
3236
3237 if ((*value < '0') || (*value > '9'))
3238 return FALSE;
3239
3240 /* hour */
3241 guint8 iter;
3242 for (iter = 0, tmp = 0, endptr = value; (*endptr >= '0') && (*endptr <= '9') && (iter < 2); iter++, endptr++) {
3243 tmp = tmp * 10 + *endptr - '0';
3244 if (tmp > 23)
3245 return FALSE;
3246 }
3247 timegda->hour = tmp;
3248 if ((sep && *endptr != sep) || !*endptr)
3249 return FALSE;
3250
3251 /* minutes */
3252 if (sep)
3253 endptr++;
3254 for (tmp = 0, iter = 0 ; (*endptr >= '0') && (*endptr <= '9') && (iter < 2); iter ++, endptr++) {
3255 tmp = tmp * 10 + *endptr - '0';
3256 if (tmp > 59)
3257 return FALSE;
3258 }
3259 timegda->minute = tmp;
3260 if ((sep && *endptr != sep) || !*endptr)
3261 return FALSE;
3262
3263 /* seconds */
3264 if (sep)
3265 endptr++;
3266 for (tmp = 0, iter = 0 ; (*endptr >= '0') && (*endptr <= '9') && (iter < 2); iter++, endptr++) {
3267 tmp = tmp * 10 + *endptr - '0';
3268 if (tmp > 59)
3269 return FALSE;
3270 }
3271 timegda->second = tmp;
3272 if (*endptr && (*endptr != '.') && (*endptr != '+') && (*endptr != '-')) {
3273 *out_endptr = endptr;
3274 return TRUE; /* end of the parsing */
3275 }
3276
3277 if (*endptr == '.') {
3278 endptr++;
3279 if (!*endptr)
3280 return FALSE;
3281 for (tmp = 0 ; (*endptr >= '0') && (*endptr <= '9'); endptr++) {
3282 if (tmp > G_MAXULONG / 10)
3283 return FALSE;
3284 tmp = tmp * 10 + *endptr - '0';
3285 }
3286 timegda->fraction = tmp;
3287 }
3288 if ((*endptr == '+') || (*endptr == '-')) {
3289 gint8 mult = 1;
3290 if (*endptr == '-')
3291 mult = -1;
3292 for (tmp = 0,endptr++ ; (*endptr >= '0') && (*endptr <= '9'); endptr++) {
3293 tmp = tmp * 10 + *endptr - '0';
3294 if (tmp >= 24)
3295 return FALSE;
3296 }
3297 timegda->timezone = tmp * 60 * 60 * mult;
3298 }
3299 else if (*endptr) {
3300 for (; g_ascii_isspace (*endptr); endptr++);
3301 if (((*endptr == 'G') || (*endptr == 'g')) &&
3302 ((endptr[1] == 'M') || (endptr[1] == 'm')) &&
3303 ((endptr[2] == 'T') || (endptr[2] == 't')) && !endptr[3]) {
3304 timegda->timezone = 0;
3305 endptr += 3;
3306 }
3307 else if (((*endptr == 'U') || (*endptr == 'u')) &&
3308 ((endptr[1] == 'T') || (endptr[1] == 't')) &&
3309 ((endptr[2] == 'C') || (endptr[2] == 'c')) && !endptr[3]) {
3310 timegda->timezone = 0;
3311 endptr += 3;
3312 }
3313 else if (((*endptr == 'T') || (*endptr == 'u')) &&
3314 ((endptr[1] == 'U') || (endptr[1] == 'u')) && !endptr[2]) {
3315 timegda->timezone = 0;
3316 endptr += 2;
3317 }
3318 else if (((*endptr == 'Z') || (*endptr == 'z')) && !endptr[1]) {
3319 timegda->timezone = 0;
3320 endptr += 1;
3321 }
3322 else {
3323 /* http://en.wikipedia.org/wiki/List_of_time_zone_abbreviations */
3324 GTimeZone *tz;
3325 tz = g_time_zone_new (endptr);
3326 if (tz) {
3327 if (g_time_zone_get_offset (tz, 0) == 0) {
3328 g_time_zone_unref (tz);
3329 return FALSE;
3330 }
3331 else {
3332 timegda->timezone = g_time_zone_get_offset (tz, 0);
3333 g_time_zone_unref (tz);
3334 for (; *endptr; endptr++);
3335 }
3336 }
3337 else
3338 return FALSE;
3339 }
3340 }
3341
3342 *out_endptr = endptr;
3343 return TRUE;
3344 }
3345
3346 /**
3347 * gda_parse_iso8601_time:
3348 * @timegda: a pointer to a #GdaTime structure which will be filled
3349 * @value: a string
3350 *
3351 * Extracts time parts from @value, and sets @timegda's contents
3352 *
3353 * Accepted date format is "HH:MM:SS[.ms][TZ]" where TZ is +hour or -hour
3354 *
3355 * Returns: %TRUE if no error occurred
3356 */
3357 gboolean
gda_parse_iso8601_time(GdaTime * timegda,const gchar * value)3358 gda_parse_iso8601_time (GdaTime *timegda, const gchar *value)
3359 {
3360 g_return_val_if_fail (timegda, FALSE);
3361
3362 if (!value)
3363 return FALSE;
3364
3365 const char *endptr;
3366 if (! _parse_iso8601_time (timegda, value, ':', GDA_TIMEZONE_INVALID, &endptr) || *endptr)
3367 return FALSE;
3368 else
3369 return TRUE;
3370 }
3371
3372 /**
3373 * gda_parse_formatted_time:
3374 * @timegda: a pointer to a #GdaTime structure which will be filled
3375 * @value: a string
3376 * @sep: the time separator, usually ':'. If equal to @0, then the expexted format will be HHMMSS...
3377 *
3378 * Returns: %TRUE if no error occurred
3379 *
3380 * Since: 5.2
3381 */
3382 gboolean
gda_parse_formatted_time(GdaTime * timegda,const gchar * value,gchar sep)3383 gda_parse_formatted_time (GdaTime *timegda, const gchar *value, gchar sep)
3384 {
3385 g_return_val_if_fail (timegda, FALSE);
3386
3387 if (!value)
3388 return FALSE;
3389 const char *endptr;
3390 if (! _parse_iso8601_time (timegda, value, sep, GDA_TIMEZONE_INVALID, &endptr) || *endptr)
3391 return FALSE;
3392 else
3393 return TRUE;
3394 }
3395
3396 /**
3397 * gda_parse_iso8601_timestamp:
3398 * @timestamp: a pointer to a #GdaTimeStamp structure which will be filled
3399 * @value: a string
3400 *
3401 * Extracts date and time parts from @value, and sets @timestamp's contents
3402 *
3403 * Accepted date format is "YYYY-MM-DD HH:MM:SS[.ms][TZ]" where TZ is +hour or -hour
3404 *
3405 * Returns: %TRUE if @value has been sucessfuly parsed as a valid timestamp (see g_date_valid())
3406 */
3407 gboolean
gda_parse_iso8601_timestamp(GdaTimestamp * timestamp,const gchar * value)3408 gda_parse_iso8601_timestamp (GdaTimestamp *timestamp, const gchar *value)
3409 {
3410 return gda_parse_formatted_timestamp (timestamp, value, G_DATE_YEAR, G_DATE_MONTH, G_DATE_DAY, '-');
3411 }
3412
3413 /**
3414 * gda_parse_formatted_timestamp:
3415 * @timestamp: a pointer to a #GdaTimeStamp structure which will be filled
3416 * @value: a string to be parsed
3417 * @first: a #GDateDMY specifying which of year, month or day appears first (in the first bytes) in @value
3418 * @second: a #GDateDMY specifying which of year, month or day appears second (in the first bytes) in @value
3419 * @third: a #GDateDMY specifying which of year, month or day appears third (in the first bytes) in @value
3420 * @sep: spcifies the expected separator character bewteen year, month and day (for example '-')
3421 *
3422 * This function is similar to gda_parse_iso8601_timestamp() (with @first being @G_DATE_YEAR, @second being @G_DATE_MONTH,
3423 * @third being @G_DATE_DAY and @sep being '-') but allows one to specify the expected date format.
3424 *
3425 * Returns: %TRUE if @value has been sucessfuly parsed as a valid date (see g_date_valid()).
3426 *
3427 * Since: 5.2
3428 */
3429 gboolean
gda_parse_formatted_timestamp(GdaTimestamp * timestamp,const gchar * value,GDateDMY first,GDateDMY second,GDateDMY third,gchar sep)3430 gda_parse_formatted_timestamp (GdaTimestamp *timestamp, const gchar *value,
3431 GDateDMY first, GDateDMY second, GDateDMY third, gchar sep)
3432 {
3433 g_return_val_if_fail (timestamp, FALSE);
3434
3435 gboolean retval = TRUE;
3436 const char *endptr;
3437 GDate gdate;
3438 GdaTime timegda;
3439
3440 memset (timestamp, 0, sizeof (GdaTimestamp));
3441 memset (&timegda, 0, sizeof (GdaTime));
3442 timegda.timezone = GDA_TIMEZONE_INVALID;
3443
3444 if (!value)
3445 return FALSE;
3446
3447 /* date part */
3448 if (! _parse_formatted_date (&gdate, value, first, second, third, sep, &endptr)) {
3449 retval = FALSE;
3450 goto out;
3451 }
3452 timestamp->year = g_date_get_year (&gdate);
3453 timestamp->month = g_date_get_month (&gdate);
3454 timestamp->day = g_date_get_day (&gdate);
3455
3456 /* separator */
3457 if (!*endptr)
3458 goto out;
3459
3460 if (*endptr != ' ') {
3461 retval = FALSE;
3462 goto out;
3463 }
3464 value = endptr + 1;
3465 if (!*value)
3466 goto out;
3467
3468 /* time part */
3469 if (! _parse_iso8601_time (&timegda, value, ':', GDA_TIMEZONE_INVALID, &endptr) ||
3470 *endptr)
3471 retval = FALSE;
3472 out:
3473 timestamp->hour = timegda.hour;
3474 timestamp->minute = timegda.minute;
3475 timestamp->second = timegda.second;
3476 timestamp->fraction = timegda.fraction;
3477 timestamp->timezone = timegda.timezone;
3478
3479 return retval;
3480 }
3481