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 &lt;parameter&gt; 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 = &lt;parameter definition&gt;" 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 = &lt;parameter definition&gt;" 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 +&lt;colindex&gt; or
1931  * -&lt;colindex&gt; 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 "&lt;part&gt;[.&lt;part&gt;[...]]" 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 (&amp;table_name_value, G_TYPE_STRING);
2539  * g_value_take_string (&amp;table_name_value, gda_sql_identifier_quote (user_sqlid, cnc, NULL, TRUE, FALSE);
2540  * gda_connection_update_meta_store (cnc, &amp;mcontext, NULL);
2541  * g_value_reset (&amp;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 (&amp;table_name_value, G_TYPE_STRING);
2552  * g_value_take_string (&amp;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, &amp;table_name_value, NULL);
2555  * g_value_reset (&amp;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>&lt;&gt;&quot;#%{}|\^~[]&apos;`;/?:@=&amp;</constant> and space characters are replaced by
2723  * <constant>&quot;%%ab&quot;</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>&lt;&gt;&quot;#%{}|\^~[]&apos;`;/?:@=&amp;</constant> and space characters are replaced by
2793  * <constant>&quot;%%ab&quot;</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 "[&lt;username&gt;[:&lt;password&gt;]@]&lt;DSN&gt;" form
2857  * @out_dsn: a place to store the new string containing the &lt;DSN&gt; part
2858  * @out_username: a place to store the new string containing the &lt;username&gt; part
2859  * @out_password: a place to store the new string containing the &lt;password&gt; 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 "[&lt;provider&gt;://][&lt;username&gt;[:&lt;password&gt;]@]&lt;connection_params&gt;" form
2905  * @out_cnc_params: a place to store the new string containing the &lt;connection_params&gt; part
2906  * @out_provider: a place to store the new string containing the &lt;provider&gt; part
2907  * @out_username: a place to store the new string containing the &lt;username&gt; part
2908  * @out_password: (nullable): a place to store the new string containing the &lt;password&gt; 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