1 /*
2  * Copyright (C) 2000 - 2001 Reinhard Müller <reinhard@src.gnome.org>
3  * Copyright (C) 2000 - 2004 Rodrigo Moya <rodrigo@gnome-db.org>
4  * Copyright (C) 2001 - 2003 Gonzalo Paniagua Javier <gonzalo@gnome-db.org>
5  * Copyright (C) 2001 - 2013 Vivien Malerba <malerba@gnome-db.org>
6  * Copyright (C) 2002 Andrew Hill <andru@src.gnome.org>
7  * Copyright (C) 2002 Cleber Rodrigues <cleberrrjr@bol.com.br>
8  * Copyright (C) 2002 Zbigniew Chyla <cyba@gnome.pl>
9  * Copyright (C) 2003 Laurent Sansonetti <lrz@src.gnome.org>
10  * Copyright (C) 2003 Paisa Seeluangsawat <paisa@users.sf.net>
11  * Copyright (C) 2004 - 2005 Alan Knowles <alank@src.gnome.org>
12  * Copyright (C) 2004 Dani Baeyens <daniel.baeyens@hispalinux.es>
13  * Copyright (C) 2004 José María Casanova Crespo <jmcasanova@igalia.com>
14  * Copyright (C) 2004 Szalai Ferenc <szferi@einstein.ki.iif.hu>
15  * Copyright (C) 2005 - 2009 Bas Driessen <bas.driessen@xobas.com>
16  * Copyright (C) 2005 Álvaro Peña <alvaropg@telefonica.net>
17  * Copyright (C) 2006 - 2012 Murray Cumming <murrayc@murrayc.com>
18  * Copyright (C) 2007 Armin Burgmeier <armin@openismus.com>
19  * Copyright (C) 2007 Leonardo Boshell <lb@kmc.com.co>
20  * Copyright (C) 2008 Johannes Schmid <jschmid@openismus.com>
21  * Copyright (C) 2010 David King <davidk@openismus.com>
22  * Copyright (C) 2010 Jonh Wendell <jwendell@gnome.org>
23  * Copyright (C) 2011,2018 Daniel Espinosa <esodan@gmail.com>
24  *
25  * This library is free software; you can redistribute it and/or
26  * modify it under the terms of the GNU Lesser General Public
27  * License as published by the Free Software Foundation; either
28  * version 2 of the License, or (at your option) any later version.
29  *
30  * This library is distributed in the hope that it will be useful,
31  * but WITHOUT ANY WARRANTY; without even the implied warranty of
32  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
33  * Lesser General Public License for more details.
34  *
35  * You should have received a copy of the GNU Lesser General Public
36  * License along with this library; if not, write to the
37  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
38  * Boston, MA  02110-1301, USA.
39  */
40 
41 #undef GDA_DISABLE_DEPRECATED
42 #include <stdio.h>
43 #include <libgda/gda-config.h>
44 #include <libgda/gda-connection.h>
45 #include <libgda/gda-connection-private.h>
46 #include <libgda/gda-connection-internal.h>
47 #include <libgda/gda-connection-event.h>
48 #include <glib/gi18n-lib.h>
49 #include <libgda/gda-log.h>
50 #include <libgda/gda-server-provider.h>
51 #include <libgda/gda-server-provider-extra.h>
52 #include "gda-marshal.h"
53 #include <libgda/gda-transaction-status-private.h>
54 #include <string.h>
55 #include <libgda/gda-enum-types.h>
56 #include <libgda/gda-holder.h>
57 #include <libgda/gda-set.h>
58 #include <sql-parser/gda-sql-parser.h>
59 #include <sql-parser/gda-statement-struct-trans.h>
60 #include <libgda/gda-meta-store-extra.h>
61 #include <libgda/gda-util.h>
62 #include <libgda/gda-mutex.h>
63 #include <libgda/gda-lockable.h>
64 #include <libgda/thread-wrapper/gda-thread-provider.h>
65 #include <libgda/gda-repetitive-statement.h>
66 #include <gda-statement-priv.h>
67 #include <sqlite/virtual/gda-vconnection-data-model.h>
68 #include <libgda/gda-debug-macros.h>
69 #include <libgda/gda-data-handler.h>
70 
71 #include <glib/gstdio.h>
72 #include <fcntl.h>
73 #include <unistd.h>
74 
75 static GMutex parser_mutex;
76 static GdaSqlParser *internal_parser = NULL;
77 
78 #define PROV_CLASS(provider) (GDA_SERVER_PROVIDER_CLASS (G_OBJECT_GET_CLASS (provider)))
79 
80 /* number of GdaConnectionEvent kept by each connection. Should be enough to avoid losing any
81  * event, considering that the events are reseted after each statement execution */
82 #define EVENTS_ARRAY_SIZE 5
83 
84 struct _GdaConnectionPrivate {
85 	GdaServerProvider    *provider_obj;
86 	GdaConnectionOptions  options; /* ORed flags */
87 	gchar                *dsn;
88 	gchar                *cnc_string;
89 	gchar                *auth_string;
90 	gboolean              is_thread_wrapper;
91 	guint                 monitor_id;
92 
93 	GdaMetaStore         *meta_store;
94 
95 	gboolean              auto_clear_events; /* TRUE if events_list is cleared before any statement execution */
96 	GdaConnectionEvent  **events_array; /* circular array */
97 	gint                  events_array_size;
98 	gboolean              events_array_full;
99 	gint                  events_array_next;
100 	GList                *events_list; /* for API compat */
101 
102 	GdaTransactionStatus *trans_status;
103 	GHashTable           *prepared_stmts;
104 
105 	gpointer              provider_data;
106 	GDestroyNotify        provider_data_destroy_func;
107 
108 	/* multi threading locking */
109 	GThread              *unique_possible_thread; /* non NULL => only that thread can use this connection */
110 	GCond                 unique_possible_cond;
111 	GMutex                object_mutex;
112 	GRecMutex             rmutex;
113 	/* Asynchronous statement execution */
114 	guint                 next_task_id; /* starts at 1 as 0 is an error */
115 	GArray               *waiting_tasks; /* array of CncTask pointers to tasks to be executed */
116 	GArray               *completed_tasks; /* array of CncTask pointers to tasks already executed */
117 
118 	/* auto meta data update */
119 	GArray               *trans_meta_context; /* Array of GdaMetaContext pointers */
120 
121 	gboolean              exec_times;
122 	guint                 exec_slowdown;
123 
124 	ThreadConnectionData *th_data; /* used if connection is used by the GdaThreadProvider, NULL otherwise */
125 };
126 
127 /* represents an asynchronous execution task */
128 typedef struct {
129 	guint task_id; /* ID assigned by GdaConnection object */
130 	guint prov_task_id; /* ID assigned by GdaServerProvider */
131 	gboolean being_processed; /* TRUE if currently being processed */
132 	GRecMutex rmutex;
133 	GdaStatement *stmt; /* statement to execute */
134 	GdaStatementModelUsage model_usage;
135 	GType *col_types;
136 	GdaSet *params;
137 	gboolean need_last_insert_row;
138 	GdaSet *last_insert_row;
139 	GObject *result;
140 	GError *error;
141 	GTimer *exec_timer;
142 } CncTask;
143 #define CNC_TASK(x) ((CncTask*)(x))
144 
145 static CncTask *cnc_task_new (guint id, GdaStatement *stmt, GdaStatementModelUsage model_usage,
146 			      GType *col_types, GdaSet *params, gboolean need_last_insert_row);
147 static void     cnc_task_free (CncTask *task);
148 #define         cnc_task_lock(task) g_rec_mutex_lock (&((task)->rmutex))
149 #define         cnc_task_unlock(task) g_rec_mutex_unlock (&((task)->rmutex))
150 
151 static void add_exec_time_to_object (GObject *obj, GTimer *timer);
152 
153 static void gda_connection_class_init (GdaConnectionClass *klass);
154 static void gda_connection_init       (GdaConnection *cnc, GdaConnectionClass *klass);
155 static void gda_connection_dispose    (GObject *object);
156 static void gda_connection_finalize   (GObject *object);
157 static void gda_connection_set_property (GObject *object,
158 					 guint param_id,
159 					 const GValue *value,
160 					 GParamSpec *pspec);
161 static void gda_connection_get_property (GObject *object,
162 					 guint param_id,
163 					 GValue *value,
164 					 GParamSpec *pspec);
165 
166 /* GdaLockable interface */
167 static void                 gda_connection_lockable_init (GdaLockableIface *iface);
168 static void                 gda_connection_lock      (GdaLockable *lockable);
169 static gboolean             gda_connection_trylock   (GdaLockable *lockable);
170 static void                 gda_connection_unlock    (GdaLockable *lockable);
171 
172 static void update_meta_store_after_statement_exec (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params);
173 static void change_events_array_max_size (GdaConnection *cnc, gint size);
174 
175 enum {
176 	ERROR,
177 	CONN_OPENED,
178         CONN_TO_CLOSE,
179         CONN_CLOSED,
180 	DSN_CHANGED,
181 	TRANSACTION_STATUS_CHANGED,
182 	LAST_SIGNAL
183 };
184 
185 static gint gda_connection_signals[LAST_SIGNAL] = { 0, 0, 0, 0, 0, 0 };
186 
187 /* properties */
188 enum
189 {
190         PROP_0,
191         PROP_DSN,
192         PROP_CNC_STRING,
193         PROP_PROVIDER_OBJ,
194         PROP_AUTH_STRING,
195         PROP_OPTIONS,
196 	PROP_META_STORE,
197 	PROP_THREAD_OWNER,
198 	PROP_IS_THREAD_WRAPPER,
199 	PROP_MONITOR_WRAPPED_IN_MAINLOOP,
200 	PROP_EVENTS_HISTORY_SIZE,
201 	PROP_EXEC_TIMES,
202 	PROP_EXEC_SLOWDOWN
203 };
204 
205 static GObjectClass *parent_class = NULL;
206 extern GdaServerProvider *_gda_config_sqlite_provider; /* defined in gda-config.c */
207 static GdaServerProvider *_gda_thread_wrapper_provider = NULL;
208 
209 static gint debug_level = -1;
210 static void
dump_exec_params(GdaConnection * cnc,GdaStatement * stmt,GdaSet * params)211 dump_exec_params (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params)
212 {
213 	if (params && (debug_level & 8)) {
214 		GSList *list;
215 		gchar *sql;
216 		sql = gda_statement_to_sql_extended (stmt, cnc, params, GDA_STATEMENT_SQL_PARAMS_SHORT,
217 						     NULL, NULL);
218 		g_print ("EVENT> COMMAND: parameters (on cnx %p) for statement [%s]\n", cnc, sql);
219 		for (list = params->holders; list; list = list->next) {
220 			GdaHolder *holder = GDA_HOLDER (list->data);
221 			gchar *str;
222 			const GValue *value;
223 			value = gda_holder_get_value (holder);
224 			str = value ? gda_value_stringify (value) : "NULL";
225 			g_print ("\t%s: type=>%s, value=>%s\n", gda_holder_get_id (holder),
226 				 gda_g_type_to_string (gda_holder_get_g_type (holder)),
227 				 str);
228 			if (value)
229 				g_free (str);
230 		}
231 		g_free (sql);
232 	}
233 }
234 
235 
236 /*
237  * GdaConnection class implementation
238  * @klass:
239  */
240 static void
gda_connection_class_init(GdaConnectionClass * klass)241 gda_connection_class_init (GdaConnectionClass *klass)
242 {
243 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
244 
245 	parent_class = g_type_class_peek_parent (klass);
246 
247 	/**
248 	 * GdaConnection::error:
249 	 * @cnc: the #GdaConnection
250 	 * @event: a #GdaConnectionEvent object
251 	 *
252 	 * Gets emitted whenever a connection event occurs. Check the nature of @event to
253 	 * see if it's an error or a simple notification
254 	 */
255 	gda_connection_signals[ERROR] =
256 		g_signal_new ("error",
257 			      G_TYPE_FROM_CLASS (object_class),
258 			      G_SIGNAL_RUN_LAST,
259 			      G_STRUCT_OFFSET (GdaConnectionClass, error),
260 			      NULL, NULL,
261 			      g_cclosure_marshal_VOID__OBJECT,
262 			      G_TYPE_NONE, 1, GDA_TYPE_CONNECTION_EVENT);
263 	/**
264 	 * GdaConnection::conn-opened:
265 	 * @cnc: the #GdaConnection
266 	 *
267 	 * Gets emitted when the connection has been opened to the database
268 	 */
269 	gda_connection_signals[CONN_OPENED] =
270                 g_signal_new ("conn-opened",
271                               G_TYPE_FROM_CLASS (object_class),
272                               G_SIGNAL_RUN_FIRST,
273                               G_STRUCT_OFFSET (GdaConnectionClass, conn_opened),
274                               NULL, NULL,
275                               _gda_marshal_VOID__VOID,
276                               G_TYPE_NONE, 0);
277 	/**
278 	 * GdaConnection::conn-to-close:
279 	 * @cnc: the #GdaConnection
280 	 *
281 	 * Gets emitted when the connection to the database is about to be closed
282 	 */
283         gda_connection_signals[CONN_TO_CLOSE] =
284                 g_signal_new ("conn-to-close",
285                               G_TYPE_FROM_CLASS (object_class),
286                               G_SIGNAL_RUN_FIRST,
287                               G_STRUCT_OFFSET (GdaConnectionClass, conn_to_close),
288                               NULL, NULL,
289                               _gda_marshal_VOID__VOID,
290                               G_TYPE_NONE, 0);
291 	/**
292 	 * GdaConnection::conn-closed:
293 	 * @cnc: the #GdaConnection
294 	 *
295 	 * Gets emitted when the connection to the database has been closed
296 	 */
297         gda_connection_signals[CONN_CLOSED] =    /* runs after user handlers */
298                 g_signal_new ("conn-closed",
299                               G_TYPE_FROM_CLASS (object_class),
300                               G_SIGNAL_RUN_LAST,
301                               G_STRUCT_OFFSET (GdaConnectionClass, conn_closed),
302                               NULL, NULL,
303                               _gda_marshal_VOID__VOID,
304                               G_TYPE_NONE, 0);
305 	/**
306 	 * GdaConnection::dsn-changed:
307 	 * @cnc: the #GdaConnection
308 	 *
309 	 * Gets emitted when the DSN used by @cnc has been changed
310 	 */
311 	gda_connection_signals[DSN_CHANGED] =
312 		g_signal_new ("dsn-changed",
313 			      G_TYPE_FROM_CLASS (object_class),
314 			      G_SIGNAL_RUN_LAST,
315 			      G_STRUCT_OFFSET (GdaConnectionClass, dsn_changed),
316 			      NULL, NULL,
317 			      g_cclosure_marshal_VOID__VOID,
318 			      G_TYPE_NONE, 0);
319 	/**
320 	 * GdaConnection::transaction-status-changed:
321 	 * @cnc: the #GdaConnection
322 	 *
323 	 * Gets emitted when the transaction status of @cnc has changed (a transaction has been
324 	 * started, rolled back, a savepoint added,...)
325 	 */
326 	gda_connection_signals[TRANSACTION_STATUS_CHANGED] =
327 		g_signal_new ("transaction-status-changed",
328 			      G_TYPE_FROM_CLASS (object_class),
329 			      G_SIGNAL_RUN_LAST,
330 			      G_STRUCT_OFFSET (GdaConnectionClass, transaction_status_changed),
331 			      NULL, NULL,
332 			      g_cclosure_marshal_VOID__VOID,
333 			      G_TYPE_NONE, 0);
334 
335 	/* Properties */
336         object_class->set_property = gda_connection_set_property;
337         object_class->get_property = gda_connection_get_property;
338 
339 	g_object_class_install_property (object_class, PROP_DSN,
340                                          g_param_spec_string ("dsn", NULL, _("DSN to use"), NULL,
341 							      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
342 	g_object_class_install_property (object_class, PROP_CNC_STRING,
343                                          g_param_spec_string ("cnc-string", NULL, _("Connection string to use"), NULL,
344 							      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
345 	g_object_class_install_property (object_class, PROP_PROVIDER_OBJ,
346                                          g_param_spec_object ("provider", NULL, _("Provider to use"),
347                                                                GDA_TYPE_SERVER_PROVIDER,
348 							       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
349 
350         g_object_class_install_property (object_class, PROP_AUTH_STRING,
351                                          g_param_spec_string ("auth-string", NULL,_("Authentication string to use"),
352                                                               NULL,
353                                                               (G_PARAM_READABLE | G_PARAM_WRITABLE)));
354         g_object_class_install_property (object_class, PROP_OPTIONS,
355                                          g_param_spec_flags ("options", NULL, _("Options"),
356 							    GDA_TYPE_CONNECTION_OPTIONS, GDA_CONNECTION_OPTIONS_NONE,
357 							    (G_PARAM_READABLE | G_PARAM_WRITABLE)));
358         g_object_class_install_property (object_class, PROP_META_STORE,
359 					 /* To translators: Don't translate "GdaMetaStore", it's a class name */
360 					 g_param_spec_object ("meta-store", NULL, _ ("GdaMetaStore used by the connection"),
361 							      GDA_TYPE_META_STORE,
362 							      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
363 
364 	g_object_class_install_property (object_class, PROP_THREAD_OWNER,
365 					 g_param_spec_pointer ("thread-owner", NULL,
366 							       _("Unique GThread from which the connection will be available."
367 								 "This should only be modified by the database providers' implementation"),
368 							       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
369 
370 	/**
371 	 * GdaConnection:is-wrapper:
372 	 *
373 	 * This property, if set to %TRUE, specifies that the connection is not a real connection, but rather
374 	 * a #GdaConnection object which "proxies" all the calls to another connection which executes in a sub
375 	 * thread.
376 	 *
377 	 * Note: this property is used internally by Libgda and should not be directly used by any programs. Setting
378 	 * this property has no effect, reading it is supported, though.
379 	 *
380 	 * Since: 4.2
381 	 **/
382 	g_object_class_install_property (object_class, PROP_IS_THREAD_WRAPPER,
383 					 g_param_spec_boolean ("is-wrapper", NULL,
384 							       _("Determines if the connection acts as a thread wrapper around another connection, making it completely thread safe"),
385 							       FALSE,
386 							       G_PARAM_READABLE | G_PARAM_WRITABLE));
387 
388 	/**
389 	 * GdaConnection:monitor-wrapped-in-mainloop:
390 	 *
391 	 * Useful only when there is a mainloop and when the connection acts as a thread wrapper around another connection,
392 	 * it sets up a timeout to handle signals coming from the wrapped connection.
393 	 *
394 	 * If the connection is not a thread wrapper, then this property has no effect.
395 	 *
396 	 * Since: 4.2
397 	 **/
398 	g_object_class_install_property (object_class, PROP_MONITOR_WRAPPED_IN_MAINLOOP,
399 					 g_param_spec_boolean ("monitor-wrapped-in-mainloop", NULL,
400 							       _("Make the connection set up a monitoring function in the mainloop to monitor the wrapped connection"),
401 							       FALSE,
402 							       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
403 
404 	/**
405 	 * GdaConnection:events-history-size:
406 	 *
407 	 * Defines the number of #GdaConnectionEvent objects kept in memory which can
408 	 * be fetched using gda_connection_get_events().
409 	 *
410 	 * Since: 4.2
411 	 */
412 	g_object_class_install_property (object_class, PROP_EVENTS_HISTORY_SIZE,
413 					 g_param_spec_int ("events-history-size", NULL,
414 							   _("Number of history events to keep in memory"), EVENTS_ARRAY_SIZE, G_MAXINT,
415 							   EVENTS_ARRAY_SIZE,
416 							   (G_PARAM_READABLE | G_PARAM_WRITABLE)));
417 
418 	/**
419 	 * GdaConnection:execution-timer:
420 	 *
421 	 * Computes execution times for each statement executed.
422 	 *
423 	 * Since: 4.2.9
424 	 **/
425 	g_object_class_install_property (object_class, PROP_EXEC_TIMES,
426 					 g_param_spec_boolean ("execution-timer", NULL,
427 							       _("Computes execution delay for each executed statement"),
428 							       FALSE,
429 							       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
430 	/**
431 	 * GdaConnection:execution-slowdown:
432 	 *
433 	 * Artificially slows down the execution of queries. This property can be used to
434 	 * debug some problems. If non zero, this value is the number of microseconds waited before actually
435 	 * executing each query.
436 	 *
437 	 * Since: 5.2.0
438 	 **/
439 	g_object_class_install_property (object_class, PROP_EXEC_SLOWDOWN,
440 					 g_param_spec_uint ("execution-slowdown", NULL,
441 							    _("Artificially slows down the execution of queries"),
442 							    0, G_MAXUINT, 0,
443 							    (G_PARAM_READABLE | G_PARAM_WRITABLE)));
444 
445 	object_class->dispose = gda_connection_dispose;
446 	object_class->finalize = gda_connection_finalize;
447 
448 	/* computing debug level */
449 	if (debug_level == -1) {
450 		const gchar *str;
451 		debug_level = 0;
452 		str = getenv ("GDA_CONNECTION_EVENTS_SHOW"); /* Flawfinder: ignore */
453 		if (str) {
454 			gchar **array;
455 			guint i;
456 			guint array_len;
457 			array = g_strsplit_set (str, " ,/;:", 0);
458 			array_len = g_strv_length (array);
459 			for (i = 0; i < array_len; i++) {
460 				if (!g_ascii_strcasecmp (array[i], "notice"))
461 					debug_level += 1;
462 				else if (!g_ascii_strcasecmp (array[i], "warning"))
463 					debug_level += 2;
464 				else if (!g_ascii_strcasecmp (array[i], "error"))
465 					debug_level += 4;
466 				else if (!g_ascii_strcasecmp (array[i], "command"))
467 					debug_level += 8;
468 			}
469 			g_strfreev (array);
470 		}
471 	}
472 }
473 
474 static void
gda_connection_lockable_init(GdaLockableIface * iface)475 gda_connection_lockable_init (GdaLockableIface *iface)
476 {
477 	iface->i_lock = gda_connection_lock;
478 	iface->i_trylock = gda_connection_trylock;
479 	iface->i_unlock = gda_connection_unlock;
480 }
481 
482 static void
gda_connection_init(GdaConnection * cnc,G_GNUC_UNUSED GdaConnectionClass * klass)483 gda_connection_init (GdaConnection *cnc, G_GNUC_UNUSED GdaConnectionClass *klass)
484 {
485 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
486 
487 	cnc->priv = g_new0 (GdaConnectionPrivate, 1);
488 	cnc->priv->unique_possible_thread = NULL;
489 	g_mutex_init (&cnc->priv->object_mutex);
490 	g_rec_mutex_init (&cnc->priv->rmutex);
491 	g_cond_init (& cnc->priv->unique_possible_cond);
492 	cnc->priv->provider_obj = NULL;
493 	cnc->priv->dsn = NULL;
494 	cnc->priv->cnc_string = NULL;
495 	cnc->priv->auth_string = NULL;
496 	cnc->priv->auto_clear_events = TRUE;
497 	cnc->priv->events_array_size = EVENTS_ARRAY_SIZE;
498 	cnc->priv->events_array = g_new0 (GdaConnectionEvent*, EVENTS_ARRAY_SIZE);
499 	cnc->priv->events_array_full = FALSE;
500 	cnc->priv->events_array_next = 0;
501 	cnc->priv->trans_status = NULL; /* no transaction yet */
502 	cnc->priv->prepared_stmts = NULL;
503 
504 	cnc->priv->is_thread_wrapper = FALSE;
505 	cnc->priv->monitor_id = 0;
506 
507 	cnc->priv->next_task_id = 1;
508 	cnc->priv->waiting_tasks = g_array_new (FALSE, FALSE, sizeof (gpointer));
509 	cnc->priv->completed_tasks = g_array_new (FALSE, FALSE, sizeof (gpointer));
510 
511 	cnc->priv->trans_meta_context = NULL;
512 	cnc->priv->provider_data = NULL;
513 
514 	cnc->priv->exec_times = FALSE;
515 	cnc->priv->exec_slowdown = 0;
516 }
517 
518 static void auto_update_meta_context_free (GdaMetaContext *context);
519 static void prepared_stms_foreach_func (GdaStatement *gda_stmt, GdaPStmt *prepared_stmt, GdaConnection *cnc);
520 static void
gda_connection_dispose(GObject * object)521 gda_connection_dispose (GObject *object)
522 {
523 	GdaConnection *cnc = (GdaConnection *) object;
524 
525 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
526 
527 	/* free memory */
528 	cnc->priv->unique_possible_thread = NULL;
529 	gda_connection_close_no_warning (cnc);
530 
531 	if (cnc->priv->th_data) {
532 		_gda_thread_connection_data_free (cnc->priv->th_data);
533 		cnc->priv->th_data = NULL;
534 	}
535 
536 	/* get rid of prepared statements to avoid problems */
537 	if (cnc->priv->prepared_stmts) {
538 		g_hash_table_foreach (cnc->priv->prepared_stmts,
539 				      (GHFunc) prepared_stms_foreach_func, cnc);
540 		g_hash_table_destroy (cnc->priv->prepared_stmts);
541 		cnc->priv->prepared_stmts = NULL;
542 	}
543 
544 	if (cnc->priv->provider_obj) {
545 		_gda_server_provider_handlers_clear_for_cnc (cnc->priv->provider_obj, cnc);
546 		g_object_unref (G_OBJECT (cnc->priv->provider_obj));
547 		cnc->priv->provider_obj = NULL;
548 	}
549 
550 	if (cnc->priv->events_list) {
551 		g_list_foreach (cnc->priv->events_list, (GFunc) g_object_unref, NULL);
552 		g_list_free (cnc->priv->events_list);
553 		cnc->priv->events_list = NULL;
554 	}
555 
556 	if (cnc->priv->events_array) {
557 		gint i;
558 		for (i = 0; i < cnc->priv->events_array_size ; i++) {
559 			GdaConnectionEvent *ev;
560 			ev = cnc->priv->events_array [i];
561 			if (ev)
562 				g_object_unref (ev);
563 		}
564 		g_free (cnc->priv->events_array);
565 		cnc->priv->events_array = NULL;
566 	}
567 
568 	if (cnc->priv->trans_status) {
569 		g_object_unref (cnc->priv->trans_status);
570 		cnc->priv->trans_status = NULL;
571 	}
572 
573 	if (cnc->priv->meta_store != NULL) {
574 	        g_object_unref (cnc->priv->meta_store);
575 	        cnc->priv->meta_store = NULL;
576 	}
577 
578 	if (cnc->priv->waiting_tasks) {
579 		gint i, len = cnc->priv->waiting_tasks->len;
580 		for (i = 0; i < len; i++)
581 			cnc_task_free (CNC_TASK (g_array_index (cnc->priv->waiting_tasks, gpointer, i)));
582 		g_array_free (cnc->priv->waiting_tasks, TRUE);
583 		cnc->priv->waiting_tasks = NULL;
584 	}
585 
586 	if (cnc->priv->completed_tasks) {
587 		gssize i, len = cnc->priv->completed_tasks->len;
588 		for (i = 0; i < len; i++)
589 			cnc_task_free (CNC_TASK (g_array_index (cnc->priv->completed_tasks, gpointer, i)));
590 		g_array_free (cnc->priv->completed_tasks, TRUE);
591 		cnc->priv->completed_tasks = NULL;
592 	}
593 
594 	if (cnc->priv->trans_meta_context) {
595 		gsize i;
596 		for (i = 0; i < cnc->priv->trans_meta_context->len; i++) {
597 			GdaMetaContext *context;
598 			context = g_array_index (cnc->priv->trans_meta_context, GdaMetaContext*, i);
599 			auto_update_meta_context_free (context);
600 		}
601 		g_array_free (cnc->priv->trans_meta_context, TRUE);
602 		cnc->priv->trans_meta_context = NULL;
603 	}
604 
605 	/* chain to parent class */
606 	parent_class->dispose (object);
607 }
608 
609 static void
gda_connection_finalize(GObject * object)610 gda_connection_finalize (GObject *object)
611 {
612 	GdaConnection *cnc = (GdaConnection *) object;
613 
614 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
615 
616 	/* free memory */
617 	g_free (cnc->priv->dsn);
618 	g_free (cnc->priv->cnc_string);
619 	g_free (cnc->priv->auth_string);
620 
621 	g_cond_clear (& cnc->priv->unique_possible_cond);
622 	g_mutex_clear (& cnc->priv->object_mutex);
623 	g_rec_mutex_clear (&cnc->priv->rmutex);
624 
625 	g_free (cnc->priv);
626 	cnc->priv = NULL;
627 
628 	/* chain to parent class */
629 	parent_class->finalize (object);
630 }
631 
632 /* module error */
gda_connection_error_quark(void)633 GQuark gda_connection_error_quark (void)
634 {
635         static GQuark quark;
636         if (!quark)
637                 quark = g_quark_from_static_string ("gda_connection_error");
638         return quark;
639 }
640 
641 /**
642  * gda_connection_get_type:
643  *
644  * Registers the #GdaConnection class on the GLib type system.
645  *
646  * Returns: the GType identifying the class.
647  */
648 GType
gda_connection_get_type(void)649 gda_connection_get_type (void)
650 {
651 	static GType type = 0;
652 
653 	if (G_UNLIKELY (type == 0)) {
654 		static GMutex registering;
655 		static GTypeInfo info = {
656 			sizeof (GdaConnectionClass),
657 			(GBaseInitFunc) NULL,
658 			(GBaseFinalizeFunc) NULL,
659 			(GClassInitFunc) gda_connection_class_init,
660 			NULL, NULL,
661 			sizeof (GdaConnection),
662 			0,
663 			(GInstanceInitFunc) gda_connection_init,
664 			0
665 		};
666 
667 		static GInterfaceInfo lockable_info = {
668                         (GInterfaceInitFunc) gda_connection_lockable_init,
669 			NULL,
670                         NULL
671                 };
672 
673 		g_mutex_lock (&registering);
674 		if (type == 0) {
675 			type = g_type_register_static (G_TYPE_OBJECT, "GdaConnection", &info, 0);
676 			g_type_add_interface_static (type, GDA_TYPE_LOCKABLE, &lockable_info);
677 		}
678 		g_mutex_unlock (&registering);
679 	}
680 
681 	return type;
682 }
683 
684 static gboolean
monitor_wrapped_cnc(GdaThreadWrapper * wrapper)685 monitor_wrapped_cnc (GdaThreadWrapper *wrapper)
686 {
687 	gda_thread_wrapper_iterate (wrapper, FALSE);
688 	return TRUE; /* don't remove the monitoring */
689 }
690 
691 void
_gda_connection_define_as_thread_wrapper(GdaConnection * cnc)692 _gda_connection_define_as_thread_wrapper (GdaConnection *cnc)
693 {
694 	cnc->priv->is_thread_wrapper = TRUE;
695 }
696 
697 static void
gda_connection_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)698 gda_connection_set_property (GObject *object,
699 			     guint param_id,
700 			     const GValue *value,
701 			     GParamSpec *pspec)
702 {
703 	GdaConnection *cnc;
704 
705         cnc = GDA_CONNECTION (object);
706         if (cnc->priv) {
707 		if (cnc->priv->th_data && ! gda_connection_internal_get_provider_data (cnc)) {
708 			_gda_thread_connection_data_free (cnc->priv->th_data);
709 			cnc->priv->th_data = NULL;
710 		}
711 
712                 switch (param_id) {
713 		case PROP_THREAD_OWNER:
714 			g_mutex_lock (&cnc->priv->object_mutex);
715 			g_rec_mutex_lock (&cnc->priv->rmutex);
716 			cnc->priv->unique_possible_thread = g_value_get_pointer (value);
717 #ifdef GDA_DEBUG_CNC_LOCK
718 			g_print ("Unique set to %p\n", cnc->priv->unique_possible_thread);
719 			g_print ("Signalling on %p\n", cnc->priv->unique_possible_cond);
720 #endif
721 			g_cond_broadcast (& cnc->priv->unique_possible_cond);
722 
723 			g_rec_mutex_unlock (&cnc->priv->rmutex);
724 			g_mutex_unlock (&cnc->priv->object_mutex);
725 			break;
726                 case PROP_DSN: {
727 			const gchar *datasource = g_value_get_string (value);
728 			GdaDsnInfo *dsn;
729 
730 			gda_connection_lock ((GdaLockable*) cnc);
731 			_gda_thread_connection_set_data (cnc, NULL);
732 			if (cnc->priv->provider_data) {
733 				g_warning (_("Could not set the '%s' property when the connection is opened"),
734 					   pspec->name);
735 				gda_connection_unlock ((GdaLockable*) cnc);
736 				return;
737 			}
738 
739 			dsn = gda_config_get_dsn_info (datasource);
740 			if (!dsn) {
741 				g_warning (_("No DSN named '%s' defined"), datasource);
742 				gda_connection_unlock ((GdaLockable*) cnc);
743 				return;
744 			}
745 
746 			g_free (cnc->priv->dsn);
747 			cnc->priv->dsn = g_strdup (datasource);
748 #ifdef GDA_DEBUG_signal
749 			g_print (">> 'DSN_CHANGED' from %s\n", __FUNCTION__);
750 #endif
751 			g_signal_emit (G_OBJECT (cnc), gda_connection_signals[DSN_CHANGED], 0);
752 #ifdef GDA_DEBUG_signal
753 			g_print ("<< 'DSN_CHANGED' from %s\n", __FUNCTION__);
754 #endif
755 			gda_connection_unlock ((GdaLockable*) cnc);
756                         break;
757 		}
758                 case PROP_CNC_STRING:
759 			gda_connection_lock ((GdaLockable*) cnc);
760 			_gda_thread_connection_set_data (cnc, NULL);
761 			if (cnc->priv->provider_data) {
762 				g_warning (_("Could not set the '%s' property when the connection is opened"),
763 					   pspec->name);
764 				gda_connection_unlock ((GdaLockable*) cnc);
765 				return;
766 			}
767 			g_free (cnc->priv->cnc_string);
768 			cnc->priv->cnc_string = NULL;
769 			if (g_value_get_string (value))
770 				cnc->priv->cnc_string = g_strdup (g_value_get_string (value));
771 			gda_connection_unlock ((GdaLockable*) cnc);
772                         break;
773                 case PROP_PROVIDER_OBJ:
774 			gda_connection_lock ((GdaLockable*) cnc);
775 			_gda_thread_connection_set_data (cnc, NULL);
776 			if (cnc->priv->provider_data) {
777 				g_warning (_("Could not set the '%s' property when the connection is opened"),
778 					   pspec->name);
779 				gda_connection_unlock ((GdaLockable*) cnc);
780 				return;
781 			}
782                         if (cnc->priv->provider_obj)
783 				g_object_unref (cnc->priv->provider_obj);
784 
785 			cnc->priv->provider_obj = g_value_get_object (value);
786 			g_object_ref (G_OBJECT (cnc->priv->provider_obj));
787 			gda_connection_unlock ((GdaLockable*) cnc);
788                         break;
789                 case PROP_AUTH_STRING:
790 			gda_connection_lock ((GdaLockable*) cnc);
791 			_gda_thread_connection_set_data (cnc, NULL);
792 			if (cnc->priv->provider_data) {
793 				g_warning (_("Could not set the '%s' property when the connection is opened"),
794 					   pspec->name);
795 				gda_connection_unlock ((GdaLockable*) cnc);
796 				return;
797 			}
798 			else {
799 				const gchar *str = g_value_get_string (value);
800 				g_free (cnc->priv->auth_string);
801 				cnc->priv->auth_string = NULL;
802 				if (str)
803 					cnc->priv->auth_string = g_strdup (str);
804 			}
805 			gda_connection_unlock ((GdaLockable*) cnc);
806                         break;
807                 case PROP_OPTIONS: {
808 			GdaConnectionOptions flags;
809 			flags = g_value_get_flags (value);
810 			g_rec_mutex_lock (&cnc->priv->rmutex);
811 			_gda_thread_connection_set_data (cnc, NULL);
812 			if (cnc->priv->provider_data &&
813 			    ((flags & (~GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE)) !=
814 			     (cnc->priv->options & (~GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE)))) {
815 				g_warning (_("Can't set the '%s' property once the connection is opened"),
816 					   pspec->name);
817 				g_rec_mutex_unlock (&cnc->priv->rmutex);
818 				return;
819 			}
820 			cnc->priv->options = flags;
821 			g_rec_mutex_unlock (&cnc->priv->rmutex);
822 			break;
823 		}
824 		case PROP_META_STORE:
825 			g_rec_mutex_lock (&cnc->priv->rmutex);
826 			if (cnc->priv->meta_store) {
827 				g_object_unref (cnc->priv->meta_store);
828 				cnc->priv->meta_store = NULL;
829 			}
830 			cnc->priv->meta_store = g_value_get_object (value);
831 			if (cnc->priv->meta_store)
832 				g_object_ref (cnc->priv->meta_store);
833 			if (cnc->priv->is_thread_wrapper) {
834 				ThreadConnectionData *cdata;
835 				cdata = (ThreadConnectionData*) gda_connection_internal_get_provider_data (cnc);
836 				if (cdata)
837 					g_object_set (G_OBJECT (cdata->sub_connection), "meta-store",
838 						      cnc->priv->meta_store, NULL);
839 			}
840 			g_rec_mutex_unlock (&cnc->priv->rmutex);
841 			break;
842 		case PROP_IS_THREAD_WRAPPER:
843 			g_warning ("This property should not be modified!");
844 			break;
845 		case PROP_MONITOR_WRAPPED_IN_MAINLOOP:
846 			if (cnc->priv->is_thread_wrapper) {
847 				/* cancel any existing signal monitoring */
848 				if (cnc->priv->monitor_id > 0) {
849 					g_source_remove (cnc->priv->monitor_id);
850 					cnc->priv->monitor_id = 0;
851 				}
852 				if (g_value_get_boolean (value)) {
853 					/* set up signal monitoring */
854 					ThreadConnectionData *cdata = NULL;
855 					cdata = (ThreadConnectionData*) gda_connection_internal_get_provider_data (cnc);
856 					if (cdata) {
857 						cnc->priv->monitor_id = g_timeout_add_seconds (1,
858 											       (GSourceFunc) monitor_wrapped_cnc,
859 											       cdata->wrapper);
860 						/* steal signals for current thread */
861 						gsize i;
862 						for (i = 0; i < cdata->handlers_ids->len; i++) {
863 							gulong id;
864 							id = g_array_index (cdata->handlers_ids, gulong, i);
865 							gda_thread_wrapper_steal_signal (cdata->wrapper, id);
866 						}
867 					}
868 				}
869 			}
870 			break;
871 		case PROP_EVENTS_HISTORY_SIZE:
872 			gda_connection_lock ((GdaLockable*) cnc);
873 			change_events_array_max_size (cnc, g_value_get_int (value));
874 			gda_connection_unlock ((GdaLockable*) cnc);
875 			break;
876 		case PROP_EXEC_TIMES:
877 			cnc->priv->exec_times = g_value_get_boolean (value);
878 			break;
879 		case PROP_EXEC_SLOWDOWN:
880 			cnc->priv->exec_slowdown = g_value_get_uint (value);
881 			if (cnc->priv->is_thread_wrapper) {
882 				ThreadConnectionData *cdata;
883 				cdata = (ThreadConnectionData*) gda_connection_internal_get_provider_data (cnc);
884 				if (cdata)
885 					g_object_set (G_OBJECT (cdata->sub_connection), "execution-slowdown",
886 						      cnc->priv->exec_slowdown, NULL);
887 			}
888 			break;
889                 }
890         }
891 }
892 
893 static void
gda_connection_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)894 gda_connection_get_property (GObject *object,
895 			     guint param_id,
896 			     GValue *value,
897 			     GParamSpec *pspec)
898 {
899 	GdaConnection *cnc;
900 
901         cnc = GDA_CONNECTION (object);
902         if (cnc->priv) {
903                 switch (param_id) {
904                 case PROP_DSN:
905 			g_value_set_string (value, cnc->priv->dsn);
906                         break;
907                 case PROP_CNC_STRING:
908 			g_value_set_string (value, cnc->priv->cnc_string);
909 			break;
910                 case PROP_PROVIDER_OBJ:
911 			g_value_set_object (value, (GObject*) cnc->priv->provider_obj);
912                         break;
913                 case PROP_AUTH_STRING:
914 			g_value_set_string (value, cnc->priv->auth_string);
915                         break;
916                 case PROP_OPTIONS:
917 			g_value_set_flags (value, cnc->priv->options);
918 			break;
919 		case PROP_META_STORE:
920 			g_value_set_object (value, cnc->priv->meta_store);
921 			break;
922 		case PROP_IS_THREAD_WRAPPER:
923 			g_value_set_boolean (value, cnc->priv->is_thread_wrapper);
924 			break;
925 		case PROP_MONITOR_WRAPPED_IN_MAINLOOP:
926 			g_value_set_boolean (value, cnc->priv->is_thread_wrapper && (cnc->priv->monitor_id > 0) ?
927 					     TRUE : FALSE);
928 			break;
929 		case PROP_EVENTS_HISTORY_SIZE:
930 			g_value_set_int (value, cnc->priv->events_array_size);
931 			break;
932 		case PROP_EXEC_TIMES:
933 			g_value_set_boolean (value, cnc->priv->exec_times);
934 			break;
935 		case PROP_EXEC_SLOWDOWN:
936 			g_value_set_uint (value, cnc->priv->exec_slowdown);
937 			break;
938 		default:
939 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
940 			break;
941                 }
942         }
943 }
944 
945 /*
946  * Returns: a new GType array, free using g_free(), or %NULL if none to compute
947  */
948 static GType *
merge_column_types(const GType * struct_types,const GType * user_types)949 merge_column_types (const GType *struct_types, const GType *user_types)
950 {
951 	if (! user_types || !struct_types)
952 		return NULL;
953 	GArray *array;
954 	guint i;
955 	array = g_array_new (TRUE, FALSE, sizeof (GType));
956 	for (i = 0;
957 	     (user_types [i] != G_TYPE_NONE) && (struct_types [i] != G_TYPE_NONE);
958 	     i++) {
959 		GType type;
960 		if (user_types [i] == 0)
961 			type = struct_types [i];
962 		else
963 			type = user_types [i];
964 		g_array_append_val (array, type);
965 	}
966 	if (user_types [i] != G_TYPE_NONE) {
967 		for (; user_types [i] != G_TYPE_NONE; i++) {
968 			GType type = user_types [i];
969 			g_array_append_val (array, type);
970 		}
971 	}
972 	else {
973 		for (; struct_types [i] != G_TYPE_NONE; i++) {
974 			GType type = struct_types [i];
975 			g_array_append_val (array, type);
976 		}
977 	}
978 	GType *retval;
979 	guint len;
980 	len = array->len;
981 	retval = (GType*) g_array_free (array, FALSE);
982 	retval [len] = G_TYPE_NONE;
983 	return retval;
984 }
985 
986 /*
987  * helper functions to manage CncTask
988  */
989 static void task_stmt_reset_cb (GdaStatement *stmt, CncTask *task);
990 static CncTask *
cnc_task_new(guint id,GdaStatement * stmt,GdaStatementModelUsage model_usage,GType * col_types,GdaSet * params,gboolean need_last_insert_row)991 cnc_task_new (guint id, GdaStatement *stmt, GdaStatementModelUsage model_usage, GType *col_types,
992 	      GdaSet *params, gboolean need_last_insert_row)
993 {
994 	CncTask *task;
995 
996 	task = g_new0 (CncTask, 1);
997 	task->being_processed = FALSE;
998 	task->task_id = id;
999 	task->stmt = g_object_ref (stmt);
1000 	task->exec_timer = NULL;
1001 	g_signal_connect (stmt, "reset", /* monitor statement changes */
1002 			  G_CALLBACK (task_stmt_reset_cb), task);
1003 	task->model_usage = model_usage;
1004 	GType *req_types;
1005 	req_types = merge_column_types (_gda_statement_get_requested_types (stmt), col_types);
1006 	if (req_types)
1007 		task->col_types = req_types;
1008 	else {
1009 		if (_gda_statement_get_requested_types (stmt))
1010 			col_types = (GType*) _gda_statement_get_requested_types (stmt);
1011 		if (col_types) {
1012 			gint i;
1013 			for (i = 0; ; i++) {
1014 				if (col_types [i] == G_TYPE_NONE)
1015 					break;
1016 			}
1017 			i++;
1018 			task->col_types = g_new (GType, i);
1019 			memcpy (task->col_types, col_types, i * sizeof (GType)); /* Flawfinder: ignore */
1020 		}
1021 	}
1022 	if (params)
1023 		task->params = gda_set_copy (params);
1024 	task->need_last_insert_row = need_last_insert_row;
1025 
1026 	g_rec_mutex_init (&(task->rmutex));
1027 
1028 	return task;
1029 }
1030 
1031 static void
task_stmt_reset_cb(G_GNUC_UNUSED GdaStatement * stmt,CncTask * task)1032 task_stmt_reset_cb (G_GNUC_UNUSED GdaStatement *stmt, CncTask *task)
1033 {
1034 	g_rec_mutex_lock (&(task->rmutex));
1035 	g_signal_handlers_disconnect_by_func (task->stmt,
1036 					      G_CALLBACK (task_stmt_reset_cb), task);
1037 	g_object_unref (task->stmt);
1038 	task->stmt = NULL;
1039 	g_rec_mutex_unlock (&(task->rmutex));
1040 }
1041 
1042 static void
cnc_task_free(CncTask * task)1043 cnc_task_free (CncTask *task)
1044 {
1045 	g_rec_mutex_lock (&(task->rmutex));
1046 	if (task->stmt) {
1047 		g_signal_handlers_disconnect_by_func (task->stmt,
1048 						      G_CALLBACK (task_stmt_reset_cb), task);
1049 		g_object_unref (task->stmt);
1050 	}
1051 	if (task->params)
1052 		g_object_unref (task->params);
1053 	if (task->col_types)
1054 		g_free (task->col_types);
1055 	if (task->last_insert_row)
1056 		g_object_unref (task->last_insert_row);
1057 	if (task->result)
1058 		g_object_unref (task->result);
1059 	if (task->error)
1060 		g_error_free (task->error);
1061 	if (task->exec_timer)
1062 		g_timer_destroy (task->exec_timer);
1063 
1064 	g_rec_mutex_unlock (&(task->rmutex));
1065 	g_rec_mutex_clear (&(task->rmutex));
1066 	g_free (task);
1067 }
1068 
1069 /**
1070  * _gda_connection_get_internal_thread_provider:
1071  */
1072 GdaServerProvider *
_gda_connection_get_internal_thread_provider(void)1073 _gda_connection_get_internal_thread_provider (void)
1074 {
1075 	static GMutex mutex;
1076 
1077 	g_mutex_lock (&mutex);
1078 	if (!_gda_thread_wrapper_provider)
1079 		_gda_thread_wrapper_provider = GDA_SERVER_PROVIDER (g_object_new (GDA_TYPE_THREAD_PROVIDER, NULL));
1080 	g_mutex_unlock (&mutex);
1081 	return _gda_thread_wrapper_provider;
1082 }
1083 
1084 
1085 /**
1086  * gda_connection_new_from_dsn:
1087  * @dsn: data source name.
1088  * @auth_string: (allow-none): authentication string, or %NULL
1089  * @options: options for the connection (see #GdaConnectionOptions).
1090  * @error: a place to store an error, or %NULL
1091  *
1092  * This function is similar to gda_connection_open_from_dsn(), except it does not actually open the
1093  * connection, you have to open it using gda_connection_open().
1094  *
1095  * Returns: (transfer full): a new #GdaConnection if connection opening was successful or %NULL if there was an error.
1096  *
1097  * Since: 5.0.2
1098  */
1099 GdaConnection *
gda_connection_new_from_dsn(const gchar * dsn,const gchar * auth_string,GdaConnectionOptions options,GError ** error)1100 gda_connection_new_from_dsn (const gchar *dsn, const gchar *auth_string,
1101 			      GdaConnectionOptions options, GError **error)
1102 {
1103 	GdaConnection *cnc = NULL;
1104 	GdaDsnInfo *dsn_info;
1105 	gchar *user, *pass, *real_dsn;
1106 	gchar *real_auth_string = NULL;
1107 
1108 	g_return_val_if_fail (dsn && *dsn, NULL);
1109 
1110 	if (((options & GDA_CONNECTION_OPTIONS_THREAD_SAFE) || (options & GDA_CONNECTION_OPTIONS_THREAD_SAFE)) &&
1111 	    !g_thread_supported ()) {
1112 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_UNSUPPORTED_THREADS_ERROR,
1113 			      "%s", _("Multi threading is not supported or enabled"));
1114 		return NULL;
1115 	}
1116 
1117 	gda_dsn_split (dsn, &real_dsn, &user, &pass);
1118 	if (!real_dsn) {
1119 		g_free (user);
1120 		g_free (pass);
1121 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR,
1122 			     _("Malformed data source specification '%s'"), dsn);
1123 		return NULL;
1124 	}
1125 
1126 	/* get the data source info */
1127 	dsn_info = gda_config_get_dsn_info (real_dsn);
1128 	if (!dsn_info) {
1129 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR,
1130 			     _("Data source %s not found in configuration"), real_dsn);
1131 		g_free (real_dsn);
1132 		g_free (user);
1133 		g_free (pass);
1134 		return NULL;
1135 	}
1136 	if (!auth_string && user) {
1137 		gchar *s1;
1138 		s1 = gda_rfc1738_encode (user);
1139 		if (pass) {
1140 			gchar *s2;
1141 			s2 = gda_rfc1738_encode (pass);
1142 			real_auth_string = g_strdup_printf ("USERNAME=%s;PASSWORD=%s", s1, s2);
1143 			g_free (s2);
1144 		}
1145 		else
1146 			real_auth_string = g_strdup_printf ("USERNAME=%s", s1);
1147 		g_free (s1);
1148 	}
1149 
1150 	/* try to find provider */
1151 	if (dsn_info->provider != NULL) {
1152 		GdaProviderInfo *pinfo;
1153 		GdaServerProvider *prov = NULL;
1154 
1155 		pinfo = gda_config_get_provider_info (dsn_info->provider);
1156 		if (pinfo) {
1157 			prov = gda_config_get_provider (dsn_info->provider, error);
1158 			if (((options & GDA_CONNECTION_OPTIONS_THREAD_SAFE) &&
1159 			     !gda_server_provider_supports_feature (prov, NULL,
1160 								    GDA_CONNECTION_FEATURE_MULTI_THREADING)) ||
1161 			    (options & GDA_CONNECTION_OPTIONS_THREAD_ISOLATED)) {
1162 				options |= GDA_CONNECTION_OPTIONS_THREAD_ISOLATED;
1163 				prov = _gda_connection_get_internal_thread_provider ();
1164 			}
1165 		}
1166 		else
1167 			g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_PROVIDER_NOT_FOUND_ERROR,
1168 				     _("No provider '%s' installed"), dsn_info->provider);
1169 
1170 		if (prov) {
1171 			if (PROV_CLASS (prov)->create_connection) {
1172 				cnc = PROV_CLASS (prov)->create_connection (prov);
1173 				if (cnc)
1174 					g_object_set (G_OBJECT (cnc),
1175 						      "provider", prov,
1176 						      "dsn", real_dsn,
1177 						      "auth-string", auth_string ? auth_string : real_auth_string,
1178 						      "options", options, NULL);
1179 			}
1180 			else
1181 				cnc = g_object_new (GDA_TYPE_CONNECTION,
1182 						    "provider", prov,
1183 						    "dsn", real_dsn,
1184 						    "auth-string", auth_string ? auth_string : real_auth_string,
1185 						    "options", options, NULL);
1186 		}
1187 	}
1188 	else
1189 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_PROVIDER_NOT_FOUND_ERROR,
1190 			      "%s", _("Datasource configuration error: no provider specified"));
1191 
1192 	g_free (real_auth_string);
1193 	g_free (real_dsn);
1194 	g_free (user);
1195 	g_free (pass);
1196 	return cnc;
1197 }
1198 
1199 /**
1200  * gda_connection_open_from_dsn:
1201  * @dsn: data source name.
1202  * @auth_string: (allow-none): authentication string, or %NULL
1203  * @options: options for the connection (see #GdaConnectionOptions).
1204  * @error: a place to store an error, or %NULL
1205  *
1206  * This function is the way of opening database connections with libgda, using a pre-defined data source (DSN),
1207  * see gda_config_define_dsn() for more information about how to define a DSN. If you don't want to define
1208  * a DSN, it is possible to use gda_connection_open_from_string() instead of this method.
1209  *
1210  * The @dsn string must have the following format: "[&lt;username&gt;[:&lt;password&gt;]@]&lt;DSN&gt;"
1211  * (if &lt;username&gt; and/or &lt;password&gt; are provided, and @auth_string is %NULL, then these username
1212  * and passwords will be used). Note that if provided, &lt;username&gt; and &lt;password&gt;
1213  * must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information.
1214  *
1215  * The @auth_string can contain the authentication information for the server
1216  * to accept the connection. It is a string containing semi-colon seperated named value, usually
1217  * like "USERNAME=...;PASSWORD=..." where the ... are replaced by actual values. Note that each
1218  * name and value must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information.
1219  *
1220  * The actual named parameters required depend on the provider being used, and that list is available
1221  * as the <parameter>auth_params</parameter> member of the #GdaProviderInfo structure for each installed
1222  * provider (use gda_config_get_provider_info() to get it). Also one can use the "gda-sql-5.0 -L" command to
1223  * list the possible named parameters.
1224  *
1225  * This method may fail with a GDA_CONNECTION_ERROR domain error (see the #GdaConnectionError error codes)
1226  * or a %GDA_CONFIG_ERROR domain error (see the #GdaConfigError error codes).
1227  *
1228  * Returns: (transfer full): a new #GdaConnection if connection opening was successful or %NULL if there was an error.
1229  */
1230 GdaConnection *
gda_connection_open_from_dsn(const gchar * dsn,const gchar * auth_string,GdaConnectionOptions options,GError ** error)1231 gda_connection_open_from_dsn (const gchar *dsn, const gchar *auth_string,
1232 			      GdaConnectionOptions options, GError **error)
1233 {
1234 	GdaConnection *cnc;
1235 	cnc = gda_connection_new_from_dsn (dsn, auth_string, options, error);
1236 	if (cnc && !gda_connection_open (cnc, error)) {
1237 		g_object_unref (cnc);
1238 		cnc = NULL;
1239 	}
1240 	return cnc;
1241 }
1242 
1243 
1244 /**
1245  * gda_connection_new_from_string:
1246  * @provider_name: (allow-none): provider ID to connect to, or %NULL
1247  * @cnc_string: connection string.
1248  * @auth_string: (allow-none): authentication string, or %NULL
1249  * @options: options for the connection (see #GdaConnectionOptions).
1250  * @error: a place to store an error, or %NULL
1251  *
1252  * This function is similar to gda_connection_open_from_string(), except it does not actually open the
1253  * connection, you have to open it using gda_connection_open().
1254  *
1255  * Returns: (transfer full): a new #GdaConnection if connection opening was successful or %NULL if there was an error.
1256  *
1257  * Since: 5.0.2
1258  */
1259 GdaConnection *
gda_connection_new_from_string(const gchar * provider_name,const gchar * cnc_string,const gchar * auth_string,GdaConnectionOptions options,GError ** error)1260 gda_connection_new_from_string (const gchar *provider_name, const gchar *cnc_string, const gchar *auth_string,
1261 				 GdaConnectionOptions options, GError **error)
1262 {
1263 	GdaConnection *cnc = NULL;
1264 	gchar *user, *pass, *real_cnc, *real_provider;
1265 	gchar *real_auth_string = NULL;
1266 
1267 	g_return_val_if_fail (cnc_string && *cnc_string, NULL);
1268 
1269 	if (options & GDA_CONNECTION_OPTIONS_THREAD_SAFE &&
1270 	    !g_thread_supported ()) {
1271 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_UNSUPPORTED_THREADS_ERROR,
1272 			      "%s", _("Multi threading is not supported or enabled"));
1273 		return NULL;
1274 	}
1275 
1276 	gda_connection_string_split (cnc_string, &real_cnc, &real_provider, &user, &pass);
1277 	if (!real_cnc) {
1278 		g_free (user);
1279 		g_free (pass);
1280 		g_free (real_provider);
1281 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR,
1282 			     _("Malformed connection string '%s'"), cnc_string);
1283 		return NULL;
1284 	}
1285 
1286 	if (!provider_name && !real_provider) {
1287 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_PROVIDER_NOT_FOUND_ERROR,
1288 			      "%s", _("No database driver specified"));
1289 		g_free (user);
1290 		g_free (pass);
1291 		g_free (real_cnc);
1292 		return NULL;
1293 	}
1294 
1295 	if (!auth_string && user) {
1296 		gchar *s1;
1297 		s1 = gda_rfc1738_encode (user);
1298 		if (pass) {
1299 			gchar *s2;
1300 			s2 = gda_rfc1738_encode (pass);
1301 			real_auth_string = g_strdup_printf ("USERNAME=%s;PASSWORD=%s", s1, s2);
1302 			g_free (s2);
1303 		}
1304 		else
1305 			real_auth_string = g_strdup_printf ("USERNAME=%s", s1);
1306 		g_free (s1);
1307 	}
1308 
1309 	/* try to find provider */
1310 	if (provider_name || real_provider) {
1311 		GdaProviderInfo *pinfo;
1312 		GdaServerProvider *prov = NULL;
1313 
1314 		pinfo = gda_config_get_provider_info (provider_name ? provider_name : real_provider);
1315 		if (pinfo) {
1316 			prov = gda_config_get_provider (provider_name ? provider_name : real_provider, error);
1317 			if (((options & GDA_CONNECTION_OPTIONS_THREAD_SAFE) &&
1318 			     !gda_server_provider_supports_feature (prov, NULL,
1319 								    GDA_CONNECTION_FEATURE_MULTI_THREADING)) ||
1320 			    (options & GDA_CONNECTION_OPTIONS_THREAD_ISOLATED)) {
1321 				gchar *tmp;
1322 				tmp = g_strdup_printf ("%s;PROVIDER_NAME=%s", real_cnc, pinfo->id);
1323 				g_free (real_cnc);
1324 				real_cnc = tmp;
1325 				options |= GDA_CONNECTION_OPTIONS_THREAD_ISOLATED;
1326 				prov = _gda_connection_get_internal_thread_provider ();
1327 			}
1328 		}
1329 		else
1330 			g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_PROVIDER_NOT_FOUND_ERROR,
1331 				     _("No provider '%s' installed"), provider_name ? provider_name : real_provider);
1332 
1333 		if (prov) {
1334 			if (PROV_CLASS (prov)->create_connection) {
1335 				cnc = PROV_CLASS (prov)->create_connection (prov);
1336 				if (cnc)
1337 					g_object_set (G_OBJECT (cnc),
1338 						      "provider", prov,
1339 						      "cnc-string", real_cnc,
1340 						      "auth-string", auth_string ? auth_string : real_auth_string,
1341 						      "options", options, NULL);
1342 			}
1343 			else
1344 				cnc = (GdaConnection *) g_object_new (GDA_TYPE_CONNECTION,
1345 								      "provider", prov,
1346 								      "cnc-string", real_cnc,
1347 								      "auth-string", auth_string ? auth_string : real_auth_string,
1348 								      "options", options, NULL);
1349 		}
1350 	}
1351 
1352 	g_free (real_auth_string);
1353 	g_free (real_cnc);
1354 	g_free (user);
1355 	g_free (pass);
1356 	g_free (real_provider);
1357 
1358 	return cnc;
1359 }
1360 
1361 /**
1362  * gda_connection_open_from_string:
1363  * @provider_name: (allow-none): provider ID to connect to, or %NULL
1364  * @cnc_string: connection string.
1365  * @auth_string: (allow-none): authentication string, or %NULL
1366  * @options: options for the connection (see #GdaConnectionOptions).
1367  * @error: a place to store an error, or %NULL
1368  *
1369  * Opens a connection given a provider ID and a connection string. This
1370  * allows applications to open connections without having to create
1371  * a data source (DSN) in the configuration. The format of @cnc_string is
1372  * similar to PostgreSQL and MySQL connection strings. It is a semicolumn-separated
1373  * series of &lt;key&gt;=&lt;value&gt; pairs, where each key and value are encoded as per RFC 1738,
1374  * see gda_rfc1738_encode() for more information.
1375  *
1376  * The possible keys depend on the provider, the "gda-sql-5.0 -L" command
1377  * can be used to list the actual keys for each installed database provider.
1378  *
1379  * For example the connection string to open an SQLite connection to a database
1380  * file named "my_data.db" in the current directory would be <constant>"DB_DIR=.;DB_NAME=my_data"</constant>.
1381  *
1382  * The @cnc_string string must have the following format:
1383  * "[&lt;provider&gt;://][&lt;username&gt;[:&lt;password&gt;]@]&lt;connection_params&gt;"
1384  * (if &lt;username&gt; and/or &lt;password&gt; are provided, and @auth_string is %NULL, then these username
1385  * and passwords will be used, and if &lt;provider&gt; is provided and @provider_name is %NULL then this
1386  * provider will be used). Note that if provided, &lt;username&gt;, &lt;password&gt; and  &lt;provider&gt;
1387  * must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information.
1388  *
1389  * The @auth_string must contain the authentication information for the server
1390  * to accept the connection. It is a string containing semi-colon seperated named values, usually
1391  * like "USERNAME=...;PASSWORD=..." where the ... are replaced by actual values. Note that each
1392  * name and value must be encoded as per RFC 1738, see gda_rfc1738_encode() for more information.
1393  *
1394  * The actual named parameters required depend on the provider being used, and that list is available
1395  * as the <parameter>auth_params</parameter> member of the #GdaProviderInfo structure for each installed
1396  * provider (use gda_config_get_provider_info() to get it). Similarly to the format of the connection
1397  * string, use the "gda-sql-5.0 -L" command to list the possible named parameters.
1398  *
1399  * Additionally, it is possible to have the connection string
1400  * respect the "&lt;provider_name&gt;://&lt;real cnc string&gt;" format, in which case the provider name
1401  * and the real connection string will be extracted from that string (note that if @provider_name
1402  * is not %NULL then it will still be used as the provider ID).\
1403  *
1404  * This method may fail with a GDA_CONNECTION_ERROR domain error (see the #GdaConnectionError error codes)
1405  * or a %GDA_CONFIG_ERROR domain error (see the #GdaConfigError error codes).
1406  *
1407  * Returns: (transfer full): a new #GdaConnection if connection opening was successful or %NULL if there was an error.
1408  */
1409 GdaConnection *
gda_connection_open_from_string(const gchar * provider_name,const gchar * cnc_string,const gchar * auth_string,GdaConnectionOptions options,GError ** error)1410 gda_connection_open_from_string (const gchar *provider_name, const gchar *cnc_string, const gchar *auth_string,
1411 				 GdaConnectionOptions options, GError **error)
1412 {
1413 	GdaConnection *cnc;
1414 	cnc = gda_connection_new_from_string (provider_name, cnc_string, auth_string, options, error);
1415 	if (cnc && !gda_connection_open (cnc, error)) {
1416 		g_object_unref (cnc);
1417 		cnc = NULL;
1418 	}
1419 	return cnc;
1420 }
1421 
1422 
1423 /*
1424  * Uses _gda_config_sqlite_provider to open a connection
1425  */
1426 GdaConnection *
_gda_open_internal_sqlite_connection(const gchar * cnc_string)1427 _gda_open_internal_sqlite_connection (const gchar *cnc_string)
1428 {
1429 	GdaConnection *cnc;
1430 	GdaServerProvider *prov = _gda_config_sqlite_provider;
1431 	gchar *user, *pass, *real_cnc, *real_provider;
1432 
1433 	/*g_print ("%s(%s)\n", __FUNCTION__, cnc_string);*/
1434 	gda_connection_string_split (cnc_string, &real_cnc, &real_provider, &user, &pass);
1435         if (!real_cnc) {
1436                 g_free (user);
1437                 g_free (pass);
1438                 g_free (real_provider);
1439                 return NULL;
1440         }
1441 	if (PROV_CLASS (prov)->create_connection) {
1442 		cnc = PROV_CLASS (prov)->create_connection (prov);
1443 		if (cnc)
1444 			g_object_set (G_OBJECT (cnc),
1445 				      "provider", prov,
1446 				      "cnc-string", real_cnc,
1447 				      NULL);
1448 	}
1449 	else
1450 		cnc = (GdaConnection *) g_object_new (GDA_TYPE_CONNECTION,
1451 						      "provider", prov,
1452 						      "cnc-string", real_cnc,
1453 						      NULL);
1454 
1455 	g_free (real_cnc);
1456         g_free (user);
1457         g_free (pass);
1458         g_free (real_provider);
1459 
1460 	/* open the connection */
1461 	if (!gda_connection_open (cnc, NULL)) {
1462 		g_object_unref (cnc);
1463 		cnc = NULL;
1464 	}
1465 	return cnc;
1466 }
1467 
1468 static void
sqlite_connection_closed_cb(GdaConnection * cnc,G_GNUC_UNUSED gpointer data)1469 sqlite_connection_closed_cb (GdaConnection *cnc, G_GNUC_UNUSED gpointer data)
1470 {
1471 	gchar *filename;
1472 	filename = g_object_get_data (G_OBJECT (cnc), "__gda_fname");
1473 	g_assert (filename && *filename);
1474 	g_unlink (filename);
1475 }
1476 
1477 /**
1478  * gda_connection_open_sqlite:
1479  * @directory: (allow-none): the directory the database file will be in, or %NULL for the default TMP directory
1480  * @filename: the database file name
1481  * @auto_unlink: if %TRUE, then the database file will be removed afterwards
1482  *
1483  * Opens an SQLite connection even if the SQLite provider is not installed,
1484  * to be used by database providers which need a temporary database to store
1485  * some information.
1486  *
1487  * Returns: (transfer full): a new #GdaConnection, or %NULL if an error occurred
1488  */
1489 GdaConnection *
gda_connection_open_sqlite(const gchar * directory,const gchar * filename,gboolean auto_unlink)1490 gda_connection_open_sqlite (const gchar *directory, const gchar *filename, gboolean auto_unlink)
1491 {
1492 	GdaConnection *cnc;
1493 	gchar *fname;
1494 	gint fd;
1495 
1496 	if (!directory)
1497 		directory = g_get_tmp_dir(); /* Flawfinder: ignore */
1498 	else
1499 		g_return_val_if_fail (*directory, NULL);
1500 	g_return_val_if_fail (filename && *filename, NULL);
1501 
1502 	fname = g_build_filename (directory, filename, NULL);
1503 #ifdef G_OS_WIN32
1504 	fd = g_open (fname, O_WRONLY | O_CREAT | O_TRUNC,
1505 		     S_IRUSR | S_IWUSR);
1506 #else
1507 	fd = g_open (fname, O_WRONLY | O_CREAT | O_NOCTTY | O_TRUNC,
1508 		     S_IRUSR | S_IWUSR);
1509 #endif
1510 	if (fd == -1) {
1511 		g_free (fname);
1512 		return NULL;
1513 	}
1514 	close (fd);
1515 
1516 	gchar *tmp1, *tmp2, *cncstring;
1517 	tmp1 = gda_rfc1738_encode (directory);
1518 	tmp2 = gda_rfc1738_encode (filename);
1519 	cncstring = g_strdup_printf ("SQLite://DB_DIR=%s;DB_NAME=%s", tmp1, tmp2);
1520 	g_free (tmp1);
1521 	g_free (tmp2);
1522 
1523 	cnc = _gda_open_internal_sqlite_connection (cncstring);
1524 	g_free (cncstring);
1525 
1526 	if (auto_unlink) {
1527 		g_object_set_data_full (G_OBJECT (cnc), "__gda_fname", fname, g_free);
1528 		g_signal_connect (cnc, "conn-closed",
1529 				  G_CALLBACK (sqlite_connection_closed_cb), NULL);
1530 	}
1531 	else
1532 		g_free (fname);
1533 	return cnc;
1534 }
1535 
1536 /**
1537  * gda_connection_open:
1538  * @cnc: a #GdaConnection object
1539  * @error: a place to store errors, or %NULL
1540  *
1541  * Tries to open the connection.
1542  *
1543  * Returns: TRUE if the connection is opened, and FALSE otherwise.
1544  */
1545 gboolean
gda_connection_open(GdaConnection * cnc,GError ** error)1546 gda_connection_open (GdaConnection *cnc, GError **error)
1547 {
1548 	GdaDsnInfo *dsn_info = NULL;
1549 	GdaQuarkList *params, *auth;
1550 	char *real_auth_string = NULL;
1551 
1552 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1553 
1554 	/* don't do anything if connection is already opened */
1555 	if (cnc->priv->provider_data)
1556 		return TRUE;
1557 
1558 	gda_connection_lock ((GdaLockable*) cnc);
1559 
1560 	/* connection string */
1561 	if (cnc->priv->dsn) {
1562 		/* get the data source info */
1563 		dsn_info = gda_config_get_dsn_info (cnc->priv->dsn);
1564 		if (!dsn_info) {
1565 			gda_log_error (_("Data source %s not found in configuration"), cnc->priv->dsn);
1566 			g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR,
1567 				     _("Data source %s not found in configuration"), cnc->priv->dsn);
1568 			gda_connection_unlock ((GdaLockable*) cnc);
1569 			return FALSE;
1570 		}
1571 
1572 		g_free (cnc->priv->cnc_string);
1573 		cnc->priv->cnc_string = g_strdup (dsn_info->cnc_string);
1574 	}
1575 	else {
1576 		if (!cnc->priv->cnc_string) {
1577 			gda_log_error (_("No DSN or connection string specified"));
1578 			g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_NO_CNC_SPEC_ERROR,
1579 				      "%s", _("No DSN or connection string specified"));
1580 			gda_connection_unlock ((GdaLockable*) cnc);
1581 			return FALSE;
1582 		}
1583 		/* try to see if connection string has the <provider>://<rest of the string> format */
1584 	}
1585 
1586 	/* provider test */
1587 	if (!cnc->priv->provider_obj) {
1588 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_NO_PROVIDER_SPEC_ERROR,
1589 			      "%s", _("No provider specified"));
1590 		gda_connection_unlock ((GdaLockable*) cnc);
1591 		return FALSE;
1592 	}
1593 
1594 	/* if there is a limiting thread but it's not yet set, then initialize it to the current
1595 	 * thread */
1596 	if (PROV_CLASS (cnc->priv->provider_obj)->limiting_thread ==
1597 	    GDA_SERVER_PROVIDER_UNDEFINED_LIMITING_THREAD)
1598 		PROV_CLASS (cnc->priv->provider_obj)->limiting_thread = g_thread_self ();
1599 
1600 	if (PROV_CLASS (cnc->priv->provider_obj)->limiting_thread &&
1601 	    (PROV_CLASS (cnc->priv->provider_obj)->limiting_thread != g_thread_self ())) {
1602 		/* WARNING:
1603 		 * Prior to GLib 2.32, this code used to check if the
1604 		 * PROV_CLASS (cnc->priv->provider_obj)->limiting_thread
1605 		 * was still active (i.e. not finished) and if so, the
1606 		 * PROV_CLASS (cnc->priv->provider_obj)->limiting_thread would
1607 		 * become g_thread_self().
1608 		 *
1609 		 * Now, if PROV_CLASS (cnc->priv->provider_obj)->limiting_thread is set and
1610 		 * if it's not equal to g_thread_self() then an error is returned.
1611 		 */
1612 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_PROVIDER_ERROR,
1613 			     "%s", _("Provider does not allow usage from this thread"));
1614 		gda_connection_unlock ((GdaLockable*) cnc);
1615 		return FALSE;
1616 	}
1617 
1618 	if (!PROV_CLASS (cnc->priv->provider_obj)->open_connection) {
1619 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_PROVIDER_ERROR,
1620 			      "%s", _("Internal error: provider does not implement the open_connection() virtual method"));
1621 		gda_connection_unlock ((GdaLockable*) cnc);
1622 		return FALSE;
1623 	}
1624 
1625 	params = gda_quark_list_new_from_string (cnc->priv->cnc_string);
1626 
1627 	/* retrieve correct auth_string */
1628 	if (cnc->priv->auth_string)
1629 		real_auth_string = g_strdup (cnc->priv->auth_string);
1630 	else {
1631 		if (dsn_info && dsn_info->auth_string)
1632 			real_auth_string = g_strdup (dsn_info->auth_string);
1633 		else
1634 			/* look for authentication parameters in cnc string */
1635 			real_auth_string = g_strdup (cnc->priv->cnc_string);
1636 	}
1637 
1638 	/* try to open the connection */
1639 	auth = gda_quark_list_new_from_string (real_auth_string);
1640 	gboolean opened;
1641 
1642 	opened = PROV_CLASS (cnc->priv->provider_obj)->open_connection (cnc->priv->provider_obj, cnc, params, auth,
1643 									NULL, NULL, NULL);
1644 	gda_quark_list_protect_values (params);
1645 	gda_quark_list_protect_values (auth);
1646 
1647 	if (opened && !cnc->priv->provider_data) {
1648 		g_warning ("Internal error: connection reported as opened, yet no provider data set");
1649 		opened = FALSE;
1650 	}
1651 
1652 	if (!opened) {
1653 		const GList *events;
1654 
1655 		events = gda_connection_get_events (cnc);
1656 		if (events) {
1657 			GList *l;
1658 
1659 			for (l = g_list_last ((GList*) events); l; l = l->prev) {
1660 				GdaConnectionEvent *event;
1661 
1662 				event = GDA_CONNECTION_EVENT (l->data);
1663 				if (gda_connection_event_get_event_type (event) == GDA_CONNECTION_EVENT_ERROR) {
1664 					if (error && !(*error))
1665 						g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_OPEN_ERROR,
1666 							     "%s", gda_connection_event_get_description (event));
1667 				}
1668 			}
1669 		}
1670 	}
1671 
1672 	/* free memory */
1673 	gda_quark_list_free (params);
1674 	gda_quark_list_free (auth);
1675 	g_free (real_auth_string);
1676 
1677 	if (cnc->priv->provider_data) {
1678 #ifdef GDA_DEBUG_signal
1679 		g_print (">> 'CONN_OPENED' from %s\n", __FUNCTION__);
1680 #endif
1681 		g_signal_emit (G_OBJECT (cnc), gda_connection_signals[CONN_OPENED], 0);
1682 #ifdef GDA_DEBUG_signal
1683 		g_print ("<< 'CONN_OPENED' from %s\n", __FUNCTION__);
1684 #endif
1685 	}
1686 
1687 	/* limit connection's usable thread */
1688 	if (PROV_CLASS (cnc->priv->provider_obj)->limiting_thread)
1689 		g_object_set (G_OBJECT (cnc), "thread-owner",
1690 			      PROV_CLASS (cnc->priv->provider_obj)->limiting_thread, NULL);
1691 
1692 
1693 	gda_connection_unlock ((GdaLockable*) cnc);
1694 	return cnc->priv->provider_data ? TRUE : FALSE;
1695 }
1696 
1697 
1698 /**
1699  * gda_connection_close:
1700  * @cnc: a #GdaConnection object.
1701  *
1702  * Closes the connection to the underlying data source, but first emits the
1703  * "conn-to-close" signal.
1704  */
1705 void
gda_connection_close(GdaConnection * cnc)1706 gda_connection_close (GdaConnection *cnc)
1707 {
1708 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
1709 
1710 	if (! cnc->priv->provider_data)
1711 		return;
1712 
1713 	gda_connection_lock ((GdaLockable*) cnc);
1714 #ifdef GDA_DEBUG_signal
1715         g_print (">> 'CONN_TO_CLOSE' from %s\n", __FUNCTION__);
1716 #endif
1717         g_signal_emit (G_OBJECT (cnc), gda_connection_signals[CONN_TO_CLOSE], 0);
1718 #ifdef GDA_DEBUG_signal
1719         g_print ("<< 'CONN_TO_CLOSE' from %s\n", __FUNCTION__);
1720 #endif
1721 
1722         gda_connection_close_no_warning (cnc);
1723 	gda_connection_unlock ((GdaLockable*) cnc);
1724 }
1725 
1726 static void
add_connection_event_from_error(GdaConnection * cnc,GError ** error)1727 add_connection_event_from_error (GdaConnection *cnc, GError **error)
1728 {
1729 	GdaConnectionEvent *event;
1730 	gchar *str;
1731 	event = GDA_CONNECTION_EVENT (g_object_new (GDA_TYPE_CONNECTION_EVENT,
1732 							  "type", (int)GDA_CONNECTION_EVENT_WARNING, NULL));
1733 	str = g_strdup_printf (_("Error while maintaining the meta data up to date: %s"),
1734 			       error && *error && (*error)->message ? (*error)->message : _("No detail"));
1735 	gda_connection_event_set_description (event, str);
1736 	g_free (str);
1737 	if (error)
1738 		g_clear_error (error);
1739 	gda_connection_add_event (cnc, event);
1740 }
1741 
1742 /**
1743  * gda_connection_close_no_warning:
1744  * @cnc: a #GdaConnection object.
1745  *
1746  * Closes the connection to the underlying data source, without emiting any warning signal.
1747  */
1748 void
gda_connection_close_no_warning(GdaConnection * cnc)1749 gda_connection_close_no_warning (GdaConnection *cnc)
1750 {
1751 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
1752 
1753 	g_object_ref (cnc);
1754 	gda_connection_lock ((GdaLockable*) cnc);
1755 
1756 	if (cnc->priv->monitor_id > 0) {
1757 		g_source_remove (cnc->priv->monitor_id);
1758 		cnc->priv->monitor_id = 0;
1759 	}
1760 
1761 	if (! cnc->priv->provider_data) {
1762 		g_object_unref (cnc);
1763 		gda_connection_unlock ((GdaLockable*) cnc);
1764 		return;
1765 	}
1766 
1767 	if (cnc->priv->meta_store &&
1768 	    cnc->priv->trans_meta_context &&
1769 	    gda_connection_get_transaction_status (cnc)) {
1770 		GdaConnection *mscnc;
1771 		mscnc = gda_meta_store_get_internal_connection (cnc->priv->meta_store);
1772 		if (cnc != mscnc) {
1773 			gsize i;
1774 			for (i = 0; i < cnc->priv->trans_meta_context->len; i++) {
1775 				GdaMetaContext *context;
1776 				GError *lerror = NULL;
1777 				context = g_array_index (cnc->priv->trans_meta_context, GdaMetaContext*, i);
1778 				if (! gda_connection_update_meta_store (cnc, context, &lerror))
1779 					add_connection_event_from_error (cnc, &lerror);
1780 				auto_update_meta_context_free (context);
1781 			}
1782 			g_array_free (cnc->priv->trans_meta_context, TRUE);
1783 			cnc->priv->trans_meta_context = NULL;
1784 		}
1785 	}
1786 
1787 	/* get rid of prepared statements to avoid problems */
1788 	if (cnc->priv->prepared_stmts) {
1789 		g_hash_table_foreach (cnc->priv->prepared_stmts,
1790 				      (GHFunc) prepared_stms_foreach_func, cnc);
1791 		g_hash_table_destroy (cnc->priv->prepared_stmts);
1792 		cnc->priv->prepared_stmts = NULL;
1793 	}
1794 
1795 	/* really close connection */
1796 	if (PROV_CLASS (cnc->priv->provider_obj)->close_connection)
1797 		PROV_CLASS (cnc->priv->provider_obj)->close_connection (cnc->priv->provider_obj,
1798 									cnc);
1799 	if (cnc->priv->provider_data) {
1800 		if (cnc->priv->provider_data_destroy_func)
1801 			cnc->priv->provider_data_destroy_func (cnc->priv->provider_data);
1802 		else if (cnc->priv->provider_data != cnc->priv->th_data)
1803 			g_warning ("Provider did not clean its connection data");
1804 		cnc->priv->provider_data = NULL;
1805 	}
1806 
1807 	gda_connection_unlock ((GdaLockable*) cnc);
1808 #ifdef GDA_DEBUG_signal
1809         g_print (">> 'CONN_CLOSED' from %s\n", __FUNCTION__);
1810 #endif
1811         g_signal_emit (G_OBJECT (cnc), gda_connection_signals[CONN_CLOSED], 0);
1812 #ifdef GDA_DEBUG_signal
1813         g_print ("<< 'CONN_CLOSED' from %s\n", __FUNCTION__);
1814 #endif
1815 	g_object_unref (cnc);
1816 }
1817 
1818 
1819 /**
1820  * gda_connection_is_opened:
1821  * @cnc: a #GdaConnection object.
1822  *
1823  * Checks whether a connection is open or not.
1824  *
1825  * Returns: %TRUE if the connection is open, %FALSE if it's not.
1826  */
1827 gboolean
gda_connection_is_opened(GdaConnection * cnc)1828 gda_connection_is_opened (GdaConnection *cnc)
1829 {
1830         g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1831 
1832 	return cnc->priv->provider_data ? TRUE : FALSE;
1833 }
1834 
1835 
1836 /**
1837  * gda_connection_get_options:
1838  * @cnc: a #GdaConnection object.
1839  *
1840  * Gets the #GdaConnectionOptions used to open this connection.
1841  *
1842  * Returns: the connection options.
1843  */
1844 GdaConnectionOptions
gda_connection_get_options(GdaConnection * cnc)1845 gda_connection_get_options (GdaConnection *cnc)
1846 {
1847 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), -1);
1848 
1849 	return cnc->priv->options;
1850 }
1851 
1852 /**
1853  * gda_connection_get_provider:
1854  * @cnc: a #GdaConnection object
1855  *
1856  * Gets a pointer to the #GdaServerProvider object used to access the database
1857  *
1858  * Returns: (transfer none): the #GdaServerProvider (NEVER NULL)
1859  */
1860 GdaServerProvider *
gda_connection_get_provider(GdaConnection * cnc)1861 gda_connection_get_provider (GdaConnection *cnc)
1862 {
1863 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
1864 
1865 	return cnc->priv->provider_obj;
1866 }
1867 
1868 /**
1869  * gda_connection_get_provider_name:
1870  * @cnc: a #GdaConnection object
1871  *
1872  * Gets the name (identifier) of the database provider used by @cnc
1873  *
1874  * Returns: a non modifiable string
1875  */
1876 const gchar *
gda_connection_get_provider_name(GdaConnection * cnc)1877 gda_connection_get_provider_name (GdaConnection *cnc)
1878 {
1879 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
1880 	if (!cnc->priv->provider_obj)
1881 		return NULL;
1882 
1883 	return gda_server_provider_get_name (cnc->priv->provider_obj);
1884 }
1885 
1886 /**
1887  * gda_connection_get_dsn:
1888  * @cnc: a #GdaConnection object
1889  *
1890  * Returns: the data source name the connection object is connected
1891  * to.
1892  */
1893 const gchar *
gda_connection_get_dsn(GdaConnection * cnc)1894 gda_connection_get_dsn (GdaConnection *cnc)
1895 {
1896 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
1897 
1898 	return (const gchar *) cnc->priv->dsn;
1899 }
1900 
1901 /**
1902  * gda_connection_get_cnc_string:
1903  * @cnc: a #GdaConnection object.
1904  *
1905  * Gets the connection string used to open this connection.
1906  *
1907  * The connection string is the string sent over to the underlying
1908  * database provider, which describes the parameters to be used
1909  * to open a connection on the underlying data source.
1910  *
1911  * Returns: the connection string used when opening the connection.
1912  */
1913 const gchar *
gda_connection_get_cnc_string(GdaConnection * cnc)1914 gda_connection_get_cnc_string (GdaConnection *cnc)
1915 {
1916 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
1917 
1918 	return (const gchar *) cnc->priv->cnc_string;
1919 }
1920 
1921 /**
1922  * gda_connection_get_authentication:
1923  * @cnc: a #GdaConnection object.
1924  *
1925  * Gets the user name used to open this connection.
1926  *
1927  * Returns: the user name.
1928  */
1929 const gchar *
gda_connection_get_authentication(GdaConnection * cnc)1930 gda_connection_get_authentication (GdaConnection *cnc)
1931 {
1932 	const gchar *str;
1933 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
1934 
1935 	str = (const gchar *) cnc->priv->auth_string;
1936 	if (!str)
1937 		str = "";
1938 	return str;
1939 }
1940 
1941 /**
1942  * gda_connection_get_date_format:
1943  * @cnc: a #GdaConnection object
1944  * @out_first: (out) (allow-none): the place to store the first part of the date, or %NULL
1945  * @out_second: (out) (allow-none): the place to store the second part of the date, or %NULL
1946  * @out_third: (out) (allow-none): the place to store the third part of the date, or %NULL
1947  * @out_sep: (out) (allow-none): the place to store the separator (used between year, month and day parts) part of the date, or %NULL
1948  * @error: (allow-none): a place to store errors, or %NULL
1949  *
1950  * This function allows you to determine the actual format for the date values.
1951  *
1952  * Returns: %TRUE if no error occurred
1953  *
1954  * Since: 5.2
1955  */
1956 gboolean
gda_connection_get_date_format(GdaConnection * cnc,GDateDMY * out_first,GDateDMY * out_second,GDateDMY * out_third,gchar * out_sep,GError ** error)1957 gda_connection_get_date_format (GdaConnection *cnc, GDateDMY *out_first,
1958 				GDateDMY *out_second, GDateDMY *out_third, gchar *out_sep,
1959 				GError **error)
1960 {
1961 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1962 
1963 	GdaDataHandler *dh;
1964 	dh = gda_server_provider_get_data_handler_g_type (cnc->priv->provider_obj, cnc, G_TYPE_DATE);
1965 	if (!dh) {
1966 		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
1967 			     "%s", _("Provider does not provide a GdaDataHandler for dates"));
1968 		return FALSE;
1969 	}
1970 
1971 	GDate *tdate;
1972 	tdate = g_date_new_dmy (15, 12, 2003);
1973 	g_assert (tdate && g_date_valid (tdate));
1974 
1975 	GValue *value;
1976 	value = gda_value_new (G_TYPE_DATE);
1977 	g_value_set_boxed (value, tdate);
1978 	g_date_free (tdate);
1979 
1980 	gchar *str;
1981 	str = gda_data_handler_get_str_from_value (dh, value);
1982 	gda_value_free (value);
1983 
1984 	/* parsing */
1985 	guint nb;
1986 	gchar *ptr;
1987 	GDateDMY order[3];
1988 	gchar sep;
1989 
1990 	/* 1st part */
1991 	for (nb = 0, ptr = str; *ptr; ptr++) {
1992 		if ((*ptr <= '9') && (*ptr >= '0'))
1993 			nb = nb * 10 + (*ptr - '0');
1994 		else
1995 			break;
1996 	}
1997 	if (nb == 2003)
1998 		order[0] = G_DATE_YEAR;
1999 	else if (nb == 12)
2000 		order[0] = G_DATE_MONTH;
2001 	else if (nb == 15)
2002 		order[0] = G_DATE_DAY;
2003 	else {
2004 		g_free (str);
2005 		return FALSE;
2006 	}
2007 
2008 	/* separator */
2009 	sep = *ptr;
2010 	if (!sep) {
2011 		g_free (str);
2012 		return FALSE;
2013 	}
2014 
2015 	/* 2nd part */
2016 	for (nb = 0, ptr++; *ptr; ptr++) {
2017 		if ((*ptr <= '9') && (*ptr >= '0'))
2018 			nb = nb * 10 + (*ptr - '0');
2019 		else
2020 			break;
2021 	}
2022 	if (nb == 2003)
2023 		order[1] = G_DATE_YEAR;
2024 	else if (nb == 12)
2025 		order[1] = G_DATE_MONTH;
2026 	else if (nb == 15)
2027 		order[1] = G_DATE_DAY;
2028 	else {
2029 		g_free (str);
2030 		return FALSE;
2031 	}
2032 
2033 	if (sep != *ptr) {
2034 		g_free (str);
2035 		return FALSE;
2036 	}
2037 
2038 	/* 3rd part */
2039 	for (nb = 0, ptr++; *ptr; ptr++) {
2040 		if ((*ptr <= '9') && (*ptr >= '0'))
2041 			nb = nb * 10 + (*ptr - '0');
2042 		else
2043 			break;
2044 	}
2045 	if (nb == 2003)
2046 		order[2] = G_DATE_YEAR;
2047 	else if (nb == 12)
2048 		order[2] = G_DATE_MONTH;
2049 	else if (nb == 15)
2050 		order[2] = G_DATE_DAY;
2051 	else {
2052 		g_free (str);
2053 		return FALSE;
2054 	}
2055 	g_free (str);
2056 
2057 	/* result */
2058 	if (out_first)
2059 		*out_first = order [0];
2060 	if (out_second)
2061 		*out_second = order [1];
2062 	if (out_third)
2063 		*out_third = order [2];
2064 	if (out_sep)
2065 		*out_sep = sep;
2066 
2067 	return TRUE;
2068 }
2069 
2070 /**
2071  * gda_connection_insert_row_into_table:
2072  * @cnc: an opened connection
2073  * @table: table's name to insert into
2074  * @error: a place to store errors, or %NULL
2075  * @...: a list of string/GValue pairs with the name of the column to use and the
2076  * GValue pointer containing the value to insert for the column (value can be %NULL), finished by a %NULL. There must be
2077  * at least one column name and value
2078  *
2079  * This is a convenience function, which creates an INSERT statement and executes it using the values
2080  * provided. It internally relies on variables which makes it immune to SQL injection problems.
2081  *
2082  * The equivalent SQL command is: INSERT INTO &lt;table&gt; (&lt;column_name&gt; [,...]) VALUES (&lt;column_name&gt; = &lt;new_value&gt; [,...]).
2083  *
2084  * Returns: TRUE if no error occurred
2085  *
2086  * Since: 4.2.3
2087  */
2088 G_GNUC_NULL_TERMINATED
2089 gboolean
gda_connection_insert_row_into_table(GdaConnection * cnc,const gchar * table,GError ** error,...)2090 gda_connection_insert_row_into_table (GdaConnection *cnc, const gchar *table, GError **error, ...)
2091 {
2092 	GSList *clist = NULL;
2093 	GSList *vlist = NULL;
2094 	gboolean retval;
2095 	va_list  args;
2096 	gchar *col_name;
2097 
2098 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
2099 	g_return_val_if_fail (table && *table, FALSE);
2100 
2101 	va_start (args, error);
2102 	while ((col_name = va_arg (args, gchar*))) {
2103 		clist = g_slist_prepend (clist, col_name);
2104 		GValue *value;
2105 		value = va_arg (args, GValue *);
2106 		vlist = g_slist_prepend (vlist, value);
2107 	}
2108 
2109 	va_end (args);
2110 
2111 	if (!clist) {
2112 		g_warning ("No specified column or value");
2113 		return FALSE;
2114 	}
2115 
2116 	clist = g_slist_reverse (clist);
2117 	vlist = g_slist_reverse (vlist);
2118 	retval = gda_connection_insert_row_into_table_v (cnc, table, clist, vlist, error);
2119 	g_slist_free (clist);
2120 	g_slist_free (vlist);
2121 
2122 	return retval;
2123 }
2124 
2125 /**
2126  * gda_connection_insert_row_into_table_v:
2127  * @cnc: an opened connection
2128  * @table: table's name to insert into
2129  * @col_names: (element-type utf8): a list of column names (as const gchar *)
2130  * @values: (element-type GValue): a list of values (as #GValue)
2131  * @error: a place to store errors, or %NULL
2132  *
2133  * @col_names and @values must have length (&gt;= 1).
2134  *
2135  * This is a convenience function, which creates an INSERT statement and executes it using the values
2136  * provided. It internally relies on variables which makes it immune to SQL injection problems.
2137  *
2138  * The equivalent SQL command is: INSERT INTO &lt;table&gt; (&lt;column_name&gt; [,...]) VALUES (&lt;column_name&gt; = &lt;new_value&gt; [,...]).
2139  *
2140  * Returns: TRUE if no error occurred, FALSE otherwise
2141  *
2142  * Since: 4.2.3
2143  */
2144 gboolean
gda_connection_insert_row_into_table_v(GdaConnection * cnc,const gchar * table,GSList * col_names,GSList * values,GError ** error)2145 gda_connection_insert_row_into_table_v (GdaConnection *cnc, const gchar *table,
2146 					GSList *col_names, GSList *values,
2147 					GError **error)
2148 {
2149 	gboolean retval;
2150 	GSList *fields = NULL;
2151 	GSList *expr_values = NULL;
2152 	GdaSqlStatement *sql_stm;
2153 	GdaSqlStatementInsert *ssi;
2154 	GdaStatement *insert;
2155 	gint i;
2156 
2157 	GSList *holders = NULL;
2158 	GSList *l1, *l2;
2159 
2160 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
2161 	g_return_val_if_fail (table && *table, FALSE);
2162 	g_return_val_if_fail (col_names, FALSE);
2163 	g_return_val_if_fail (g_slist_length (col_names) == g_slist_length (values), FALSE);
2164 
2165 	/* Construct insert query and list of GdaHolders */
2166 	sql_stm = gda_sql_statement_new (GDA_SQL_STATEMENT_INSERT);
2167 	ssi = (GdaSqlStatementInsert*) sql_stm->contents;
2168 	g_assert (GDA_SQL_ANY_PART (ssi)->type == GDA_SQL_ANY_STMT_INSERT);
2169 
2170 	ssi->table = gda_sql_table_new (GDA_SQL_ANY_PART (ssi));
2171 	ssi->table->table_name = gda_sql_identifier_quote (table, cnc, NULL, FALSE, FALSE);
2172 
2173 	i = 0;
2174 	for (l1 = col_names, l2 = values;
2175 	     l1;
2176 	     l1 = l1->next, l2 = l2->next) {
2177 		GdaSqlField *field;
2178 		GdaSqlExpr *expr;
2179 		GValue *value = (GValue *) l2->data;
2180 		const gchar *col_name = (const gchar*) l1->data;
2181 
2182 		/* field */
2183 		field = gda_sql_field_new (GDA_SQL_ANY_PART (ssi));
2184 		field->field_name = gda_sql_identifier_quote (col_name, cnc, NULL, FALSE, FALSE);
2185 		fields = g_slist_prepend (fields, field);
2186 
2187 		/* value */
2188 		expr = gda_sql_expr_new (GDA_SQL_ANY_PART (ssi));
2189 		if (value && (G_VALUE_TYPE (value) != GDA_TYPE_NULL)) {
2190 			/* create a GdaSqlExpr with a parameter */
2191 			GdaSqlParamSpec *param;
2192 			param = g_new0 (GdaSqlParamSpec, 1);
2193 			param->name = g_strdup_printf ("+%d", i);
2194 			param->g_type = G_VALUE_TYPE (value);
2195 			param->is_param = TRUE;
2196 			expr->param_spec = param;
2197 
2198 			GdaHolder *holder;
2199 			holder = (GdaHolder*)  g_object_new (GDA_TYPE_HOLDER, "g-type", G_VALUE_TYPE (value),
2200 							     "id", param->name, NULL);
2201 			g_assert (gda_holder_set_value (holder, value, NULL));
2202 			holders = g_slist_prepend (holders, holder);
2203 		}
2204 		else {
2205 			/* create a NULL GdaSqlExpr => nothing to do */
2206 		}
2207 		expr_values = g_slist_prepend (expr_values, expr);
2208 
2209 		i++;
2210 	}
2211 
2212 	ssi->fields_list = g_slist_reverse (fields);
2213 	ssi->values_list = g_slist_prepend (NULL, g_slist_reverse (expr_values));
2214 
2215 	insert = gda_statement_new ();
2216 	g_object_set (G_OBJECT (insert), "structure", sql_stm, NULL);
2217 	gda_sql_statement_free (sql_stm);
2218 
2219 	/* execute statement */
2220 	GdaSet *set = NULL;
2221 	if (holders) {
2222 		set = gda_set_new (holders);
2223 		g_slist_foreach (holders, (GFunc) g_object_unref, NULL);
2224 		g_slist_free (holders);
2225 	}
2226 
2227 	retval = (gda_connection_statement_execute_non_select (cnc, insert, set, NULL, error) == -1) ? FALSE : TRUE;
2228 
2229 	if (set)
2230 		g_object_unref (set);
2231 	g_object_unref (insert);
2232 
2233 	return retval;
2234 }
2235 
2236 /**
2237  * gda_connection_update_row_in_table:
2238  * @cnc: an opened connection
2239  * @table: the table's name with the row's values to be updated
2240  * @condition_column_name: the name of the column to used in the WHERE condition clause
2241  * @condition_value: the @condition_column_type's GType
2242  * @error: a place to store errors, or %NULL
2243  * @...: a list of string/GValue pairs with the name of the column to use and the
2244  * GValue pointer containing the value to update the column to (value can be %NULL), finished by a %NULL. There must be
2245  * at least one column name and value
2246  *
2247  * This is a convenience function, which creates an UPDATE statement and executes it using the values
2248  * provided. It internally relies on variables which makes it immune to SQL injection problems.
2249  *
2250  * The equivalent SQL command is: UPDATE &lt;table&gt; SET &lt;column_name&gt; = &lt;new_value&gt; [,...] WHERE &lt;condition_column_name&gt; = &lt;condition_value&gt;.
2251  *
2252  * Returns: TRUE if no error occurred, FALSE otherwise
2253  *
2254  * Since: 4.2.3
2255  */
2256 G_GNUC_NULL_TERMINATED
2257 gboolean
gda_connection_update_row_in_table(GdaConnection * cnc,const gchar * table,const gchar * condition_column_name,GValue * condition_value,GError ** error,...)2258 gda_connection_update_row_in_table (GdaConnection *cnc, const gchar *table,
2259 				    const gchar *condition_column_name,
2260 				    GValue *condition_value, GError **error, ...)
2261 {
2262 	GSList *clist = NULL;
2263 	GSList *vlist = NULL;
2264 	gboolean retval;
2265 	va_list  args;
2266 	gchar *col_name;
2267 
2268 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
2269 	g_return_val_if_fail (table && *table, FALSE);
2270 
2271 	va_start (args, error);
2272 	while ((col_name = va_arg (args, gchar*))) {
2273 		clist = g_slist_prepend (clist, col_name);
2274 		GValue *value;
2275 		value = va_arg (args, GValue *);
2276 		vlist = g_slist_prepend (vlist, value);
2277 	}
2278 
2279 	va_end (args);
2280 
2281 	if (!clist) {
2282 		g_warning ("No specified column or value");
2283 		return FALSE;
2284 	}
2285 
2286 	clist = g_slist_reverse (clist);
2287 	vlist = g_slist_reverse (vlist);
2288 	retval = gda_connection_update_row_in_table_v (cnc, table, condition_column_name, condition_value, clist, vlist, error);
2289 	g_slist_free (clist);
2290 	g_slist_free (vlist);
2291 
2292 	return retval;
2293 }
2294 
2295 /**
2296  * gda_connection_update_row_in_table_v:
2297  * @cnc: an opened connection
2298  * @table: the table's name with the row's values to be updated
2299  * @condition_column_name: the name of the column to used in the WHERE condition clause
2300  * @condition_value: the @condition_column_type's GType
2301  * @col_names: (element-type utf8): a list of column names (as const gchar *)
2302  * @values: (element-type GValue): a list of values (as #GValue)
2303  * @error: a place to store errors, or %NULL
2304  *
2305  * @col_names and @values must have length (&gt;= 1).
2306  *
2307  * This is a convenience function, which creates an UPDATE statement and executes it using the values
2308  * provided. It internally relies on variables which makes it immune to SQL injection problems.
2309  *
2310  * The equivalent SQL command is: UPDATE &lt;table&gt; SET &lt;column_name&gt; = &lt;new_value&gt; [,...] WHERE &lt;condition_column_name&gt; = &lt;condition_value&gt;.
2311  *
2312  * Returns: TRUE if no error occurred, FALSE otherwise
2313  *
2314  * Since: 4.2.3
2315  */
2316 gboolean
gda_connection_update_row_in_table_v(GdaConnection * cnc,const gchar * table,const gchar * condition_column_name,GValue * condition_value,GSList * col_names,GSList * values,GError ** error)2317 gda_connection_update_row_in_table_v (GdaConnection *cnc, const gchar *table,
2318 				      const gchar *condition_column_name,
2319 				      GValue *condition_value,
2320 				      GSList *col_names, GSList *values,
2321 				      GError **error)
2322 {
2323 	gboolean retval;
2324 	GSList *fields = NULL;
2325 	GSList *expr_values = NULL;
2326 	GdaSqlStatement *sql_stm;
2327 	GdaSqlStatementUpdate *ssu;
2328 	GdaStatement *update;
2329 	gint i;
2330 
2331 	GSList *holders = NULL;
2332 	GSList *l1, *l2;
2333 
2334 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
2335 	g_return_val_if_fail (table && *table, FALSE);
2336 	g_return_val_if_fail (col_names, FALSE);
2337 	g_return_val_if_fail (g_slist_length (col_names) == g_slist_length (values), FALSE);
2338 
2339 	/* Construct update query and list of GdaHolders */
2340 	sql_stm = gda_sql_statement_new (GDA_SQL_STATEMENT_UPDATE);
2341 	ssu = (GdaSqlStatementUpdate*) sql_stm->contents;
2342 	g_assert (GDA_SQL_ANY_PART (ssu)->type == GDA_SQL_ANY_STMT_UPDATE);
2343 
2344 	ssu->table = gda_sql_table_new (GDA_SQL_ANY_PART (ssu));
2345 	ssu->table->table_name = gda_sql_identifier_quote (table, cnc, NULL, FALSE, FALSE);
2346 
2347 	if (condition_column_name) {
2348 		GdaSqlExpr *where, *op;
2349 		where = gda_sql_expr_new (GDA_SQL_ANY_PART (ssu));
2350 		ssu->cond = where;
2351 
2352 		where->cond = gda_sql_operation_new (GDA_SQL_ANY_PART (where));
2353 		where->cond->operator_type = GDA_SQL_OPERATOR_TYPE_EQ;
2354 
2355 		op = gda_sql_expr_new (GDA_SQL_ANY_PART (where->cond));
2356 		where->cond->operands = g_slist_prepend (NULL, op);
2357 		op->value = gda_value_new (G_TYPE_STRING);
2358 		g_value_take_string (op->value, gda_sql_identifier_quote (condition_column_name, cnc, NULL,
2359 									  FALSE, FALSE));
2360 
2361 		op = gda_sql_expr_new (GDA_SQL_ANY_PART (where->cond));
2362 		where->cond->operands = g_slist_append (where->cond->operands, op);
2363 		if (condition_value) {
2364 			GdaSqlParamSpec *param;
2365 			param = g_new0 (GdaSqlParamSpec, 1);
2366 			param->name = g_strdup ("cond");
2367 			param->g_type = G_VALUE_TYPE (condition_value);
2368 			param->is_param = TRUE;
2369 			op->param_spec = param;
2370 
2371 			GdaHolder *holder;
2372 			holder = (GdaHolder*)  g_object_new (GDA_TYPE_HOLDER, "g-type", G_VALUE_TYPE (condition_value),
2373 							     "id", param->name, NULL);
2374 			g_assert (gda_holder_set_value (holder, condition_value, NULL));
2375 			holders = g_slist_prepend (holders, holder);
2376 		}
2377 		else {
2378 			/* nothing to do: NULL */
2379 		}
2380 	}
2381 
2382 	i = 0;
2383 	for (l1 = col_names, l2 = values;
2384 	     l1;
2385 	     l1 = l1->next, l2 = l2->next) {
2386 		GValue *value = (GValue *) l2->data;
2387 		const gchar *col_name = (const gchar*) l1->data;
2388 		GdaSqlField *field;
2389 		GdaSqlExpr *expr;
2390 
2391 		/* field */
2392 		field = gda_sql_field_new (GDA_SQL_ANY_PART (ssu));
2393 		field->field_name = gda_sql_identifier_quote (col_name, cnc, NULL, FALSE, FALSE);
2394 		fields = g_slist_prepend (fields, field);
2395 
2396 		/* value */
2397 		expr = gda_sql_expr_new (GDA_SQL_ANY_PART (ssu));
2398 		if (value && (G_VALUE_TYPE (value) != GDA_TYPE_NULL)) {
2399 			/* create a GdaSqlExpr with a parameter */
2400 			GdaSqlParamSpec *param;
2401 			param = g_new0 (GdaSqlParamSpec, 1);
2402 			param->name = g_strdup_printf ("+%d", i);
2403 			param->g_type = G_VALUE_TYPE (value);
2404 			param->is_param = TRUE;
2405 			expr->param_spec = param;
2406 
2407 			GdaHolder *holder;
2408 			holder = (GdaHolder*)  g_object_new (GDA_TYPE_HOLDER, "g-type", G_VALUE_TYPE (value),
2409 							     "id", param->name, NULL);
2410 			g_assert (gda_holder_set_value (holder, value, NULL));
2411 			holders = g_slist_prepend (holders, holder);
2412 		}
2413 		else {
2414 			/* create a NULL GdaSqlExpr => nothing to do */
2415 		}
2416 		expr_values = g_slist_prepend (expr_values, expr);
2417 
2418 		i++;
2419 	}
2420 
2421 	ssu->fields_list = g_slist_reverse (fields);
2422 	ssu->expr_list = g_slist_reverse (expr_values);
2423 
2424 	update = gda_statement_new ();
2425 	g_object_set (G_OBJECT (update), "structure", sql_stm, NULL);
2426 	gda_sql_statement_free (sql_stm);
2427 
2428 	/* execute statement */
2429 	GdaSet *set = NULL;
2430 	if (holders) {
2431 		set = gda_set_new (holders);
2432 		g_slist_foreach (holders, (GFunc) g_object_unref, NULL);
2433 		g_slist_free (holders);
2434 	}
2435 
2436 	retval = (gda_connection_statement_execute_non_select (cnc, update, set, NULL, error) == -1) ? FALSE : TRUE;
2437 
2438 	if (set)
2439 		g_object_unref (set);
2440 	g_object_unref (update);
2441 
2442 	return retval;
2443 }
2444 
2445 /**
2446  * gda_connection_delete_row_from_table:
2447  * @cnc: an opened connection
2448  * @table: the table's name with the row's values to be updated
2449  * @condition_column_name: the name of the column to used in the WHERE condition clause
2450  * @condition_value: the @condition_column_type's GType
2451  * @error: a place to store errors, or %NULL
2452  *
2453  * This is a convenience function, which creates a DELETE statement and executes it using the values
2454  * provided. It internally relies on variables which makes it immune to SQL injection problems.
2455  *
2456  * The equivalent SQL command is: DELETE FROM &lt;table&gt; WHERE &lt;condition_column_name&gt; = &lt;condition_value&gt;.
2457  *
2458  * Returns: TRUE if no error occurred, FALSE otherwise
2459  *
2460  * Since: 4.2.3
2461  */
2462 gboolean
gda_connection_delete_row_from_table(GdaConnection * cnc,const gchar * table,const gchar * condition_column_name,GValue * condition_value,GError ** error)2463 gda_connection_delete_row_from_table (GdaConnection *cnc, const gchar *table,
2464 				      const gchar *condition_column_name,
2465 				      GValue *condition_value, GError **error)
2466 {
2467 	gboolean retval;
2468 	GdaSqlStatement *sql_stm;
2469 	GdaSqlStatementDelete *ssd;
2470 	GdaStatement *delete;
2471 
2472 	GSList *holders = NULL;
2473 
2474 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
2475 	g_return_val_if_fail (table && *table, FALSE);
2476 
2477 	/* Construct delete query and list of GdaHolders */
2478 	sql_stm = gda_sql_statement_new (GDA_SQL_STATEMENT_DELETE);
2479 	ssd = (GdaSqlStatementDelete*) sql_stm->contents;
2480 	g_assert (GDA_SQL_ANY_PART (ssd)->type == GDA_SQL_ANY_STMT_DELETE);
2481 
2482 	ssd->table = gda_sql_table_new (GDA_SQL_ANY_PART (ssd));
2483 	ssd->table->table_name = gda_sql_identifier_quote (table, cnc, NULL, FALSE, FALSE);
2484 
2485 	if (condition_column_name) {
2486 		GdaSqlExpr *where, *op;
2487 		where = gda_sql_expr_new (GDA_SQL_ANY_PART (ssd));
2488 		ssd->cond = where;
2489 
2490 		where->cond = gda_sql_operation_new (GDA_SQL_ANY_PART (where));
2491 		where->cond->operator_type = GDA_SQL_OPERATOR_TYPE_EQ;
2492 
2493 		op = gda_sql_expr_new (GDA_SQL_ANY_PART (where->cond));
2494 		where->cond->operands = g_slist_prepend (NULL, op);
2495 		op->value = gda_value_new (G_TYPE_STRING);
2496 		g_value_take_string (op->value, gda_sql_identifier_quote (condition_column_name, cnc, NULL,
2497 									  FALSE, FALSE));
2498 
2499 		op = gda_sql_expr_new (GDA_SQL_ANY_PART (where->cond));
2500 		where->cond->operands = g_slist_append (where->cond->operands, op);
2501 		if (condition_value) {
2502 			GdaSqlParamSpec *param;
2503 			param = g_new0 (GdaSqlParamSpec, 1);
2504 			param->name = g_strdup ("cond");
2505 			param->g_type = G_VALUE_TYPE (condition_value);
2506 			param->is_param = TRUE;
2507 			op->param_spec = param;
2508 
2509 			GdaHolder *holder;
2510 			holder = (GdaHolder*)  g_object_new (GDA_TYPE_HOLDER, "g-type", G_VALUE_TYPE (condition_value),
2511 							     "id", param->name, NULL);
2512 			g_assert (gda_holder_set_value (holder, condition_value, NULL));
2513 			holders = g_slist_prepend (holders, holder);
2514 		}
2515 		else {
2516 			/* nothing to do: NULL */
2517 		}
2518 	}
2519 
2520 	delete = gda_statement_new ();
2521 	g_object_set (G_OBJECT (delete), "structure", sql_stm, NULL);
2522 	gda_sql_statement_free (sql_stm);
2523 
2524 	/* execute statement */
2525 	GdaSet *set = NULL;
2526 	if (holders) {
2527 		set = gda_set_new (holders);
2528 		g_slist_foreach (holders, (GFunc) g_object_unref, NULL);
2529 		g_slist_free (holders);
2530 	}
2531 
2532 	retval = (gda_connection_statement_execute_non_select (cnc, delete, set, NULL, error) == -1) ? FALSE : TRUE;
2533 
2534 	if (set)
2535 		g_object_unref (set);
2536 	g_object_unref (delete);
2537 
2538 	return retval;
2539 }
2540 
2541 /**
2542  * gda_connection_parse_sql_string:
2543  * @cnc: (allow-none): a #GdaConnection object, or %NULL
2544  * @sql: an SQL command to parse, not %NULL
2545  * @params: (out) (allow-none) (transfer full): a place to store a new #GdaSet, for parameters used in SQL command, or %NULL
2546  * @error: a place to store errors, or %NULL
2547  *
2548  * This function helps to parse a SQL string which uses parameters and store them at @params.
2549  *
2550  * Returns: (transfer full): a #GdaStatement representing the SQL command, or %NULL if an error occurred
2551  *
2552  * Since: 4.2.3
2553  */
2554 GdaStatement*
gda_connection_parse_sql_string(GdaConnection * cnc,const gchar * sql,GdaSet ** params,GError ** error)2555 gda_connection_parse_sql_string (GdaConnection *cnc, const gchar *sql, GdaSet **params, GError **error)
2556 {
2557 	GdaStatement *stmt;
2558 	GdaSqlParser *parser = NULL;
2559 
2560 	g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
2561 	g_return_val_if_fail (sql, NULL);
2562 
2563 	if (params)
2564 		*params = NULL;
2565 	if (cnc)
2566 		parser = gda_connection_create_parser (cnc);
2567 	if (!parser)
2568 		parser = gda_sql_parser_new ();
2569 
2570 	stmt = gda_sql_parser_parse_string (parser, sql, NULL, error);
2571 	g_object_unref (parser);
2572 	if (! stmt)
2573 		return NULL;
2574 
2575 	if (params && !gda_statement_get_parameters (stmt, params, error)) {
2576 		g_object_unref (stmt);
2577 		return NULL;
2578 	}
2579 
2580 	return stmt;
2581 }
2582 
2583 /**
2584  * gda_connection_point_available_event:
2585  * @cnc: a #GdaConnection object
2586  * @type: a #GdaConnectionEventType
2587  *
2588  * Use this method to get a pointer to the next available connection event which can then be customized
2589  * and taken into account using gda_connection_add_event().
2590  *
2591  * Returns: (transfer full): a pointer to the next available connection event, or %NULL if event should
2592  * be ignored
2593  *
2594  * Since: 4.2
2595  */
2596 GdaConnectionEvent *
gda_connection_point_available_event(GdaConnection * cnc,GdaConnectionEventType type)2597 gda_connection_point_available_event (GdaConnection *cnc, GdaConnectionEventType type)
2598 {
2599 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
2600 
2601 	/* ownership is transfered to the caller ! */
2602 
2603 	GdaConnectionEvent *eev;
2604 	eev = cnc->priv->events_array [cnc->priv->events_array_next];
2605 	if (!eev)
2606 		eev = GDA_CONNECTION_EVENT (g_object_new (GDA_TYPE_CONNECTION_EVENT,
2607 							  "type", (int)type, NULL));
2608 	else {
2609 		gda_connection_event_set_event_type (eev, type);
2610 		cnc->priv->events_array [cnc->priv->events_array_next] = NULL;
2611 	}
2612 
2613 	return eev;
2614 }
2615 
2616 #ifdef GDA_DEBUG_NO
2617 static void
dump_events_array(GdaConnection * cnc)2618 dump_events_array (GdaConnection *cnc)
2619 {
2620 	gint i;
2621 	g_print ("=== Array dump for %p ===\n", cnc);
2622 	for (i = 0; i < cnc->priv->events_array_size; i++) {
2623 		g_print ("   [%d] => %p\n", i, cnc->priv->events_array [i]);
2624 	}
2625 
2626 	const GList *list;
2627 	for (list = gda_connection_get_events (cnc); list; list = list->next) {
2628 		GdaConnectionEvent *ev = GDA_CONNECTION_EVENT (list->data);
2629 		g_print ("    => %p\n", ev);
2630 	}
2631 }
2632 #endif
2633 
2634 /**
2635  * gda_connection_add_event:
2636  * @cnc: a #GdaConnection object.
2637  * @event: (transfer full): is stored internally, so you don't need to unref it.
2638  *
2639  * Adds an event to the given connection. This function is usually
2640  * called by providers, to inform clients of events that happened
2641  * during some operation.
2642  *
2643  * As soon as a provider (or a client, it does not matter) calls this
2644  * function with an @event object which is an error,
2645  * the connection object emits the "error" signal, to which clients can connect to be
2646  * informed of events.
2647  *
2648  * WARNING: the reference to the @event object is stolen by this function!
2649  */
2650 void
gda_connection_add_event(GdaConnection * cnc,GdaConnectionEvent * event)2651 gda_connection_add_event (GdaConnection *cnc, GdaConnectionEvent *event)
2652 {
2653 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
2654 	g_return_if_fail (GDA_IS_CONNECTION_EVENT (event));
2655 
2656 	g_rec_mutex_lock (& cnc->priv->rmutex);
2657 
2658 	/* clear external list of events */
2659 	if (cnc->priv->events_list) {
2660 		g_list_foreach (cnc->priv->events_list, (GFunc) g_object_unref, NULL);
2661 		g_list_free (cnc->priv->events_list);
2662 		cnc->priv->events_list = NULL;
2663 	}
2664 
2665 	/* add event, ownership is transfered to @cnc */
2666 	GdaConnectionEvent *eev;
2667 	eev = cnc->priv->events_array [cnc->priv->events_array_next];
2668 	if (eev != event) {
2669 		if (eev)
2670 			g_object_unref (eev);
2671 		cnc->priv->events_array [cnc->priv->events_array_next] = event;
2672 	}
2673 
2674 	/* handle indexes */
2675 	cnc->priv->events_array_next ++;
2676 	if (cnc->priv->events_array_next == cnc->priv->events_array_size) {
2677 		cnc->priv->events_array_next = 0;
2678 		cnc->priv->events_array_full = TRUE;
2679 	}
2680 
2681 	if (debug_level > 0) {
2682 		const gchar *str = NULL;
2683 		switch (gda_connection_event_get_event_type (event)) {
2684 		case GDA_CONNECTION_EVENT_NOTICE:
2685 			if (debug_level & 1) str = "NOTICE";
2686 			break;
2687 		case GDA_CONNECTION_EVENT_WARNING:
2688 			if (debug_level & 2) str = "WARNING";
2689 			break;
2690 		case GDA_CONNECTION_EVENT_ERROR:
2691 			if (debug_level & 4) str = "ERROR";
2692 			break;
2693 		case GDA_CONNECTION_EVENT_COMMAND:
2694 			if (debug_level & 8) str = "COMMAND";
2695 			break;
2696 		default:
2697 			break;
2698 		}
2699 		if (str)
2700 			g_print ("EVENT> %s: %s (on cnx %p, %s)\n", str,
2701 				 gda_connection_event_get_description (event), cnc,
2702 				 gda_connection_event_get_sqlstate (event));
2703 	}
2704 
2705 	if (gda_connection_event_get_event_type (event) == GDA_CONNECTION_EVENT_ERROR)
2706 		g_signal_emit (G_OBJECT (cnc), gda_connection_signals[ERROR], 0, event);
2707 
2708 #ifdef GDA_DEBUG_NO
2709 	dump_events_array (cnc);
2710 #endif
2711 	g_rec_mutex_unlock (& cnc->priv->rmutex);
2712 }
2713 
2714 /**
2715  * gda_connection_add_event_string: (skip)
2716  * @cnc: a #GdaConnection object.
2717  * @str: a format string (see the printf(3) documentation).
2718  * @...: the arguments to insert in the error message.
2719  *
2720  * Adds a new error to the given connection object. This is just a convenience
2721  * function that simply creates a #GdaConnectionEvent and then calls
2722  * #gda_server_connection_add_error.
2723  *
2724  * Returns: (transfer none): a new #GdaConnectionEvent object, however the caller does not hold a reference to the returned object, and if need be the caller must call g_object_ref() on it.
2725  */
2726 GdaConnectionEvent *
gda_connection_add_event_string(GdaConnection * cnc,const gchar * str,...)2727 gda_connection_add_event_string (GdaConnection *cnc, const gchar *str, ...)
2728 {
2729 	GdaConnectionEvent *error;
2730 
2731 	va_list args;
2732 	gchar sz[2048];
2733 
2734 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
2735 	g_return_val_if_fail (str != NULL, NULL);
2736 
2737 	/* build the message string */
2738 	va_start (args, str);
2739 	g_vsnprintf (sz, 2048, str, args);
2740 	va_end (args);
2741 
2742 	error = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
2743 	gda_connection_event_set_description (error, sz);
2744 	gda_connection_event_set_code (error, -1);
2745 	gda_connection_event_set_source (error, gda_connection_get_provider_name (cnc));
2746 	gda_connection_event_set_sqlstate (error, "-1");
2747 
2748 	gda_connection_add_event (cnc, error);
2749 
2750 	return error;
2751 }
2752 
2753 static void
_clear_connection_events(GdaConnection * locked_cnc)2754 _clear_connection_events (GdaConnection *locked_cnc)
2755 {
2756 	if (locked_cnc->priv->auto_clear_events) {
2757 		locked_cnc->priv->events_array_full = FALSE;
2758 		locked_cnc->priv->events_array_next = 0;
2759 	}
2760 }
2761 
2762 /**
2763  * gda_connection_clear_events_list:
2764  * @cnc: a #GdaConnection object.
2765  *
2766  * This function lets you clear the list of #GdaConnectionEvent's of the
2767  * given connection.
2768  */
2769 void
gda_connection_clear_events_list(GdaConnection * cnc)2770 gda_connection_clear_events_list (GdaConnection *cnc)
2771 {
2772 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
2773 	gda_connection_lock ((GdaLockable*) cnc);
2774 	_clear_connection_events (cnc);
2775 	gda_connection_unlock ((GdaLockable*) cnc);
2776 }
2777 
2778 /**
2779  * gda_connection_create_operation:
2780  * @cnc: a #GdaConnection object
2781  * @type: the type of operation requested
2782  * @options: (allow-none): an optional list of parameters
2783  * @error: a place to store an error, or %NULL
2784  *
2785  * Creates a new #GdaServerOperation object which can be modified in order
2786  * to perform the type type of action. It is a wrapper around the gda_server_provider_create_operation()
2787  * method.
2788  *
2789  * Returns: (transfer full): a new #GdaServerOperation object, or %NULL in the connection's provider does not support the @type type
2790  * of operation or if an error occurred
2791  */
2792 GdaServerOperation*
gda_connection_create_operation(GdaConnection * cnc,GdaServerOperationType type,GdaSet * options,GError ** error)2793 gda_connection_create_operation (GdaConnection *cnc, GdaServerOperationType type,
2794                                  GdaSet *options, GError **error)
2795 {
2796 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
2797 	g_return_val_if_fail (cnc->priv->provider_obj, NULL);
2798 
2799 	return gda_server_provider_create_operation (cnc->priv->provider_obj, cnc, type, options, error);
2800 }
2801 
2802 /**
2803  * gda_connection_perform_operation:
2804  * @cnc: a #GdaConnection object
2805  * @op: a #GdaServerOperation object
2806  * @error: a place to store an error, or %NULL
2807  *
2808  * Performs the operation described by @op (which should have been created using
2809  * gda_connection_create_operation()). It is a wrapper around the gda_server_provider_perform_operation()
2810  * method.
2811  *
2812  * Returns: TRUE if no error occurred
2813  */
2814 gboolean
gda_connection_perform_operation(GdaConnection * cnc,GdaServerOperation * op,GError ** error)2815 gda_connection_perform_operation (GdaConnection *cnc, GdaServerOperation *op, GError **error)
2816 {
2817 	gboolean retval;
2818 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
2819 	g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
2820 	g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE);
2821 
2822 	cnc->priv->auto_clear_events = FALSE;
2823 	retval = gda_server_provider_perform_operation (cnc->priv->provider_obj, cnc, op, error);
2824 	cnc->priv->auto_clear_events = TRUE;
2825 	return retval;
2826 }
2827 
2828 /**
2829  * gda_connection_create_parser:
2830  * @cnc: a #GdaConnection object
2831  *
2832  * Creates a new parser object able to parse the SQL dialect understood by @cnc.
2833  * If the #GdaServerProvider object internally used by @cnc does not have its own parser,
2834  * then %NULL is returned, and a general SQL parser can be obtained
2835  * using gda_sql_parser_new().
2836  *
2837  * Returns: (transfer full): a new #GdaSqlParser object, or %NULL
2838  */
2839 GdaSqlParser *
gda_connection_create_parser(GdaConnection * cnc)2840 gda_connection_create_parser (GdaConnection *cnc)
2841 {
2842 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
2843 	g_return_val_if_fail (cnc->priv->provider_obj, NULL);
2844 
2845 	return gda_server_provider_create_parser (cnc->priv->provider_obj, cnc);
2846 }
2847 
2848 /*
2849  * Also resets the events list (as perceived when calling gda_connection_get_events()
2850  */
2851 static void
change_events_array_max_size(GdaConnection * cnc,gint size)2852 change_events_array_max_size (GdaConnection *cnc, gint size)
2853 {
2854 	size ++; /* add 1 to compensate the "lost" slot when rotating the events array */
2855 	if (size == cnc->priv->events_array_size)
2856 		return;
2857 
2858 	if (size > cnc->priv->events_array_size) {
2859 		gint i;
2860 		cnc->priv->events_array = g_renew (GdaConnectionEvent*, cnc->priv->events_array,
2861 						   size);
2862 		for (i = cnc->priv->events_array_size; i < size; i++)
2863 			cnc->priv->events_array [i] = NULL;
2864 	}
2865 	else if (size >= EVENTS_ARRAY_SIZE) {
2866 		gint i;
2867 		for (i = size; i < cnc->priv->events_array_size; i++) {
2868 			if (cnc->priv->events_array [i])
2869 				g_object_unref (cnc->priv->events_array [i]);
2870 		}
2871 		cnc->priv->events_array = g_renew (GdaConnectionEvent*, cnc->priv->events_array,
2872 						   size);
2873 	}
2874 	cnc->priv->events_array_size = size;
2875 	cnc->priv->events_array_full = FALSE;
2876 	cnc->priv->events_array_next = 0;
2877 }
2878 
2879 /**
2880  * gda_connection_batch_execute:
2881  * @cnc: a #GdaConnection object
2882  * @batch: a #GdaBatch object which contains all the statements to execute
2883  * @params: (allow-none): a #GdaSet object (which can be obtained using gda_batch_get_parameters()), or %NULL
2884  * @model_usage:  specifies how the returned data model(s) will be used, as a #GdaStatementModelUsage enum
2885  * @error: a place to store errors, or %NULL
2886  *
2887  * Executes all the statements contained in @batch (in the order in which they were added to @batch), and
2888  * returns a list of #GObject objects, at most one #GObject for each statement; see gda_connection_statement_execute()
2889  * for details about the returned objects.
2890  *
2891  * If one of the statement fails, then none of the subsequent statement will be executed, and the method returns
2892  * the list of #GObject created by the correct execution of the previous statements. If a transaction is required,
2893  * then it should be started before calling this method.
2894  *
2895  * Returns: (transfer full) (element-type GObject): a new list of #GObject objects
2896  */
2897 GSList *
gda_connection_batch_execute(GdaConnection * cnc,GdaBatch * batch,GdaSet * params,GdaStatementModelUsage model_usage,GError ** error)2898 gda_connection_batch_execute (GdaConnection *cnc, GdaBatch *batch, GdaSet *params,
2899 			      GdaStatementModelUsage model_usage, GError **error)
2900 {
2901 	GSList *retlist = NULL, *stmt_list;
2902 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
2903 	g_return_val_if_fail (GDA_IS_BATCH (batch), NULL);
2904 
2905 	gda_connection_lock ((GdaLockable*) cnc);
2906 	cnc->priv->auto_clear_events = FALSE;
2907 
2908 	/* increase the size of cnc->priv->events_array to be able to store all the
2909 	 * connection events */
2910 	stmt_list = (GSList*) gda_batch_get_statements (batch);
2911 	change_events_array_max_size (cnc, g_slist_length (stmt_list) * 2);
2912 
2913 	for (; stmt_list; stmt_list = stmt_list->next) {
2914 		GObject *obj;
2915 		obj = gda_connection_statement_execute (cnc, GDA_STATEMENT (stmt_list->data), params,
2916 							model_usage, NULL, error);
2917 		if (!obj)
2918 			break;
2919 		retlist = g_slist_prepend (retlist, obj);
2920 	}
2921 	cnc->priv->auto_clear_events = TRUE;
2922 	gda_connection_unlock ((GdaLockable*) cnc);
2923 
2924 	return g_slist_reverse (retlist);
2925 }
2926 
2927 
2928 /**
2929  * gda_connection_quote_sql_identifier:
2930  * @cnc: a #GdaConnection object
2931  * @id: an SQL identifier
2932  *
2933  * Use this method to get a correctly quoted (if necessary) SQL identifier which can be used
2934  * in SQL statements, from @id. If @id is already correctly quoted for @cnc, then a copy of @id
2935  * may be returned.
2936  *
2937  * This method may add double quotes (or other characters) around @id:
2938  * <itemizedlist>
2939  *  <listitem><para>if @id is a reserved SQL keyword (such as SELECT, INSERT, ...)</para></listitem>
2940  *  <listitem><para>if @id contains non allowed characters such as spaces, or if it starts with a digit</para></listitem>
2941  *  <listitem><para>in any other event as necessary for @cnc, depending on the the options passed when opening the @cnc
2942  *            connection, and specifically the <link linkend="GDA-CONNECTION-OPTIONS-SQL-IDENTIFIERS-CASE-SENSITIVE:CAPS">
2943  *            GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE</link> option.</para></listitem>
2944  * </itemizedlist>
2945  *
2946  * One can safely pass an already quoted @id to this method, either with quoting characters allowed by @cnc or using the
2947  * double quote (") character.
2948  *
2949  * Returns: a new string, to free with g_free() once not needed anymore
2950  *
2951  * Since: 4.0.3
2952  */
2953 gchar *
gda_connection_quote_sql_identifier(GdaConnection * cnc,const gchar * id)2954 gda_connection_quote_sql_identifier (GdaConnection *cnc, const gchar *id)
2955 {
2956 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
2957 	g_return_val_if_fail (id, NULL);
2958 
2959 	return gda_sql_identifier_quote (id, cnc, NULL, FALSE,
2960 					 cnc->priv->options & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE);
2961 }
2962 
2963 /**
2964  * gda_connection_statement_to_sql:
2965  * @cnc: a #GdaConnection object
2966  * @stmt: a #GdaStatement object
2967  * @params: (allow-none): a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or %NULL
2968  * @flags: SQL rendering flags, as #GdaStatementSqlFlag OR'ed values
2969  * @params_used: (allow-none) (element-type Gda.Holder) (out) (transfer container): a place to store the list of individual #GdaHolder objects within @params which have been used
2970  * @error: a place to store errors, or %NULL
2971  *
2972  * Renders @stmt as an SQL statement, adapted to the SQL dialect used by @cnc
2973  *
2974  * Returns: (transfer full): a new string, or %NULL if an error occurred
2975  */
2976 gchar *
gda_connection_statement_to_sql(GdaConnection * cnc,GdaStatement * stmt,GdaSet * params,GdaStatementSqlFlag flags,GSList ** params_used,GError ** error)2977 gda_connection_statement_to_sql (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params, GdaStatementSqlFlag flags,
2978 				 GSList **params_used, GError **error)
2979 {
2980 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
2981 	g_return_val_if_fail (cnc->priv->provider_obj, NULL);
2982 	g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
2983 
2984 	if (PROV_CLASS (cnc->priv->provider_obj)->statement_to_sql)
2985 		return (PROV_CLASS (cnc->priv->provider_obj)->statement_to_sql) (cnc->priv->provider_obj,
2986 										 cnc, stmt, params, flags,
2987 										 params_used, error);
2988 	else
2989 		return gda_statement_to_sql_extended (stmt, cnc, params, flags, params_used, error);
2990 }
2991 
2992 /**
2993  * gda_connection_statement_prepare:
2994  * @cnc: a #GdaConnection
2995  * @stmt: a #GdaStatement object
2996  * @error: a place to store errors, or %NULL
2997  *
2998  * Ask the database accessed through the @cnc connection to prepare the usage of @stmt. This is only useful
2999  * if @stmt will be used more than once (however some database providers may always prepare statements
3000  * before executing them).
3001  *
3002  * This function is also useful to make sure @stmt is fully understood by the database before actually executing it.
3003  *
3004  * Note however that it is also possible that gda_connection_statement_prepare() fails when
3005  * gda_connection_statement_execute() does not fail (this will usually be the case with statements such as
3006  * <![CDATA["SELECT * FROM ##tablename::string"]]> because database usually don't allow variables to be used in place of a
3007  * table name).
3008  *
3009  * Returns: TRUE if no error occurred.
3010  */
3011 gboolean
gda_connection_statement_prepare(GdaConnection * cnc,GdaStatement * stmt,GError ** error)3012 gda_connection_statement_prepare (GdaConnection *cnc, GdaStatement *stmt, GError **error)
3013 {
3014 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
3015 	g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
3016 	g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE);
3017 
3018 	if (PROV_CLASS (cnc->priv->provider_obj)->statement_prepare)
3019 		return (PROV_CLASS (cnc->priv->provider_obj)->statement_prepare)(cnc->priv->provider_obj,
3020 										 cnc, stmt, error);
3021 	else {
3022 		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
3023 			      "%s", _("Provider does not support statement preparation"));
3024 		return FALSE;
3025 	}
3026 }
3027 
3028 /*
3029  * @args is consumed as a succession of (column number, GType) arguments
3030  * which ends with a column number of -1. The returned array is always terminated by G_TYPE_NONE,
3031  * and contains 0 where no column type information has been provided
3032  */
3033 static GType *
make_col_types_array(va_list args)3034 make_col_types_array (va_list args)
3035 {
3036 	GType *types;
3037 	gint max = 10;
3038 	gint col, lastidx = 0;
3039 
3040 	col = va_arg (args, gint);
3041 	if (col < 0)
3042 		return NULL;
3043 
3044 	types = g_new0 (GType, max + 1);
3045 	types [max] = G_TYPE_NONE;
3046 	for (; col >= 0; col = va_arg (args, gint)) {
3047 		if (col >= max) {
3048 			gint i;
3049 			types = g_renew (GType, types, col + 5 + 1);
3050 			for (i = max; i <= col + 5; i ++)
3051 				types[i] = 0;
3052 			max = col + 5;
3053 			types [max] = G_TYPE_NONE;
3054 		}
3055 		types [col] = va_arg (args, GType);
3056 		lastidx = col+1;
3057 	}
3058 
3059 	if (lastidx == 0) {
3060 		g_free (types);
3061 		types = NULL;
3062 	}
3063 	else
3064 		types [lastidx] = G_TYPE_NONE;
3065 
3066 	return types;
3067 }
3068 
3069 static void
add_exec_time_to_object(GObject * obj,GTimer * timer)3070 add_exec_time_to_object (GObject *obj, GTimer *timer)
3071 {
3072 	gdouble etime;
3073 	etime = g_timer_elapsed (timer, NULL);
3074 	if (GDA_IS_DATA_SELECT (obj))
3075 		g_object_set (obj, "execution-delay", etime, NULL);
3076 	else if (GDA_IS_SET (obj)) {
3077 		GdaHolder *holder;
3078 		holder = gda_holder_new_inline (G_TYPE_DOUBLE, "EXEC_DELAY", etime);
3079 		gda_set_add_holder ((GdaSet*) obj, holder);
3080 		g_object_unref ((GObject*) holder);
3081 	}
3082 	else
3083 		TO_IMPLEMENT;
3084 }
3085 
3086 /*
3087  * No locking is done here must be done before calling
3088  *
3089  * Returns: -1 if task not found
3090  */
3091 static gint
get_task_index(GdaConnection * cnc,guint task_id,gboolean * out_completed,gboolean id_is_prov)3092 get_task_index (GdaConnection *cnc, guint task_id, gboolean *out_completed, gboolean id_is_prov)
3093 {
3094 	gint i, len;
3095 	CncTask *task;
3096 	len = cnc->priv->completed_tasks->len;
3097 	for (i = 0; i < len; i++) {
3098 		task = CNC_TASK (g_array_index (cnc->priv->completed_tasks, gpointer, i));
3099 		if ((! id_is_prov && (task->task_id == task_id)) ||
3100 		    (id_is_prov && (task->prov_task_id == task_id))) {
3101 			*out_completed = TRUE;
3102 			return i;
3103 		}
3104 	}
3105 
3106 	len = cnc->priv->waiting_tasks->len;
3107 	for (i = 0; i < len; i++) {
3108 		task = CNC_TASK (g_array_index (cnc->priv->waiting_tasks, gpointer, i));
3109 		if ((! id_is_prov && (task->task_id == task_id)) ||
3110 		    (id_is_prov && (task->prov_task_id == task_id))) {
3111 			*out_completed = FALSE;
3112 			return i;
3113 		}
3114 	}
3115 
3116 	return -1;
3117 }
3118 
3119 /*
3120  * This callback is called from the GdaServerProvider object, from the handle_async() method
3121  */
3122 static void
async_stmt_exec_cb(G_GNUC_UNUSED GdaServerProvider * provider,GdaConnection * cnc,guint task_id,GObject * result_obj,const GError * error,G_GNUC_UNUSED CncTask * task)3123 async_stmt_exec_cb (G_GNUC_UNUSED GdaServerProvider *provider, GdaConnection *cnc, guint task_id,
3124 		    GObject *result_obj, const GError *error, G_GNUC_UNUSED CncTask *task)
3125 {
3126 	gint i;
3127 	gboolean is_completed;
3128 
3129 	g_object_ref ((GObject*) cnc);
3130 	gda_connection_lock (GDA_LOCKABLE (cnc));
3131 
3132 	i = get_task_index (cnc, task_id, &is_completed, TRUE);
3133 	if (i >= 0) {
3134 		CncTask *task;
3135 		g_assert (!is_completed);
3136 
3137 		/* complete @task and free some memory */
3138 		task = CNC_TASK (g_array_index (cnc->priv->waiting_tasks, gpointer, i));
3139 		cnc_task_lock (task);
3140 
3141 		task->being_processed = FALSE;
3142 		if (task->exec_timer)
3143 			g_timer_stop (task->exec_timer);
3144 
3145 		if (error)
3146 			task->error = g_error_copy (error);
3147 		if (result_obj) {
3148 			task->result = g_object_ref (result_obj);
3149 			if (task->exec_timer)
3150 				add_exec_time_to_object (task->result, task->exec_timer);
3151 		}
3152 		if (task->stmt) {
3153 			g_signal_handlers_disconnect_by_func (task->stmt,
3154 							      G_CALLBACK (task_stmt_reset_cb), task);
3155 			g_object_unref (task->stmt);
3156 			task->stmt = NULL;
3157 		}
3158 		if (task->params) {
3159 			g_object_unref (task->params);
3160 			task->params = NULL;
3161 		}
3162 		if (task->col_types) {
3163 			g_free (task->col_types);
3164 			task->col_types = NULL;
3165 		}
3166 
3167 		g_array_remove_index (cnc->priv->waiting_tasks, i);
3168 		g_array_append_val (cnc->priv->completed_tasks, task);
3169 
3170 		cnc_task_unlock (task);
3171 
3172 		/* execute next waiting task if there is one */
3173 		while (cnc->priv->waiting_tasks->len >= 1) {
3174 			/* execute statement now as there are no other ones to be executed */
3175 			GError *lerror = NULL;
3176 			task = CNC_TASK (g_array_index (cnc->priv->waiting_tasks, gpointer, 0));
3177 			cnc_task_lock (task);
3178 			task->being_processed = TRUE;
3179 			dump_exec_params (cnc, task->stmt, task->params);
3180 			if (cnc->priv->exec_times)
3181 				g_timer_start (task->exec_timer);
3182 			if (cnc->priv->exec_slowdown && !cnc->priv->is_thread_wrapper)
3183 				g_usleep (cnc->priv->exec_slowdown);
3184 
3185 			PROV_CLASS (cnc->priv->provider_obj)->statement_execute (cnc->priv->provider_obj, cnc,
3186 										 task->stmt,
3187 										 task->params,
3188 										 task->model_usage,
3189 										 task->col_types,
3190 										 &(task->last_insert_row),
3191 										 &(task->prov_task_id),
3192 										 (GdaServerProviderExecCallback) async_stmt_exec_cb,
3193 										 task, &lerror);
3194 			if (lerror) {
3195 				/* task execution failed => move it to completed tasks array */
3196 				task->error = lerror;
3197 				task->being_processed = FALSE;
3198 				if (cnc->priv->exec_times)
3199 					g_timer_stop (task->exec_timer);
3200 				g_array_remove_index (cnc->priv->waiting_tasks, 0);
3201 				g_array_append_val (cnc->priv->completed_tasks, task);
3202 				cnc_task_unlock (task);
3203 			}
3204 			else {
3205 				update_meta_store_after_statement_exec (cnc, task->stmt, task->params);
3206 				cnc_task_unlock (task);
3207 				break;
3208 			}
3209 		}
3210 	}
3211 	else
3212 		g_warning ("Provider called back for the execution of task %u (provider numbering) which does not exist, "
3213 			   "ignored.\n", task_id);
3214 
3215 	gda_connection_unlock (GDA_LOCKABLE (cnc));
3216 	g_object_unref ((GObject*) cnc);
3217 }
3218 
3219 /**
3220  * gda_connection_async_statement_execute:
3221  * @cnc: a #GdaConnection
3222  * @stmt: a #GdaStatement object
3223  * @params: (allow-none): a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or %NULL
3224  * @model_usage: in the case where @stmt is a SELECT statement, specifies how the returned data model will be used
3225  * @col_types: (array) (allow-none): an array of GType to request each returned #GdaDataModel's column's GType, terminated with the G_TYPE_NONE
3226  * @need_last_insert_row: TRUE if the values of the last interted row must be computed
3227  * @error: a place to store errors, or %NULL
3228  *
3229  * This method is similar to gda_connection_statement_execute() but is asynchronous as it method returns
3230  * immediately with a task ID. It's up to the caller to use gda_connection_async_fetch_result() regularly to check
3231  * if the statement's execution is finished.
3232  *
3233  * It is possible to call the method several times to request several statements to be executed asynchronously, the
3234  * statements will be executed in the order in which they were requested.
3235  *
3236  * The parameters, if present, are copied and can be discarded or modified before the statement is actually executed.
3237  * The @stmt object is not copied but simply referenced (for performance reasons), and if it is modified before
3238  * it is actually executed, then its execution will not occur. It is however safe to call g_object_unref() on it if
3239  * it's not needed anymore.
3240  *
3241  * The execution failure of any statement has no impact on the execution of other statements except for example if
3242  * the connection has a transaction started and the failure invalidates the transaction (as decided by the database
3243  * server).
3244  *
3245  * Note that for asynchronous calls to succeed, it is gererally necessary to specify the
3246  * %GDA_CONNECTION_OPTIONS_THREAD_ISOLATED flag when opening the connection to be sure it is opened in a separate thread
3247  * in which asynchronous calls are made (failing to use this flag make the asynchronous call dependant on the database
3248  * provider implementation and at the moment none support this feature).
3249  *
3250  * Returns: a task ID, or 0 if an error occurred (not an error regarding @stmt itself as its execution has not yet started
3251  * but any other error)
3252  *
3253  * Since: 4.2
3254  */
3255 guint
gda_connection_async_statement_execute(GdaConnection * cnc,GdaStatement * stmt,GdaSet * params,GdaStatementModelUsage model_usage,GType * col_types,gboolean need_last_insert_row,GError ** error)3256 gda_connection_async_statement_execute (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params,
3257 					GdaStatementModelUsage model_usage, GType *col_types,
3258 					gboolean need_last_insert_row,
3259 					GError **error)
3260 {
3261 	guint id;
3262 	CncTask *task;
3263 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), 0);
3264 	g_return_val_if_fail (cnc->priv->provider_obj, 0);
3265 	g_return_val_if_fail (GDA_IS_STATEMENT (stmt), 0);
3266 	g_return_val_if_fail (PROV_CLASS (cnc->priv->provider_obj)->statement_execute, 0);
3267 
3268 
3269 	g_object_ref ((GObject*) cnc);
3270 	if (! gda_connection_trylock ((GdaLockable*) cnc)) {
3271 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CANT_LOCK_ERROR,
3272 			     _("Can't obtain connection lock"));
3273 		g_object_unref ((GObject*) cnc);
3274 		return 0;
3275 	}
3276 
3277 	if (!cnc->priv->provider_data) {
3278 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR,
3279 			     _("Connection is closed"));
3280 		gda_connection_unlock (GDA_LOCKABLE (cnc));
3281 		g_object_unref ((GObject*) cnc);
3282 		return 0;
3283 	}
3284 
3285 	if (!PROV_CLASS (cnc->priv->provider_obj)->handle_async) {
3286 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_UNSUPPORTED_ASYNC_EXEC_ERROR,
3287 			     _("Asynchronous execution is not supported"));
3288 		gda_connection_unlock (GDA_LOCKABLE (cnc));
3289 		g_object_unref ((GObject*) cnc);
3290 		return 0;
3291 	}
3292 
3293 	id = cnc->priv->next_task_id ++;
3294 	task = cnc_task_new (id, stmt, model_usage, col_types, params, need_last_insert_row);
3295 	g_array_append_val (cnc->priv->waiting_tasks, task);
3296 	if (cnc->priv->exec_times) {
3297 		task->exec_timer = g_timer_new ();
3298 		g_timer_stop (task->exec_timer);
3299 	}
3300 
3301 	if (cnc->priv->waiting_tasks->len == 1) {
3302 		/* execute statement now as there are no other ones to be executed */
3303 		GError *lerror = NULL;
3304 
3305 		cnc_task_lock (task);
3306 		task->being_processed = TRUE;
3307 		dump_exec_params (cnc, task->stmt, task->params);
3308 		if (cnc->priv->exec_times)
3309 			g_timer_start (task->exec_timer);
3310 		if (cnc->priv->exec_slowdown && !cnc->priv->is_thread_wrapper)
3311 			g_usleep (cnc->priv->exec_slowdown);
3312 
3313 		PROV_CLASS (cnc->priv->provider_obj)->statement_execute (cnc->priv->provider_obj, cnc,
3314 									 task->stmt,
3315 									 task->params,
3316 									 task->model_usage,
3317 									 task->col_types,
3318 									 &(task->last_insert_row),
3319 									 &(task->prov_task_id),
3320 									 (GdaServerProviderExecCallback) async_stmt_exec_cb,
3321 									 task, &lerror);
3322 		if (lerror) {
3323 			/* task execution failed => move it to completed tasks array */
3324 			gint i;
3325 			gboolean is_completed;
3326 
3327 			task->error = lerror;
3328 			task->being_processed = FALSE;
3329 			if (cnc->priv->exec_times)
3330 				g_timer_stop (task->exec_timer);
3331 			i = get_task_index (cnc, id, &is_completed, FALSE);
3332 			g_assert ((i >= 0) && !is_completed);
3333 			g_array_remove_index (cnc->priv->waiting_tasks, i);
3334 			g_array_append_val (cnc->priv->completed_tasks, task);
3335 		}
3336 		else
3337 			update_meta_store_after_statement_exec (cnc, task->stmt, task->params);
3338 		cnc_task_unlock (task);
3339 	}
3340 
3341 	gda_connection_unlock ((GdaLockable*) cnc);
3342 	g_object_unref ((GObject*) cnc);
3343 
3344 	return id;
3345 }
3346 
3347 /**
3348  * gda_connection_async_fetch_result:
3349  * @cnc: a #GdaConnection
3350  * @task_id: a task ID returned by gda_connection_async_statement_execute()
3351  * @last_insert_row: (out) (transfer full) (allow-none): a place to store a new #GdaSet object which contains the values of the last inserted row, or %NULL
3352  * @error: a place to store errors, or %NULL
3353  *
3354  * Use this method to obtain the result of the execution of a statement which has been executed asynchronously by
3355  * calling gda_connection_async_statement_execute(). This function is non locking and will return %NULL (and no
3356  * error will be set) if the statement has not been executed yet.
3357  *
3358  * If the statement has been executed, this method returns the same value as gda_connection_statement_execute()
3359  * would have if the statement had been
3360  * executed synchronously.
3361  *
3362  * Returns: (transfer full): a #GObject, or %NULL if an error occurred
3363  *
3364  * Since: 4.2
3365  */
3366 GObject *
gda_connection_async_fetch_result(GdaConnection * cnc,guint task_id,GdaSet ** last_insert_row,GError ** error)3367 gda_connection_async_fetch_result (GdaConnection *cnc, guint task_id, GdaSet **last_insert_row, GError **error)
3368 {
3369 	gint i;
3370 	gboolean is_completed;
3371 	GObject *obj = NULL;
3372 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
3373 	g_return_val_if_fail (cnc->priv->provider_obj, NULL);
3374 
3375 	if (! gda_connection_trylock ((GdaLockable*) cnc)) {
3376 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CANT_LOCK_ERROR,
3377 			     _("Can't obtain connection lock"));
3378 		return NULL;
3379 	}
3380 
3381 	/* if provider needs to be awaken, then do it now */
3382 	if (PROV_CLASS (cnc->priv->provider_obj)->handle_async) {
3383 		if (! (PROV_CLASS (cnc->priv->provider_obj)->handle_async (cnc->priv->provider_obj, cnc, error))) {
3384 			gda_connection_unlock ((GdaLockable*) cnc);
3385 			return NULL;
3386 		}
3387 	}
3388 
3389 	i = get_task_index (cnc, task_id, &is_completed, FALSE);
3390 	if (i < 0) {
3391 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_TASK_NOT_FOUND_ERROR,
3392 		     _("Can't find task %u"), task_id);
3393 	}
3394 	else if (is_completed) {
3395 		/* task completed */
3396 		CncTask *task;
3397 		task = CNC_TASK (g_array_index (cnc->priv->completed_tasks, gpointer, i));
3398 		g_array_remove_index (cnc->priv->completed_tasks, i);
3399 
3400 		cnc_task_lock (task);
3401 		if (task->result)
3402 			obj = g_object_ref (task->result);
3403 		if (task->error) {
3404 			g_propagate_error (error, task->error);
3405 			task->error = NULL;
3406 		}
3407 		if (last_insert_row) {
3408 			if (task->last_insert_row)
3409 				*last_insert_row = g_object_ref (task->last_insert_row);
3410 			else
3411 				*last_insert_row = NULL;
3412 		}
3413 		cnc_task_unlock (task);
3414 		cnc_task_free (task);
3415 	}
3416 	else {
3417 		/* task not yet completed */
3418 		/* nothing to do */
3419 	}
3420 
3421 	gda_connection_unlock ((GdaLockable*) cnc);
3422 	return obj;
3423 }
3424 
3425 /**
3426  * gda_connection_async_cancel:
3427  * @cnc: a #GdaConnection
3428  * @task_id: a task ID returned by gda_connection_async_statement_execute()
3429  * @error: a place to store errors, or %NULL
3430  *
3431  * Requests that a task be cancelled. This operation may of may not have any effect
3432  * depending on the task's status, even if it returns %TRUE. If it returns %FALSE,
3433  * then the task has not been cancelled.
3434  *
3435  * Returns: TRUE if no error occurred
3436  *
3437  * Since: 4.2
3438  */
3439 gboolean
gda_connection_async_cancel(GdaConnection * cnc,guint task_id,GError ** error)3440 gda_connection_async_cancel (GdaConnection *cnc, guint task_id, GError **error)
3441 {
3442 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
3443 	g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
3444 
3445 	if (! gda_connection_trylock ((GdaLockable*) cnc)) {
3446 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CANT_LOCK_ERROR,
3447 			     _("Can't obtain connection lock"));
3448 		return FALSE;
3449 	}
3450 
3451 	gint i;
3452 	gboolean is_completed;
3453 	gboolean retval = TRUE;
3454 	i = get_task_index (cnc, task_id, &is_completed, FALSE);
3455 	if ((i >= 0) && (!is_completed)) {
3456 		CncTask *task;
3457 		task = CNC_TASK (g_array_index (cnc->priv->waiting_tasks, gpointer, i));
3458 		if (task->being_processed) {
3459 			if (PROV_CLASS (cnc->priv->provider_obj)->cancel) {
3460 				retval = PROV_CLASS (cnc->priv->provider_obj)->cancel (cnc->priv->provider_obj, cnc,
3461 										       task->prov_task_id, error);
3462 				if (retval) {
3463 					/* cancellation may have succeeded => remove this task from the tasks to execute */
3464 					g_array_remove_index (cnc->priv->waiting_tasks, i);
3465 					cnc_task_free (task);
3466 				}
3467 			}
3468 			else {
3469 				g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
3470 					     "%s", _("Provider does not support asynchronous server operation"));
3471 				retval = FALSE;
3472 			}
3473 			task->being_processed = FALSE;
3474 			if (cnc->priv->exec_times)
3475 				g_timer_stop (task->exec_timer);
3476 		}
3477 		else {
3478 			/* simply remove this task from the tasks to execute */
3479 			g_array_remove_index (cnc->priv->waiting_tasks, i);
3480 			cnc_task_free (task);
3481 		}
3482 	}
3483 	else if (i < 0) {
3484 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_TASK_NOT_FOUND_ERROR,
3485 			     _("Can't find task %u"), task_id);
3486 		retval = FALSE;
3487 	}
3488 
3489 	gda_connection_unlock ((GdaLockable*) cnc);
3490 	return retval;
3491 }
3492 
3493 /*
3494  * Wrapper which adds @...
3495  */
3496 static GObject *
gda_connection_statement_execute_v(GdaConnection * cnc,GdaStatement * stmt,GdaSet * params,GdaStatementModelUsage model_usage,GdaSet ** last_inserted_row,GError ** error,...)3497 gda_connection_statement_execute_v (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params,
3498 				    GdaStatementModelUsage model_usage, GdaSet **last_inserted_row, GError **error, ...)
3499 {
3500 	va_list ap;
3501 	GObject *obj;
3502 	GType *types, *req_types;
3503 	GTimer *timer = NULL;
3504 	va_start (ap, error);
3505 	types = make_col_types_array (ap);
3506 	va_end (ap);
3507 
3508 	g_object_ref ((GObject*) cnc);
3509 	gda_connection_lock ((GdaLockable*) cnc);
3510 
3511 	_clear_connection_events (cnc);
3512 
3513 	if (last_inserted_row)
3514 		*last_inserted_row = NULL;
3515 
3516 	if (!cnc->priv->provider_data) {
3517 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR,
3518 			     _("Connection is closed"));
3519 		gda_connection_unlock (GDA_LOCKABLE (cnc));
3520 		g_object_unref ((GObject*) cnc);
3521 		g_free (types);
3522 		return NULL;
3523 	}
3524 
3525 	req_types = merge_column_types (_gda_statement_get_requested_types (stmt), types);
3526 	if (req_types) {
3527 		g_free (types);
3528 		types = req_types;
3529 		req_types = NULL;
3530 	}
3531 	else if (_gda_statement_get_requested_types (stmt))
3532 		req_types = (GType*) _gda_statement_get_requested_types (stmt);
3533 
3534 	if (! (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS) &&
3535 	    ! (model_usage & GDA_STATEMENT_MODEL_CURSOR_FORWARD))
3536 		model_usage |= GDA_STATEMENT_MODEL_RANDOM_ACCESS;
3537 
3538 	dump_exec_params (cnc, stmt, params);
3539 	if (cnc->priv->exec_times)
3540 		timer = g_timer_new ();
3541 	if (cnc->priv->exec_slowdown && !cnc->priv->is_thread_wrapper)
3542 		g_usleep (cnc->priv->exec_slowdown);
3543 
3544 	obj = PROV_CLASS (cnc->priv->provider_obj)->statement_execute (cnc->priv->provider_obj, cnc, stmt, params,
3545 								       model_usage,
3546 								       req_types ? req_types : types,
3547 								       last_inserted_row,
3548 								       NULL, NULL, NULL, error);
3549 	if (timer)
3550 		g_timer_stop (timer);
3551 	g_free (types);
3552 
3553 	if (obj) {
3554 		if (timer)
3555 			add_exec_time_to_object (obj, timer);
3556 		update_meta_store_after_statement_exec (cnc, stmt, params);
3557 		if (GDA_IS_DATA_SELECT (obj) && (model_usage & GDA_STATEMENT_MODEL_OFFLINE) &&
3558 		    ! gda_data_select_prepare_for_offline ((GdaDataSelect*) obj, error)) {
3559 			g_object_unref (obj);
3560 			obj = NULL;
3561 		}
3562 	}
3563 	gda_connection_unlock ((GdaLockable*) cnc);
3564 	g_object_unref ((GObject*) cnc);
3565 	if (timer)
3566 		g_timer_destroy (timer);
3567 
3568 	return obj;
3569 }
3570 
3571 
3572 /**
3573  * gda_connection_execute_select_command:
3574  * @cnc: an opened connection
3575  * @sql: a query statement that must begin with "SELECT"
3576  * @error: a place to store errors, or %NULL
3577  *
3578  * Execute a SQL SELECT command over an opened connection.
3579  *
3580  * Returns: (transfer full): a new #GdaDataModel if successful, %NULL otherwise
3581  *
3582  * Since: 4.2.3
3583  */
3584 GdaDataModel *
gda_connection_execute_select_command(GdaConnection * cnc,const gchar * sql,GError ** error)3585 gda_connection_execute_select_command (GdaConnection *cnc, const gchar *sql, GError **error)
3586 {
3587 	GdaStatement *stmt;
3588 	GdaDataModel *model;
3589 
3590 	g_return_val_if_fail (sql != NULL
3591 			      || GDA_IS_CONNECTION (cnc)
3592 			      || !gda_connection_is_opened (cnc)
3593 			      || g_str_has_prefix (sql, "SELECT"),
3594 			      NULL);
3595 
3596 	g_mutex_lock (&parser_mutex);
3597 	if (!internal_parser)
3598 		internal_parser = gda_sql_parser_new ();
3599 	g_mutex_unlock (&parser_mutex);
3600 
3601 	stmt = gda_sql_parser_parse_string (internal_parser, sql, NULL, error);
3602 	if (!stmt)
3603 		return NULL;
3604 	model = gda_connection_statement_execute_select (cnc, stmt, NULL, error);
3605 	g_object_unref (stmt);
3606 
3607 	return model;
3608 }
3609 
3610 /**
3611  * gda_connection_execute_non_select_command:
3612  * @cnc: an opened connection
3613  * @sql: a query statement that must not begin with "SELECT"
3614  * @error: a place to store errors, or %NULL
3615  *
3616  * This is a convenience function to execute a SQL command over the opened connection. For the
3617  * returned value, see gda_connection_statement_execute_non_select()'s documentation.
3618  *
3619  * Returns: the number of rows affected or -1, or -2
3620  *
3621  * Since: 4.2.3
3622  */
3623 gint
gda_connection_execute_non_select_command(GdaConnection * cnc,const gchar * sql,GError ** error)3624 gda_connection_execute_non_select_command (GdaConnection *cnc, const gchar *sql, GError **error)
3625 {
3626 	GdaStatement *stmt;
3627 	gint retval;
3628 
3629 	g_return_val_if_fail (sql != NULL
3630 			      || GDA_IS_CONNECTION (cnc)
3631 			      || !gda_connection_is_opened (cnc), -1);
3632 
3633 	g_mutex_lock (&parser_mutex);
3634 	if (!internal_parser)
3635 		internal_parser = gda_sql_parser_new ();
3636 	g_mutex_unlock (&parser_mutex);
3637 
3638 	stmt = gda_sql_parser_parse_string (internal_parser, sql, NULL, error);
3639 	if (!stmt)
3640 		return -1;
3641 
3642 	retval = gda_connection_statement_execute_non_select (cnc, stmt, NULL, NULL, error);
3643 	g_object_unref (stmt);
3644 	return retval;
3645 }
3646 
3647 /**
3648  * gda_connection_statement_execute:
3649  * @cnc: a #GdaConnection
3650  * @stmt: a #GdaStatement object
3651  * @params: (allow-none): a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or %NULL
3652  * @model_usage: in the case where @stmt is a SELECT statement, specifies how the returned data model will be used
3653  * @last_insert_row: (out) (transfer full) (allow-none): a place to store a new #GdaSet object which contains the values of the last inserted row, or %NULL
3654  * @error: a place to store errors, or %NULL
3655  *
3656  * Executes @stmt.
3657  *
3658  * As @stmt can, by design (and if not abused), contain only one SQL statement, the
3659  * return object will either be:
3660  * <itemizedlist>
3661  *   <listitem><para>a #GdaDataSelect object (which is also a #GdaDataModel) if @stmt is a SELECT statement
3662  *             (usually a GDA_SQL_STATEMENT_SELECT, see #GdaSqlStatementType)
3663  *             containing the results of the SELECT. The resulting data model is by default read only, but
3664  *             modifications can be enabled, see the #GdaDataSelect's documentation for more information.</para></listitem>
3665  *   <listitem><para>a #GdaSet for any other SQL statement which correctly executed. In this case
3666  *        (if the provider supports it), then the #GdaSet may contain value holders named:
3667  *        <itemizedlist>
3668  *          <listitem><para>a (gint) #GdaHolder named "IMPACTED_ROWS"</para></listitem>
3669  *          <listitem><para>a (GObject) #GdaHolder named "EVENT" which contains a #GdaConnectionEvent</para></listitem>
3670  *        </itemizedlist></para></listitem>
3671  * </itemizedlist>
3672  *
3673  * If @last_insert_row is not %NULL and @stmt is an INSERT statement, then it will contain (if the
3674  * provider used by @cnc supports it) a new #GdaSet object composed of value holders named "+&lt;column number&gt;"
3675  * starting at column 0 which contain the actual inserted values. For example if a table is composed of an 'id' column
3676  * which is auto incremented and a 'name' column then the execution of a "INSERT INTO mytable (name) VALUES ('joe')"
3677  * query will return a #GdaSet with two holders:
3678  * <itemizedlist>
3679  *   <listitem><para>one with the '+0' ID which may for example contain 1 (note that its "name" property should be "id")</para></listitem>
3680  *   <listitem><para>one with the '+1' ID which will contain 'joe' (note that its "name" property should be "name")</para></listitem>
3681  * </itemizedlist>
3682  *
3683  * This method may fail with a %GDA_SERVER_PROVIDER_ERROR domain error (see the #GdaServerProviderError error codes).
3684  *
3685  * Note1: If @stmt is a SELECT statement which has some parameters and  if @params is %NULL, then the statement can't
3686  * be executed and this method will return %NULL.
3687  *
3688  * Note2: If @stmt is a SELECT statement which has some parameters and  if @params is not %NULL but contains some
3689  * invalid parameters, then the statement can't be executed and this method will return %NULL, unless the
3690  * @model_usage has the GDA_STATEMENT_MODEL_ALLOW_NOPARAM flag.
3691  *
3692  * Note3: If @stmt is a SELECT statement which has some parameters and  if @params is not %NULL but contains some
3693  * invalid parameters and if @model_usage has the GDA_STATEMENT_MODEL_ALLOW_NOPARAM flag, then the returned
3694  * data model will contain no row but will have all the correct columns (even though some of the columns might
3695  * report as GDA_TYPE_NULL). In this case, if (after this method call) any of @params' parameters change
3696  * then the resulting data model will re-run itself, see the GdaDataSelect's
3697  * <link linkend="GdaDataSelect--auto-reset">auto-reset</link> property for more information.
3698  *
3699  * Note4: if @model_usage does not contain the GDA_STATEMENT_MODEL_RANDOM_ACCESS or
3700  * GDA_STATEMENT_MODEL_CURSOR_FORWARD flags, then the default will be to return a random access data model
3701  *
3702  * Note5: If @stmt is a SELECT statement which returns blob values (of type %GDA_TYPE_BLOB), then an implicit
3703  * transaction will have been started by the database provider, and it's up to the caller to close the transaction
3704  * (which will then be locked) once all the blob ressources have been
3705  * liberated (when the returned data model is destroyed). See the section about
3706  * <link linkend="gen:blobs">Binary large objects (BLOBs)</link> for more information.
3707  *
3708  * Also see the <link linkend="limitations">provider's limitations</link>, and the
3709  * <link linkend="data-select">Advanced GdaDataSelect usage</link> sections.
3710  *
3711  * Returns: (transfer full): a #GObject, or %NULL if an error occurred
3712  */
3713 GObject *
gda_connection_statement_execute(GdaConnection * cnc,GdaStatement * stmt,GdaSet * params,GdaStatementModelUsage model_usage,GdaSet ** last_inserted_row,GError ** error)3714 gda_connection_statement_execute (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params,
3715 				  GdaStatementModelUsage model_usage, GdaSet **last_inserted_row, GError **error)
3716 {
3717 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
3718 	g_return_val_if_fail (cnc->priv->provider_obj, NULL);
3719 	g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
3720 	g_return_val_if_fail (PROV_CLASS (cnc->priv->provider_obj)->statement_execute, NULL);
3721 
3722 	if (last_inserted_row)
3723 		*last_inserted_row = NULL;
3724 
3725 	return gda_connection_statement_execute_v (cnc, stmt, params, model_usage, last_inserted_row, error, -1);
3726 }
3727 
3728 /**
3729  * gda_connection_statement_execute_non_select:
3730  * @cnc: a #GdaConnection object.
3731  * @stmt: a #GdaStatement object.
3732  * @params: (allow-none): a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or %NULL
3733  * @last_insert_row: (out) (transfer full) (allow-none): a place to store a new #GdaSet object which contains the values of the last inserted row, or %NULL
3734  * @error: a place to store an error, or %NULL
3735  *
3736  * Executes a non-selection statement on the given connection.
3737  *
3738  * This function returns the number of rows affected by the execution of @stmt, or -1
3739  * if an error occurred, or -2 if the connection's provider does not return the number of rows affected.
3740  *
3741  * This function is just a convenience function around the gda_connection_statement_execute()
3742  * function.
3743  * See the documentation of the gda_connection_statement_execute() for information
3744  * about the @params list of parameters.
3745  *
3746  * See gda_connection_statement_execute() form more information about @last_insert_row.
3747  *
3748  * Returns: the number of rows affected (&gt;=0) or -1 or -2
3749  */
3750 gint
gda_connection_statement_execute_non_select(GdaConnection * cnc,GdaStatement * stmt,GdaSet * params,GdaSet ** last_insert_row,GError ** error)3751 gda_connection_statement_execute_non_select (GdaConnection *cnc, GdaStatement *stmt,
3752 					     GdaSet *params, GdaSet **last_insert_row, GError **error)
3753 {
3754 	GdaSet *set;
3755 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), -1);
3756 	g_return_val_if_fail (cnc->priv->provider_obj, -1);
3757 	g_return_val_if_fail (GDA_IS_STATEMENT (stmt), -1);
3758 	g_return_val_if_fail (PROV_CLASS (cnc->priv->provider_obj)->statement_execute, -1);
3759 
3760 	if ((gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT) ||
3761 	    (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_COMPOUND)) {
3762 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_STATEMENT_TYPE_ERROR,
3763 			      "%s", _("Statement is a selection statement"));
3764 		return -1;
3765 	}
3766 
3767 	if (last_insert_row)
3768 		*last_insert_row = NULL;
3769 
3770 	set = (GdaSet *) gda_connection_statement_execute_v (cnc, stmt, params,
3771 							     GDA_STATEMENT_MODEL_RANDOM_ACCESS, last_insert_row,
3772 							     error, -1);
3773 	if (!set)
3774 		return -1;
3775 
3776 	if (!GDA_IS_SET (set)) {
3777 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_STATEMENT_TYPE_ERROR,
3778 			      "%s", _("Statement is a selection statement"));
3779 		g_object_unref (set);
3780 		return -1;
3781 	}
3782 	else {
3783 		GdaHolder *h;
3784 		gint retval = -2;
3785 
3786 		h = gda_set_get_holder (set, "IMPACTED_ROWS");
3787 		if (h) {
3788 			const GValue *value;
3789 			value = gda_holder_get_value (h);
3790 			if (value && (G_VALUE_TYPE (value) == G_TYPE_INT))
3791 				retval = g_value_get_int (value);
3792 		}
3793 		g_object_unref (set);
3794 		return retval;
3795 	}
3796 }
3797 
3798 /**
3799  * gda_connection_statement_execute_select:
3800  * @cnc: a #GdaConnection object.
3801  * @stmt: a #GdaStatement object.
3802  * @params: (allow-none): a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or %NULL
3803  * @error: a place to store an error, or %NULL
3804  *
3805  * Executes a selection command on the given connection.
3806  *
3807  * This function returns a #GdaDataModel resulting from the SELECT statement, or %NULL
3808  * if an error occurred.
3809  *
3810  * This function is just a convenience function around the gda_connection_statement_execute()
3811  * function.
3812  *
3813  * See the documentation of the gda_connection_statement_execute() for information
3814  * about the @params list of parameters.
3815  *
3816  * Returns: (transfer full): a #GdaDataModel containing the data returned by the
3817  * data source, or %NULL if an error occurred
3818  */
3819 GdaDataModel *
gda_connection_statement_execute_select(GdaConnection * cnc,GdaStatement * stmt,GdaSet * params,GError ** error)3820 gda_connection_statement_execute_select (GdaConnection *cnc, GdaStatement *stmt,
3821 					 GdaSet *params, GError **error)
3822 {
3823 	GdaDataModel *model;
3824 
3825 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
3826 	g_return_val_if_fail (cnc->priv->provider_obj, NULL);
3827 	g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
3828 	g_return_val_if_fail (PROV_CLASS (cnc->priv->provider_obj)->statement_execute, NULL);
3829 
3830 	model = (GdaDataModel *) gda_connection_statement_execute_v (cnc, stmt, params,
3831 								     GDA_STATEMENT_MODEL_RANDOM_ACCESS, NULL,
3832 								     error, -1);
3833 	if (model && !GDA_IS_DATA_MODEL (model)) {
3834 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_STATEMENT_TYPE_ERROR,
3835 			      "%s", _("Statement is not a selection statement"));
3836 		g_object_unref (model);
3837 		model = NULL;
3838 	}
3839 	return model;
3840 }
3841 
3842 /**
3843  * gda_connection_statement_execute_select_fullv: (skip)
3844  * @cnc: a #GdaConnection object.
3845  * @stmt: a #GdaStatement object.
3846  * @params: (allow-none): a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or %NULL
3847  * @model_usage: specifies how the returned data model will be used as a #GdaStatementModelUsage enum
3848  * @error: a place to store an error, or %NULL
3849  * @...: a (-1 terminated) list of (column number, GType) specifying for each column mentioned the GType
3850  * of the column in the returned #GdaDataModel.
3851  *
3852  * Executes a selection command on the given connection.
3853  *
3854  * This function returns a #GdaDataModel resulting from the SELECT statement, or %NULL
3855  * if an error occurred.
3856  *
3857  * This function is just a convenience function around the gda_connection_statement_execute()
3858  * function.
3859  *
3860  * See the documentation of the gda_connection_statement_execute() for information
3861  * about the @params list of parameters.
3862  *
3863  * Returns: (transfer full): a #GdaDataModel containing the data returned by the
3864  * data source, or %NULL if an error occurred
3865  */
3866 GdaDataModel *
gda_connection_statement_execute_select_fullv(GdaConnection * cnc,GdaStatement * stmt,GdaSet * params,GdaStatementModelUsage model_usage,GError ** error,...)3867 gda_connection_statement_execute_select_fullv (GdaConnection *cnc, GdaStatement *stmt,
3868 					       GdaSet *params, GdaStatementModelUsage model_usage,
3869 					       GError **error, ...)
3870 {
3871 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
3872 	g_return_val_if_fail (cnc->priv->provider_obj, NULL);
3873 	g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
3874 	g_return_val_if_fail (PROV_CLASS (cnc->priv->provider_obj)->statement_execute, NULL);
3875 
3876 	va_list ap;
3877 	GdaDataModel *model;
3878 	GType *types, *req_types;
3879 	GTimer *timer = NULL;
3880 
3881 	va_start (ap, error);
3882 	types = make_col_types_array (ap);
3883 	va_end (ap);
3884 
3885 	g_object_ref ((GObject*) cnc);
3886 	gda_connection_lock ((GdaLockable*) cnc);
3887 
3888 	_clear_connection_events (cnc);
3889 
3890 	if (!cnc->priv->provider_data) {
3891 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR,
3892 			     _("Connection is closed"));
3893 		gda_connection_unlock (GDA_LOCKABLE (cnc));
3894 		g_object_unref ((GObject*) cnc);
3895 		g_free (types);
3896 		return NULL;
3897 	}
3898 
3899 	req_types = merge_column_types (_gda_statement_get_requested_types (stmt), types);
3900 	if (req_types) {
3901 		g_free (types);
3902 		types = req_types;
3903 		req_types = NULL;
3904 	}
3905 	else if (_gda_statement_get_requested_types (stmt))
3906 		req_types = (GType*) _gda_statement_get_requested_types (stmt);
3907 
3908 	if (! (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS) &&
3909 	    ! (model_usage & GDA_STATEMENT_MODEL_CURSOR_FORWARD))
3910 		model_usage |= GDA_STATEMENT_MODEL_RANDOM_ACCESS;
3911 
3912 	dump_exec_params (cnc, stmt, params);
3913 	if (cnc->priv->exec_times)
3914 		timer = g_timer_new ();
3915 	if (cnc->priv->exec_slowdown && !cnc->priv->is_thread_wrapper)
3916 		g_usleep (cnc->priv->exec_slowdown);
3917 
3918 	model = (GdaDataModel *) PROV_CLASS (cnc->priv->provider_obj)->statement_execute (cnc->priv->provider_obj,
3919 											  cnc, stmt, params, model_usage,
3920 											  req_types ? req_types : types,
3921 											  NULL, NULL,
3922 											  NULL, NULL, error);
3923 	if (timer)
3924 		g_timer_stop (timer);
3925 	gda_connection_unlock ((GdaLockable*) cnc);
3926 	g_object_unref ((GObject*) cnc);
3927 	g_free (types);
3928 	if (model && timer)
3929 		add_exec_time_to_object ((GObject*) model, timer);
3930 	if (timer)
3931 		g_timer_destroy (timer);
3932 	if (model) {
3933 		if (GDA_IS_DATA_SELECT (model) && (model_usage & GDA_STATEMENT_MODEL_OFFLINE) &&
3934 		    ! gda_data_select_prepare_for_offline ((GdaDataSelect*) model, error)) {
3935 			g_object_unref (model);
3936 			model = NULL;
3937 		}
3938 		else if (!GDA_IS_DATA_MODEL (model)) {
3939 			g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_STATEMENT_TYPE_ERROR,
3940 				     "%s", _("Statement is not a selection statement"));
3941 			g_object_unref (model);
3942 			model = NULL;
3943 			update_meta_store_after_statement_exec (cnc, stmt, params);
3944 		}
3945 	}
3946 	return model;
3947 }
3948 
3949 /**
3950  * gda_connection_statement_execute_select_full:
3951  * @cnc: a #GdaConnection object.
3952  * @stmt: a #GdaStatement object.
3953  * @params: (allow-none): a #GdaSet object (which can be obtained using gda_statement_get_parameters()), or %NULL
3954  * @model_usage: specifies how the returned data model will be used as a #GdaStatementModelUsage enum
3955  * @col_types: (array) (allow-none): an array of GType to request each returned #GdaDataModel's column's GType, terminated with the G_TYPE_NONE
3956  * value. Any value left to 0 will make the database provider determine the real GType. @col_types can also be %NULL if no
3957  * column type is specified.
3958  * @error: a place to store an error, or %NULL
3959  *
3960  * Executes a selection command on the given connection.
3961  *
3962  * This function returns a #GdaDataModel resulting from the SELECT statement, or %NULL
3963  * if an error occurred.
3964  *
3965  * This function is just a convenience function around the gda_connection_statement_execute()
3966  * function.
3967  *
3968  * See the documentation of the gda_connection_statement_execute() for information
3969  * about the @params list of parameters.
3970  *
3971  * Returns: (transfer full): a #GdaDataModel containing the data returned by the
3972  * data source, or %NULL if an error occurred
3973  */
3974 GdaDataModel *
gda_connection_statement_execute_select_full(GdaConnection * cnc,GdaStatement * stmt,GdaSet * params,GdaStatementModelUsage model_usage,GType * col_types,GError ** error)3975 gda_connection_statement_execute_select_full (GdaConnection *cnc, GdaStatement *stmt,
3976 					      GdaSet *params, GdaStatementModelUsage model_usage,
3977 					      GType *col_types, GError **error)
3978 {
3979 	GdaDataModel *model;
3980 	GTimer *timer = NULL;
3981 
3982 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
3983 	g_return_val_if_fail (cnc->priv->provider_obj, NULL);
3984 	g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
3985 	g_return_val_if_fail (PROV_CLASS (cnc->priv->provider_obj)->statement_execute, NULL);
3986 
3987 	g_object_ref ((GObject*) cnc);
3988 	gda_connection_lock ((GdaLockable*) cnc);
3989 
3990 	if (!cnc->priv->provider_data) {
3991 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR,
3992 			     _("Connection is closed"));
3993 		gda_connection_unlock (GDA_LOCKABLE (cnc));
3994 		g_object_unref ((GObject*) cnc);
3995 		return NULL;
3996 	}
3997 
3998 	GType *req_types;
3999 	req_types = merge_column_types (_gda_statement_get_requested_types (stmt), col_types);
4000 	if (!req_types && !col_types)
4001 		col_types = (GType*) _gda_statement_get_requested_types (stmt);
4002 
4003 	if (! (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS) &&
4004 	    ! (model_usage & GDA_STATEMENT_MODEL_CURSOR_FORWARD))
4005 		model_usage |= GDA_STATEMENT_MODEL_RANDOM_ACCESS;
4006 
4007 	dump_exec_params (cnc, stmt, params);
4008 	if (cnc->priv->exec_times)
4009 		timer = g_timer_new ();
4010 	if (cnc->priv->exec_slowdown && !cnc->priv->is_thread_wrapper)
4011 		g_usleep (cnc->priv->exec_slowdown);
4012 
4013 	model = (GdaDataModel *) PROV_CLASS (cnc->priv->provider_obj)->statement_execute (cnc->priv->provider_obj,
4014 											  cnc, stmt, params,
4015 											  model_usage,
4016 											  req_types ? req_types : col_types,
4017 											  NULL,
4018 											  NULL, NULL, NULL, error);
4019 	if (timer)
4020 		g_timer_stop (timer);
4021 	g_free (req_types);
4022 	gda_connection_unlock ((GdaLockable*) cnc);
4023 	g_object_unref ((GObject*) cnc);
4024 
4025 	if (model && timer)
4026 		add_exec_time_to_object ((GObject*) model, timer);
4027 	if (model) {
4028 		if (GDA_IS_DATA_SELECT (model) && (model_usage & GDA_STATEMENT_MODEL_OFFLINE) &&
4029 		    ! gda_data_select_prepare_for_offline ((GdaDataSelect*) model, error)) {
4030 			g_object_unref (model);
4031 			model = NULL;
4032 		}
4033 		else if (!GDA_IS_DATA_MODEL (model)) {
4034 			g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_STATEMENT_TYPE_ERROR,
4035 				     "%s", _("Statement is not a selection statement"));
4036 			g_object_unref (model);
4037 			model = NULL;
4038 			update_meta_store_after_statement_exec (cnc, stmt, params);
4039 		}
4040 	}
4041 	if (timer)
4042 		g_timer_destroy (timer);
4043 	return model;
4044 }
4045 
4046 /**
4047  * gda_connection_repetitive_statement_execute:
4048  * @cnc: a #GdaConnection
4049  * @rstmt: a #GdaRepetitiveStatement object
4050  * @model_usage: specifies how the returned data model will be used as a #GdaStatementModelUsage enum
4051  * @col_types: (array) (allow-none): an array of GType to request each returned GdaDataModel's column's GType, see gda_connection_statement_execute_select_full() for more information
4052  * @stop_on_error: set to TRUE if the method has to stop on the first error.
4053  * @error: a place to store errors, or %NULL
4054  *
4055  * Executes the statement upon which @rstmt is built. Note that as several statements can actually be executed by this
4056  * method, it is recommended to be within a transaction.
4057  *
4058  * If @error is not %NULL and @stop_on_error is %FALSE, then it may contain the last error which occurred.
4059  *
4060  * Returns: (transfer full) (element-type GObject): a new list of #GObject pointers (see gda_connection_statement_execute() for more information about what they
4061  * represent), one for each actual execution of the statement upon which @rstmt is built. If @stop_on_error is %FALSE, then
4062  * the list may contain some %NULL pointers which refer to statements which failed to execute.
4063  *
4064  * Since: 4.2
4065  */
4066 GSList *
gda_connection_repetitive_statement_execute(GdaConnection * cnc,GdaRepetitiveStatement * rstmt,GdaStatementModelUsage model_usage,GType * col_types,gboolean stop_on_error,GError ** error)4067 gda_connection_repetitive_statement_execute (GdaConnection *cnc, GdaRepetitiveStatement *rstmt,
4068 					     GdaStatementModelUsage model_usage, GType *col_types,
4069 					     gboolean stop_on_error, GError **error)
4070 {
4071 	GSList *sets_list, *list;
4072 	GSList *retlist = NULL;
4073 	GdaStatement *stmt;
4074 
4075 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
4076 	g_return_val_if_fail (cnc->priv->provider_obj, NULL);
4077 	g_return_val_if_fail (GDA_IS_REPETITIVE_STATEMENT (rstmt), NULL);
4078 	g_return_val_if_fail (PROV_CLASS (cnc->priv->provider_obj)->statement_execute, NULL);
4079 
4080 	g_object_get (rstmt, "statement", &stmt, NULL);
4081 	g_return_val_if_fail (stmt, NULL);
4082 
4083 	g_object_ref ((GObject*) cnc);
4084 	gda_connection_lock ((GdaLockable*) cnc);
4085 
4086 	if (!cnc->priv->provider_data) {
4087 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR,
4088 			     _("Connection is closed"));
4089 		gda_connection_unlock (GDA_LOCKABLE (cnc));
4090 		g_object_unref ((GObject*) cnc);
4091 		return NULL;
4092 	}
4093 
4094 	GType *req_types;
4095 	req_types = merge_column_types (_gda_statement_get_requested_types (stmt), col_types);
4096 	if (!req_types && !col_types)
4097 		col_types = (GType*) _gda_statement_get_requested_types (stmt);
4098 
4099 	if (! (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS) &&
4100 	    ! (model_usage & GDA_STATEMENT_MODEL_CURSOR_FORWARD))
4101 		model_usage |= GDA_STATEMENT_MODEL_RANDOM_ACCESS;
4102 
4103 	sets_list = gda_repetitive_statement_get_all_sets (rstmt);
4104 	for (list = sets_list; list; list = list->next) {
4105 		GObject *obj;
4106 		GError *lerror = NULL;
4107 		GTimer *timer = NULL;
4108 
4109 		dump_exec_params (cnc, stmt, (GdaSet*) list->data);
4110 		if (cnc->priv->exec_times)
4111 			timer = g_timer_new ();
4112 		if (cnc->priv->exec_slowdown && !cnc->priv->is_thread_wrapper)
4113 			g_usleep (cnc->priv->exec_slowdown);
4114 
4115 		obj = PROV_CLASS (cnc->priv->provider_obj)->statement_execute (cnc->priv->provider_obj, cnc, stmt,
4116 									       GDA_SET (list->data),
4117 									       model_usage,
4118 									       req_types ? req_types : col_types,
4119 									       NULL,
4120 									       NULL, NULL, NULL, &lerror);
4121 		if (timer)
4122 			g_timer_stop (timer);
4123 		if (!obj) {
4124 			if (stop_on_error) {
4125 				if (timer)
4126 					g_timer_destroy (timer);
4127 				break;
4128 			}
4129 			else {
4130 				if (error && *error) {
4131 					g_error_free (*error);
4132 					*error = NULL;
4133 				}
4134 				g_propagate_error (error, lerror);
4135 			}
4136 		}
4137 		else {
4138 			if (timer)
4139 				add_exec_time_to_object (obj, timer);
4140 			update_meta_store_after_statement_exec (cnc, stmt, (GdaSet*) list->data);
4141 
4142 			if (GDA_IS_DATA_SELECT (obj) && (model_usage & GDA_STATEMENT_MODEL_OFFLINE) &&
4143 			    ! gda_data_select_prepare_for_offline ((GdaDataSelect*) obj, error)) {
4144 				g_object_unref (obj);
4145 				obj = NULL;
4146 			}
4147 
4148 			if (obj)
4149 				retlist = g_slist_prepend (retlist, obj);
4150 		}
4151 		if (timer)
4152 			g_timer_destroy (timer);
4153 	}
4154 	g_slist_free (sets_list);
4155 	g_free (req_types);
4156 
4157 	gda_connection_unlock ((GdaLockable*) cnc);
4158 	g_object_unref ((GObject*) cnc);
4159 	g_object_unref (stmt);
4160 
4161 	return g_slist_reverse (retlist);
4162 }
4163 
4164 /*
4165  * Forces the GdaTransactionStatus. This is reserved to connections which are thread wrappers
4166  *
4167  * @trans_status may be NULL
4168  * if @trans_status is not NULL, then its ref count is increased.
4169  */
4170 void
_gda_connection_force_transaction_status(GdaConnection * cnc,GdaConnection * wrapped_cnc)4171 _gda_connection_force_transaction_status (GdaConnection *cnc, GdaConnection *wrapped_cnc)
4172 {
4173 	g_assert (cnc->priv->is_thread_wrapper);
4174 	if (cnc->priv->trans_status)
4175 		g_object_unref (cnc->priv->trans_status);
4176 
4177 	cnc->priv->trans_status = wrapped_cnc->priv->trans_status;
4178 	if (cnc->priv->trans_status)
4179 		g_object_ref (cnc->priv->trans_status);
4180 
4181 #ifdef GDA_DEBUG_signal
4182         g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
4183 #endif
4184         g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0);
4185 #ifdef GDA_DEBUG_signal
4186         g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
4187 #endif
4188 
4189 #ifdef GDA_DEBUG_NO
4190 	if (cnc->priv->trans_status)
4191 		gda_transaction_status_dump (cnc->priv->trans_status, 5);
4192 #endif
4193 }
4194 
4195 /**
4196  * gda_connection_begin_transaction:
4197  * @cnc: a #GdaConnection object.
4198  * @name: (allow-none): the name of the transation to start, or %NULL
4199  * @level: the requested transaction level (%GDA_TRANSACTION_ISOLATION_UNKNOWN if not specified)
4200  * @error: a place to store errors, or %NULL
4201  *
4202  * Starts a transaction on the data source, identified by the
4203  * @name parameter.
4204  *
4205  * Before starting a transaction, you can check whether the underlying
4206  * provider does support transactions or not by using the
4207  * gda_connection_supports_feature() function.
4208  *
4209  * Returns: %TRUE if the transaction was started successfully, %FALSE
4210  * otherwise.
4211  */
4212 gboolean
gda_connection_begin_transaction(GdaConnection * cnc,const gchar * name,GdaTransactionIsolation level,GError ** error)4213 gda_connection_begin_transaction (GdaConnection *cnc, const gchar *name, GdaTransactionIsolation level,
4214 				  GError **error)
4215 {
4216 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
4217 	g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
4218 
4219 	if (PROV_CLASS (cnc->priv->provider_obj)->begin_transaction)
4220 		return PROV_CLASS (cnc->priv->provider_obj)->begin_transaction (cnc->priv->provider_obj, cnc, name, level, error);
4221 	else
4222 		return FALSE;
4223 }
4224 
4225 /**
4226  * gda_connection_commit_transaction:
4227  * @cnc: a #GdaConnection object.
4228  * @name: (allow-none): the name of the transation to commit, or %NULL
4229  * @error: a place to store errors, or %NULL
4230  *
4231  * Commits the given transaction to the backend database. You need to call
4232  * gda_connection_begin_transaction() first.
4233  *
4234  * Returns: %TRUE if the transaction was finished successfully,
4235  * %FALSE otherwise.
4236  */
4237 gboolean
gda_connection_commit_transaction(GdaConnection * cnc,const gchar * name,GError ** error)4238 gda_connection_commit_transaction (GdaConnection *cnc, const gchar *name, GError **error)
4239 {
4240 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
4241 	g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
4242 
4243 	if (PROV_CLASS (cnc->priv->provider_obj)->commit_transaction)
4244 		return PROV_CLASS (cnc->priv->provider_obj)->commit_transaction (cnc->priv->provider_obj, cnc, name, error);
4245 	else
4246 		return FALSE;
4247 }
4248 
4249 /**
4250  * gda_connection_rollback_transaction:
4251  * @cnc: a #GdaConnection object.
4252  * @name: (allow-none): the name of the transation to commit, or %NULL
4253  * @error: a place to store errors, or %NULL
4254  *
4255  * Rollbacks the given transaction. This means that all changes
4256  * made to the underlying data source since the last call to
4257  * #gda_connection_begin_transaction() or #gda_connection_commit_transaction()
4258  * will be discarded.
4259  *
4260  * Returns: %TRUE if the operation was successful, %FALSE otherwise.
4261  */
4262 gboolean
gda_connection_rollback_transaction(GdaConnection * cnc,const gchar * name,GError ** error)4263 gda_connection_rollback_transaction (GdaConnection *cnc, const gchar *name, GError **error)
4264 {
4265 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
4266 	g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
4267 
4268 	if (PROV_CLASS (cnc->priv->provider_obj)->rollback_transaction)
4269 		return PROV_CLASS (cnc->priv->provider_obj)->rollback_transaction (cnc->priv->provider_obj, cnc, name, error);
4270 	else
4271 		return FALSE;
4272 }
4273 
4274 /**
4275  * gda_connection_add_savepoint:
4276  * @cnc: a #GdaConnection object
4277  * @name: (allow-none): name of the savepoint to add
4278  * @error: a place to store errors or %NULL
4279  *
4280  * Adds a SAVEPOINT named @name.
4281  *
4282  * Returns: TRUE if no error occurred
4283  */
4284 gboolean
gda_connection_add_savepoint(GdaConnection * cnc,const gchar * name,GError ** error)4285 gda_connection_add_savepoint (GdaConnection *cnc, const gchar *name, GError **error)
4286 {
4287 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
4288 	g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
4289 
4290 	if (PROV_CLASS (cnc->priv->provider_obj)->add_savepoint)
4291 		return PROV_CLASS (cnc->priv->provider_obj)->add_savepoint (cnc->priv->provider_obj, cnc, name, error);
4292 	else
4293 		return FALSE;
4294 }
4295 
4296 /**
4297  * gda_connection_rollback_savepoint:
4298  * @cnc: a #GdaConnection object
4299  * @name: (allow-none): name of the savepoint to rollback to
4300  * @error: a place to store errors or %NULL
4301  *
4302  * Rollback all the modifications made after the SAVEPOINT named @name.
4303  *
4304  * Returns: TRUE if no error occurred
4305  */
4306 gboolean
gda_connection_rollback_savepoint(GdaConnection * cnc,const gchar * name,GError ** error)4307 gda_connection_rollback_savepoint (GdaConnection *cnc, const gchar *name, GError **error)
4308 {
4309 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
4310 	g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
4311 
4312 	if (PROV_CLASS (cnc->priv->provider_obj)->rollback_savepoint)
4313 		return PROV_CLASS (cnc->priv->provider_obj)->rollback_savepoint (cnc->priv->provider_obj, cnc, name, error);
4314 	else
4315 		return FALSE;
4316 }
4317 
4318 /**
4319  * gda_connection_delete_savepoint:
4320  * @cnc: a #GdaConnection object
4321  * @name: (allow-none): name of the savepoint to delete
4322  * @error: a place to store errors or %NULL
4323  *
4324  * Delete the SAVEPOINT named @name when not used anymore.
4325  *
4326  * Returns: TRUE if no error occurred
4327  */
4328 gboolean
gda_connection_delete_savepoint(GdaConnection * cnc,const gchar * name,GError ** error)4329 gda_connection_delete_savepoint (GdaConnection *cnc, const gchar *name, GError **error)
4330 {
4331 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
4332 	g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
4333 
4334 	if (PROV_CLASS (cnc->priv->provider_obj)->delete_savepoint)
4335 		return PROV_CLASS (cnc->priv->provider_obj)->delete_savepoint (cnc->priv->provider_obj, cnc, name, error);
4336 	else
4337 		return FALSE;
4338 }
4339 
4340 /**
4341  * gda_connection_get_transaction_status:
4342  * @cnc: a #GdaConnection object
4343  *
4344  * Get the status of @cnc regarding transactions. The returned object should not be modified
4345  * or destroyed; however it may be modified or destroyed by the connection itself.
4346  *
4347  * If %NULL is returned, then no transaction has been associated with @cnc
4348  *
4349  * Returns: (transfer none): a #GdaTransactionStatus object, or %NULL
4350  */
4351 GdaTransactionStatus *
gda_connection_get_transaction_status(GdaConnection * cnc)4352 gda_connection_get_transaction_status (GdaConnection *cnc)
4353 {
4354 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
4355 
4356 	return cnc->priv->trans_status;
4357 }
4358 
4359 /**
4360  * gda_connection_supports_feature:
4361  * @cnc: a #GdaConnection object.
4362  * @feature: feature to ask for.
4363  *
4364  * Asks the underlying provider for if a specific feature is supported.
4365  *
4366  * Returns: %TRUE if the provider supports it, %FALSE if not.
4367  */
4368 gboolean
gda_connection_supports_feature(GdaConnection * cnc,GdaConnectionFeature feature)4369 gda_connection_supports_feature (GdaConnection *cnc, GdaConnectionFeature feature)
4370 {
4371 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
4372 	g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
4373 
4374 	if (feature == GDA_CONNECTION_FEATURE_ASYNC_EXEC)
4375 		return PROV_CLASS (cnc->priv->provider_obj)->handle_async ? TRUE : FALSE;
4376 	return gda_server_provider_supports_feature (cnc->priv->provider_obj, cnc, feature);
4377 }
4378 
4379 /* builds a list of #GdaMetaContext contexts templates: contexts which have a non NULL table_name,
4380  * and empty or partially filled column names and values specifications */
4381 static GSList *
build_upstream_context_templates(GdaMetaStore * store,GdaMetaContext * context,GSList * elist,GError ** error)4382 build_upstream_context_templates (GdaMetaStore *store, GdaMetaContext *context, GSList *elist, GError **error)
4383 {
4384 	GSList *depend_on_contexts;
4385 	GSList *retlist;
4386 	GError *lerror = NULL;
4387 	depend_on_contexts = _gda_meta_store_schema_get_upstream_contexts (store, context, &lerror);
4388 	if (!depend_on_contexts) {
4389 		if (lerror) {
4390 			/* error while getting dependencies */
4391 			g_propagate_error (error, lerror);
4392 			return FALSE;
4393 		}
4394 		return elist;
4395 	}
4396 	else {
4397 		GSList *list;
4398 		retlist = NULL;
4399 		for (list = depend_on_contexts; list; list = list->next)
4400 			retlist = build_upstream_context_templates (store, (GdaMetaContext *) list->data,
4401 								    retlist, error);
4402 		list = g_slist_concat (depend_on_contexts, elist);
4403 		retlist = g_slist_concat (retlist, list);
4404 		return retlist;
4405 	}
4406 }
4407 
4408 
4409 /* builds a list of #GdaMetaContext contexts templates: contexts which have a non NULL table_name,
4410  * and empty or partially filled column names and values specifications */
4411 static GSList *
build_downstream_context_templates(GdaMetaStore * store,GdaMetaContext * context,GSList * elist,GError ** error)4412 build_downstream_context_templates (GdaMetaStore *store, GdaMetaContext *context, GSList *elist, GError **error)
4413 {
4414 	GSList *depending_contexts;
4415 	GSList *retlist;
4416 	GError *lerror = NULL;
4417 	depending_contexts = _gda_meta_store_schema_get_downstream_contexts (store, context, &lerror);
4418 	if (!depending_contexts) {
4419 		if (lerror) {
4420 			/* error while getting dependencies */
4421 			g_propagate_error (error, lerror);
4422 			return NULL;
4423 		}
4424 		return elist;
4425 	}
4426 	else {
4427 		GSList *list;
4428 		retlist = NULL;
4429 		for (list = depending_contexts; list; list = list->next)
4430 			retlist = build_downstream_context_templates (store, (GdaMetaContext *) list->data,
4431 								      retlist, error);
4432 		list = g_slist_concat (elist, depending_contexts);
4433 		retlist = g_slist_concat (list, retlist);
4434 		return retlist;
4435 	}
4436 }
4437 
4438 static gchar *
meta_context_stringify(GdaMetaContext * context)4439 meta_context_stringify (GdaMetaContext *context)
4440 {
4441 	gint i;
4442 	gchar *str;
4443 	GString *string = g_string_new ("");
4444 
4445 	for (i = 0; i < context->size; i++) {
4446 		if (i > 0)
4447 			g_string_append_c (string, ' ');
4448 		str = gda_value_stringify (context->column_values[i]);
4449 		g_string_append_printf (string, " [%s => %s]", context->column_names[i], str);
4450 		g_free (str);
4451 	}
4452 	if (i == 0)
4453 		g_string_append (string, "no constraint in context");
4454 	str = string->str;
4455 	g_string_free (string, FALSE);
4456 	return str;
4457 }
4458 
4459 /*#define GDA_DEBUG_META_STORE_UPDATE*/
4460 #ifdef GDA_DEBUG_META_STORE_UPDATE
4461 static void
meta_context_dump(GdaMetaContext * context)4462 meta_context_dump (GdaMetaContext *context)
4463 {
4464 	gchar *str;
4465 	str = meta_context_stringify (context);
4466 	g_print ("GdaMetaContext for table %s: %s\n", context->table_name, str);
4467 	g_free (str);
4468 }
4469 #endif
4470 
4471 /*
4472  *
4473  */
4474 static gint
check_parameters(GdaMetaContext * context,GError ** error,gint nb,...)4475 check_parameters (GdaMetaContext *context, GError **error, gint nb, ...)
4476 {
4477 #define MAX_PARAMS 10
4478 	gint i;
4479 	va_list ap;
4480 	gint retval = -1;
4481 	GValue **pvalue;
4482 	struct {
4483 		GValue **pvalue;
4484 		GType    type;
4485 	} spec_array [MAX_PARAMS];
4486 	gint nb_params = 0;
4487 
4488 	va_start (ap, nb);
4489 	/* make a list of all the GValue pointers */
4490 	for (pvalue = va_arg (ap, GValue **); pvalue; pvalue = va_arg (ap, GValue **), nb_params++) {
4491 		g_assert (nb_params < MAX_PARAMS); /* hard limit, recompile to change it (should never be needed) */
4492 		spec_array[nb_params].pvalue = pvalue;
4493 		spec_array[nb_params].type = va_arg (ap, GType);
4494 	}
4495 
4496 	/* test against each test case */
4497 	for (i = 0; i < nb; i++) {
4498 		gchar *pname;
4499 		gboolean allfound = TRUE;
4500 		gint j;
4501 		for (j = 0; j < nb_params; j++)
4502 			*(spec_array[j].pvalue) = NULL;
4503 
4504 		for (pname = va_arg (ap, gchar*); pname; pname = va_arg (ap, gchar*)) {
4505 			gint j;
4506 			pvalue = va_arg (ap, GValue **);
4507 			*pvalue = NULL;
4508 			for (j = 0; allfound && (j < context->size); j++) {
4509 				if (!strcmp (context->column_names[j], pname)) {
4510 					*pvalue = context->column_values[j];
4511 					break;
4512 				}
4513 			}
4514 			if (j == context->size)
4515 				allfound = FALSE;
4516 		}
4517 		if (allfound) {
4518 			retval = i;
4519 			break;
4520 		}
4521 	}
4522 	va_end (ap);
4523 
4524 	if (retval >= 0) {
4525 		gint j;
4526 		for (j = 0; j < nb_params; j++) {
4527 			GValue *v = *(spec_array[j].pvalue);
4528 			if (v && (gda_value_is_null (v) || (G_VALUE_TYPE (v) != spec_array[j].type))) {
4529 				g_set_error (error, GDA_CONNECTION_ERROR,
4530 					     GDA_CONNECTION_META_DATA_CONTEXT_ERROR,
4531 					     "%s", _("Invalid argument"));
4532 				retval = -1;
4533 			}
4534 		}
4535 	}
4536 	else {
4537 		gchar *str;
4538 		str = meta_context_stringify (context);
4539 		g_set_error (error, GDA_CONNECTION_ERROR,
4540 			     GDA_CONNECTION_META_DATA_CONTEXT_ERROR,
4541 			     _("Missing or wrong arguments for table '%s': %s"),
4542 			     context->table_name, str);
4543 		g_free (str);
4544 	}
4545 
4546 	/*g_print ("Check arguments context => found %d\n", retval);*/
4547 	return retval;
4548 }
4549 
4550 static gboolean
local_meta_update(GdaServerProvider * provider,GdaConnection * cnc,GdaMetaContext * context,GError ** error)4551 local_meta_update (GdaServerProvider *provider, GdaConnection *cnc, GdaMetaContext *context, GError **error)
4552 {
4553 	const gchar *tname = context->table_name;
4554 	GdaMetaStore *store;
4555 	gboolean retval;
4556 
4557 	const GValue *catalog = NULL;
4558 	const GValue *schema = NULL;
4559 	const GValue *name = NULL;
4560 	gint i;
4561 
4562 
4563 #ifdef GDA_DEBUG_META_STORE_UPDATE
4564 	g_print ("%s() => ", __FUNCTION__);
4565 	meta_context_dump (context);
4566 #endif
4567 
4568 	if (*tname != '_')
4569 		return TRUE;
4570 	tname ++;
4571 
4572 	store = gda_connection_get_meta_store (cnc);
4573 	switch (*tname) {
4574 	case 'b': {
4575 		/* _builtin_data_types, params:
4576 		 *  - none
4577 		 */
4578 		ASSERT_TABLE_NAME (tname, "builtin_data_types");
4579 		if (!PROV_CLASS (provider)->meta_funcs._btypes) {
4580 			WARN_METHOD_NOT_IMPLEMENTED (provider, "_btypes");
4581 			break;
4582 		}
4583 		retval = PROV_CLASS (provider)->meta_funcs._btypes (provider, cnc, store, context, error);
4584 		WARN_META_UPDATE_FAILURE (retval, "_btypes");
4585 		return retval;
4586 	}
4587 
4588 	case 'c':
4589 		if ((tname[1] == 'o') && (tname[2] == 'l') && (tname[3] == 'u')) {
4590 			/* _columns,  params:
4591 			 *  -0- @table_catalog, @table_schema, @table_name
4592 			 *  -1- @character_set_catalog, @character_set_schema, @character_set_name
4593 			 *  -2- @collation_catalog, @collation_schema, @collation_name
4594 			 */
4595 			i = check_parameters (context, error, 3,
4596 					      &catalog, G_TYPE_STRING,
4597 					      &schema, G_TYPE_STRING,
4598 					      &name, G_TYPE_STRING, NULL,
4599 					      "table_catalog", &catalog, "table_schema", &schema, "table_name", &name, NULL,
4600 					      "character_set_catalog", &catalog, "character_set_schema", &schema, "character_set_name", &name, NULL,
4601 					      "collation_catalog", &catalog, "collation_schema", &schema, "collation_name", &name, NULL);
4602 			if (i < 0)
4603 				return FALSE;
4604 
4605 			ASSERT_TABLE_NAME (tname, "columns");
4606 			if (i == 0) {
4607 				if (!PROV_CLASS (provider)->meta_funcs.columns) {
4608 					WARN_METHOD_NOT_IMPLEMENTED (provider, "columns");
4609 					break;
4610 				}
4611 				retval = PROV_CLASS (provider)->meta_funcs.columns (provider, cnc, store, context, error,
4612 										    catalog, schema, name);
4613 				WARN_META_UPDATE_FAILURE (retval, "columns");
4614 				return retval;
4615 			}
4616 			else {
4617 				/* nothing to do */
4618 				return TRUE;
4619 			}
4620 		}
4621 		else if ((tname[1] == 'o') && (tname[2] == 'l')) {
4622 			/* _collations, params:
4623 			 *  -0- @collation_catalog, @collation_schema, @collation_name
4624 			 *  -1- @collation_catalog, @collation_schema
4625 			 */
4626 			i = check_parameters (context, error, 2,
4627 					      &catalog, G_TYPE_STRING,
4628 					      &schema, G_TYPE_STRING,
4629 					      &name, G_TYPE_STRING, NULL,
4630 					      "collation_catalog", &catalog, "collation_schema", &schema, "collation_name", &name, NULL,
4631 					      "collation_catalog", &catalog, "collation_schema", &schema, NULL);
4632 			if (i < 0)
4633 				return FALSE;
4634 
4635 			ASSERT_TABLE_NAME (tname, "collations");
4636 			if (!PROV_CLASS (provider)->meta_funcs.collations) {
4637 				WARN_METHOD_NOT_IMPLEMENTED (provider, "collations");
4638 				break;
4639 			}
4640 			retval = PROV_CLASS (provider)->meta_funcs.collations (provider, cnc, store, context, error,
4641 									       catalog, schema, name);
4642 			WARN_META_UPDATE_FAILURE (retval, "collations");
4643 			return retval;
4644 		}
4645 		else if ((tname[1] == 'h') && (tname[2] == 'a')) {
4646 			/* _character_sets, params:
4647 			 *  -0- @character_set_catalog, @character_set_schema, @character_set_name
4648 			 *  -1- @character_set_catalog, @character_set_schema
4649 			 */
4650 			i = check_parameters (context, error, 2,
4651 					      &catalog, G_TYPE_STRING,
4652 					      &schema, G_TYPE_STRING,
4653 					      &name, G_TYPE_STRING, NULL,
4654 					      "character_set_catalog", &catalog, "character_set_schema", &schema, "character_set_name", &name, NULL,
4655 					      "character_set_catalog", &catalog, "character_set_schema", &schema, NULL);
4656 			if (i < 0)
4657 				return FALSE;
4658 
4659 			ASSERT_TABLE_NAME (tname, "character_sets");
4660 			if (!PROV_CLASS (provider)->meta_funcs.character_sets) {
4661 				WARN_METHOD_NOT_IMPLEMENTED (provider, "character_sets");
4662 				break;
4663 			}
4664 			retval = PROV_CLASS (provider)->meta_funcs.character_sets (provider, cnc, store, context, error,
4665 										   catalog, schema, name);
4666 			WARN_META_UPDATE_FAILURE (retval, "character_sets");
4667 			return retval;
4668 		}
4669 		else if ((tname[1] == 'h') && (tname[2] == 'e')) {
4670 			/* _check_column_usage, params:
4671 			 *  -0- @table_catalog, @table_schema, @table_name, @constraint_name
4672 			 *  -1- @table_catalog, @table_schema, @table_name, @column_name
4673 			 */
4674 			const GValue *tabname = NULL;
4675 			const GValue *cname = NULL;
4676 			i = check_parameters (context, error, 2,
4677 					      &catalog, G_TYPE_STRING,
4678 					      &schema, G_TYPE_STRING,
4679 					      &tabname, G_TYPE_STRING,
4680 					      &cname, G_TYPE_STRING, NULL,
4681 					      "table_catalog", &catalog, "table_schema", &schema, "table_name", &tabname, "constraint_name", &cname, NULL,
4682 					      "table_catalog", &catalog, "table_schema", &schema, "table_name", &tabname, "column_name", &cname, NULL);
4683 			if (i < 0)
4684 				return FALSE;
4685 
4686 			ASSERT_TABLE_NAME (tname, "check_column_usage");
4687 			if (i == 0) {
4688 				if (!PROV_CLASS (provider)->meta_funcs.check_columns) {
4689 					WARN_METHOD_NOT_IMPLEMENTED (provider, "check_columns");
4690 					break;
4691 				}
4692 				retval = PROV_CLASS (provider)->meta_funcs.check_columns (provider, cnc, store, context, error,
4693 											  catalog, schema, tabname, cname);
4694 				WARN_META_UPDATE_FAILURE (retval, "check_columns");
4695 				return retval;
4696 			}
4697 			else {
4698 				/* nothing to do */
4699 				return TRUE;
4700 			}
4701 		}
4702 		break;
4703 
4704 	case 'd':
4705 		if ((tname[1] == 'o') && (tname[2] == 'm') && (tname[3] == 'a') && (tname[4] == 'i') && (tname[5] == 'n') &&
4706 		    (tname[6] == 's')) {
4707 			/* _domains, params:
4708 			 *  -0- @domain_catalog, @domain_schema
4709 			 */
4710 			i = check_parameters (context, error, 1,
4711 					      &catalog, G_TYPE_STRING,
4712 					      &schema, G_TYPE_STRING, NULL,
4713 					      "domain_catalog", &catalog, "domain_schema", &schema, NULL);
4714 			if (i < 0)
4715 				return FALSE;
4716 
4717 			ASSERT_TABLE_NAME (tname, "domains");
4718 			if (!PROV_CLASS (provider)->meta_funcs.domains) {
4719 				WARN_METHOD_NOT_IMPLEMENTED (provider, "domains");
4720 				break;
4721 			}
4722 			retval = PROV_CLASS (provider)->meta_funcs.domains (provider, cnc, store, context, error,
4723 									    catalog, schema);
4724 			WARN_META_UPDATE_FAILURE (retval, "domains");
4725 			return retval;
4726 		}
4727 		else {
4728 			/* _domain_constraints, params:
4729 			 *  -0- @domain_catalog, @domain_schema, @domain_name
4730 			 *  -1- @constraint_catalog, @constraint_schema
4731 			 */
4732 			const GValue *domname = NULL;
4733 			i = check_parameters (context, error, 2,
4734 					      &catalog, G_TYPE_STRING,
4735 					      &schema, G_TYPE_STRING,
4736 					      &domname, G_TYPE_STRING, NULL,
4737 					      "domain_catalog", &catalog, "domain_schema", &schema, "domain_name", &domname, NULL,
4738 					      "constraint_catalog", &catalog, "constraint_schema", &schema, NULL);
4739 
4740 			if (i < 0)
4741 				return FALSE;
4742 			if (i == 1)
4743 				return TRUE; /* nothing to do */
4744 
4745 			ASSERT_TABLE_NAME (tname, "domain_constraints");
4746 			if (!PROV_CLASS (provider)->meta_funcs.constraints_dom) {
4747 				WARN_METHOD_NOT_IMPLEMENTED (provider, "constraints_dom");
4748 				break;
4749 			}
4750 			retval = PROV_CLASS (provider)->meta_funcs.constraints_dom (provider, cnc, store, context, error,
4751 										    catalog, schema, domname);
4752 			WARN_META_UPDATE_FAILURE (retval, "constraints_dom");
4753 			return retval;
4754 		}
4755 		break;
4756 
4757 	case 'e':
4758 		if (tname[1] == 'n') {
4759 			/* _enums, params:
4760 			 *  -0- @udt_catalog, @udt_schema, @udt_name
4761 			 */
4762 			i = check_parameters (context, error, 1,
4763 					      &catalog, G_TYPE_STRING,
4764 					      &schema, G_TYPE_STRING,
4765 					      &name, G_TYPE_STRING, NULL,
4766 					      "udt_catalog", &catalog, "udt_schema", &schema, "udt_name", &name, NULL);
4767 			if (i < 0)
4768 				return FALSE;
4769 
4770 			ASSERT_TABLE_NAME (tname, "enums");
4771 			if (!PROV_CLASS (provider)->meta_funcs.enums) {
4772 				WARN_METHOD_NOT_IMPLEMENTED (provider, "enums");
4773 				break;
4774 			}
4775 			retval = PROV_CLASS (provider)->meta_funcs.enums (provider, cnc, store, context, error,
4776 									  catalog, schema, name);
4777 			WARN_META_UPDATE_FAILURE (retval, "enums");
4778 			return retval;
4779 		}
4780 		else {
4781 			/* _element_types, params:
4782 			 *  - none
4783 			 *  -0- @specific_name
4784 			 */
4785 			i = check_parameters (context, error, 1,
4786 					      &name, G_TYPE_STRING, NULL,
4787 					      "specific_name", &name, NULL);
4788 			ASSERT_TABLE_NAME (tname, "element_types");
4789 			if (i < 0) {
4790 				if (!PROV_CLASS (provider)->meta_funcs._el_types) {
4791 					WARN_METHOD_NOT_IMPLEMENTED (provider, "_el_types");
4792 					break;
4793 				}
4794 				retval = PROV_CLASS (provider)->meta_funcs._el_types (provider, cnc, store, context, error);
4795 				WARN_META_UPDATE_FAILURE (retval, "_el_types");
4796 			}
4797 			else {
4798 				if (!PROV_CLASS (provider)->meta_funcs.el_types) {
4799 					WARN_METHOD_NOT_IMPLEMENTED (provider, "el_types");
4800 					break;
4801 				}
4802 				retval = PROV_CLASS (provider)->meta_funcs.el_types (provider, cnc, store, context, error, name);
4803 				WARN_META_UPDATE_FAILURE (retval, "el_types");
4804 			}
4805 			return retval;
4806 		}
4807 		break;
4808 
4809 	case 'i':
4810 		if ((tname[1] == 'n') && (tname[2] == 'f')) {
4811 			/* _information_schema_catalog_name, params:
4812 			 *  - none
4813 			 */
4814 			ASSERT_TABLE_NAME (tname, "information_schema_catalog_name");
4815 			if (!PROV_CLASS (provider)->meta_funcs._info) {
4816 				WARN_METHOD_NOT_IMPLEMENTED (provider, "_info");
4817 				break;
4818 			}
4819 			retval = PROV_CLASS (provider)->meta_funcs._info (provider, cnc, store, context, error);
4820 			WARN_META_UPDATE_FAILURE (retval, "_info");
4821 			return retval;
4822 		}
4823 		else {
4824 			/* _index_column_usage, params:
4825 			 *  -0- @table_catalog, @table_schema, @table_name, @index_name
4826 			 */
4827 			const GValue *iname = NULL;
4828 			i = check_parameters (context, error, 1,
4829 					      &catalog, G_TYPE_STRING,
4830 					      &schema, G_TYPE_STRING,
4831 					      &name, G_TYPE_STRING,
4832 					      &iname, G_TYPE_STRING, NULL,
4833 					      "table_catalog", &catalog, "table_schema", &schema, "table_name", &name, "index_name", &iname, NULL);
4834 
4835 			if (i < 0)
4836 				return FALSE;
4837 
4838 			ASSERT_TABLE_NAME (tname, "index_column_usage");
4839 			if (!PROV_CLASS (provider)->meta_funcs.index_cols) {
4840 				WARN_METHOD_NOT_IMPLEMENTED (provider, "index_cols");
4841 				break;
4842 			}
4843 			retval = PROV_CLASS (provider)->meta_funcs.index_cols (provider, cnc, store, context, error,
4844 									       catalog, schema, name, iname);
4845 			WARN_META_UPDATE_FAILURE (retval, "index_cols");
4846 			return retval;
4847 		}
4848 		break;
4849 	case 'k': {
4850 		/* _key_column_usage, params:
4851 		 *  -0- @table_catalog, @table_schema, @table_name, @constraint_name
4852 		 *  -0- @ref_table_catalog, @ref_table_schema, @ref_table_name, @ref_constraint_name
4853 		 */
4854 		const GValue *tabname = NULL;
4855 		const GValue *cname = NULL;
4856 		i = check_parameters (context, error, 2,
4857 				      &catalog, G_TYPE_STRING,
4858 				      &schema, G_TYPE_STRING,
4859 				      &tabname, G_TYPE_STRING,
4860 				      &cname, G_TYPE_STRING, NULL,
4861 				      "table_catalog", &catalog, "table_schema", &schema, "table_name", &tabname, "constraint_name", &cname, NULL,
4862 				      "table_catalog", &catalog, "table_schema", &schema, "table_name", &tabname, "column_name", &cname, NULL);
4863 		if (i < 0)
4864 			return FALSE;
4865 
4866 		ASSERT_TABLE_NAME (tname, "key_column_usage");
4867 		if (i == 0) {
4868 			if (!PROV_CLASS (provider)->meta_funcs.key_columns) {
4869 				WARN_METHOD_NOT_IMPLEMENTED (provider, "key_columns");
4870 				break;
4871 			}
4872 			retval = PROV_CLASS (provider)->meta_funcs.key_columns (provider, cnc, store, context, error,
4873 										catalog, schema, tabname, cname);
4874 			WARN_META_UPDATE_FAILURE (retval, "key_columns");
4875 			return retval;
4876 		}
4877 		else {
4878 			/* nothing to do */
4879 			return TRUE;
4880 		}
4881 		break;
4882 	}
4883 
4884 	case 'p':
4885 		/* _parameters, params:
4886 		 *  -0- @specific_catalog, @specific_schema, @specific_name
4887 		 */
4888 		i = check_parameters (context, error, 1,
4889 				      &catalog, G_TYPE_STRING,
4890 				      &schema, G_TYPE_STRING,
4891 				      &name, G_TYPE_STRING, NULL,
4892 				      "specific_catalog", &catalog, "specific_schema", &schema, "specific_name", &name, NULL);
4893 		if (i < 0)
4894 			return FALSE;
4895 
4896 		ASSERT_TABLE_NAME (tname, "parameters");
4897 		if (!PROV_CLASS (provider)->meta_funcs.routine_par) {
4898 			WARN_METHOD_NOT_IMPLEMENTED (provider, "routine_par");
4899 			break;
4900 		}
4901 		retval = PROV_CLASS (provider)->meta_funcs.routine_par (provider, cnc, store, context, error,
4902 									catalog, schema, name);
4903 		WARN_META_UPDATE_FAILURE (retval, "routine_par");
4904 		return retval;
4905 
4906 	case 'r':
4907 		if ((tname[1] == 'e') && (tname[2] == 'f')) {
4908 			/* _referential_constraints, params:
4909 			 *  -0- @table_catalog, @table_schema, @table_name, @constraint_name
4910 			 *  -0- @ref_table_catalog, @ref_table_schema, @ref_table_name, @ref_constraint_name
4911 			 */
4912 			const GValue *tabname = NULL;
4913 			const GValue *cname = NULL;
4914 			i = check_parameters (context, error, 2,
4915 					      &catalog, G_TYPE_STRING,
4916 					      &schema, G_TYPE_STRING,
4917 					      &tabname, G_TYPE_STRING,
4918 					      &cname, G_TYPE_STRING, NULL,
4919 					      "table_catalog", &catalog, "table_schema", &schema, "table_name", &tabname, "constraint_name", &cname, NULL,
4920 					      "ref_table_catalog", &catalog, "ref_table_schema", &schema, "ref_table_name", &tabname, "ref_constraint_name", &cname, NULL);
4921 			if (i < 0)
4922 				return FALSE;
4923 
4924 			ASSERT_TABLE_NAME (tname, "referential_constraints");
4925 			if (i == 0) {
4926 				if (!PROV_CLASS (provider)->meta_funcs.constraints_ref) {
4927 					WARN_METHOD_NOT_IMPLEMENTED (provider, "constraints_ref");
4928 					break;
4929 				}
4930 				retval = PROV_CLASS (provider)->meta_funcs.constraints_ref (provider, cnc, store, context, error,
4931 											    catalog, schema, tabname, cname);
4932 				WARN_META_UPDATE_FAILURE (retval, "constraints_ref");
4933 				return retval;
4934 			}
4935 			else {
4936 				/* nothing to do */
4937 				return TRUE;
4938 			}
4939 		}
4940 		if ((tname[1] == 'o') && (tname[2] == 'u') && (tname[3] == 't') && (tname[4] == 'i') &&
4941 		    (tname[5] == 'n') && (tname[6] == 'e') && (tname[7] == 's')) {
4942 			/* _routines, params:
4943 			 *  -0- @specific_catalog, @specific_schema, @specific_name
4944 			 *  -1- @specific_catalog, @specific_schema
4945 			 */
4946 			i = check_parameters (context, error, 2,
4947 					      &catalog, G_TYPE_STRING,
4948 					      &schema, G_TYPE_STRING,
4949 					      &name, G_TYPE_STRING, NULL,
4950 					      "specific_catalog", &catalog, "specific_schema", &schema, "specific_name", &name, NULL,
4951 					      "specific_catalog", &catalog, "specific_schema", &schema, NULL);
4952 			if (i < 0)
4953 				return FALSE;
4954 
4955 			ASSERT_TABLE_NAME (tname, "routines");
4956 			if (!PROV_CLASS (provider)->meta_funcs.routines) {
4957 				WARN_METHOD_NOT_IMPLEMENTED (provider, "routines");
4958 				break;
4959 			}
4960 			retval = PROV_CLASS (provider)->meta_funcs.routines (provider, cnc, store, context, error,
4961 									     catalog, schema, name);
4962 			WARN_META_UPDATE_FAILURE (retval, "routines");
4963 			return retval;
4964 		}
4965 		else {
4966 			/* _routine_columns, params:
4967 			 *  -0- @specific_catalog, @specific_schema, @specific_name
4968 			 */
4969 			i = check_parameters (context, error, 1,
4970 					      &catalog, G_TYPE_STRING,
4971 					      &schema, G_TYPE_STRING,
4972 					      &name, G_TYPE_STRING, NULL,
4973 					      "specific_catalog", &catalog, "specific_schema", &schema, "specific_name", &name, NULL);
4974 			if (i < 0)
4975 				return FALSE;
4976 
4977 			ASSERT_TABLE_NAME (tname, "routine_columns");
4978 			if (!PROV_CLASS (provider)->meta_funcs.routine_col) {
4979 				WARN_METHOD_NOT_IMPLEMENTED (provider, "routine_col");
4980 				break;
4981 			}
4982 			retval = PROV_CLASS (provider)->meta_funcs.routine_col (provider, cnc, store, context, error,
4983 										catalog, schema, name);
4984 			WARN_META_UPDATE_FAILURE (retval, "routine_col");
4985 			return retval;
4986 		}
4987 		break;
4988 
4989 	case 's': {
4990 		/* _schemata, params:
4991 		 *  -0- @catalog_name, @schema_name
4992 		 *  -1- @catalog_name
4993 		 */
4994 		i = check_parameters (context, error, 2,
4995 				      &schema, G_TYPE_STRING, NULL,
4996 				      "catalog_name", &catalog, "schema_name", &schema, NULL,
4997 				      "catalog_name", &catalog, NULL);
4998 		if (i < 0)
4999 			return FALSE;
5000 		ASSERT_TABLE_NAME (tname, "schemata");
5001 
5002 		if (!PROV_CLASS (provider)->meta_funcs.schemata) {
5003 			WARN_METHOD_NOT_IMPLEMENTED (provider, "schemata");
5004 			break;
5005 		}
5006 		retval = PROV_CLASS (provider)->meta_funcs.schemata (provider, cnc, store, context, error,
5007 								     catalog, schema);
5008 		WARN_META_UPDATE_FAILURE (retval, "schemata");
5009 		return retval;
5010 	}
5011 	case 't':
5012 		if ((tname[1] == 'a') && (tname[2] == 'b') && (tname[3] == 'l') && (tname[4] == 'e') && (tname[5] == 's')) {
5013 			/* _tables, params:
5014 			 *  -0- @table_catalog, @table_schema, @table_name
5015 			 *  -1- @table_catalog, @table_schema
5016 			 */
5017 			i = check_parameters (context, error, 2,
5018 					      &catalog, G_TYPE_STRING,
5019 					      &schema, G_TYPE_STRING,
5020 					      &name, G_TYPE_STRING, NULL,
5021 					      "table_catalog", &catalog, "table_schema", &schema, "table_name", &name, NULL,
5022 					      "table_catalog", &catalog, "table_schema", &schema, NULL);
5023 			if (i < 0)
5024 				return FALSE;
5025 
5026 			ASSERT_TABLE_NAME (tname, "tables");
5027 			if (!PROV_CLASS (provider)->meta_funcs.tables_views) {
5028 				WARN_METHOD_NOT_IMPLEMENTED (provider, "tables_views");
5029 				break;
5030 			}
5031 			retval = PROV_CLASS (provider)->meta_funcs.tables_views (provider, cnc, store, context, error,
5032 										 catalog, schema, name);
5033 			WARN_META_UPDATE_FAILURE (retval, "tables_views");
5034 			return retval;
5035 		}
5036 		else if ((tname[1] == 'a') && (tname[2] == 'b') && (tname[3] == 'l') && (tname[4] == 'e') &&
5037 			 (tname[5] == '_') && (tname[6] == 'c')) {
5038 			/* _tables_constraints, params:
5039 			 *  -0- @table_catalog, @table_schema, @table_name, @constraint_name
5040 			 *  -1- @table_catalog, @table_schema, @table_name
5041 			 */
5042 			const GValue *cname = NULL;
5043 			const GValue *tabname = NULL;
5044 			i = check_parameters (context, error, 2,
5045 					      &catalog, G_TYPE_STRING,
5046 					      &schema, G_TYPE_STRING,
5047 					      &cname, G_TYPE_STRING,
5048 					      &tabname, G_TYPE_STRING, NULL,
5049 					      "table_catalog", &catalog, "table_schema", &schema, "table_name", &tabname, "constraint_name", &cname, NULL,
5050 					      "table_catalog", &catalog, "table_schema", &schema, "table_name", &tabname, NULL);
5051 
5052 			if (i < 0)
5053 				return FALSE;
5054 
5055 			ASSERT_TABLE_NAME (tname, "table_constraints");
5056 			if (!PROV_CLASS (provider)->meta_funcs.constraints_tab) {
5057 				WARN_METHOD_NOT_IMPLEMENTED (provider, "constraints_tab");
5058 				break;
5059 			}
5060 			retval = PROV_CLASS (provider)->meta_funcs.constraints_tab (provider, cnc, store, context, error,
5061 										    catalog, schema, tabname, cname);
5062 			WARN_META_UPDATE_FAILURE (retval, "constraints_tab");
5063 			return retval;
5064 		}
5065 		else if ((tname[1] == 'a') && (tname[2] == 'b') && (tname[3] == 'l') && (tname[4] == 'e') &&
5066 			 (tname[5] == '_') && (tname[6] == 'i')) {
5067 			/* _table_indexes, params:
5068 			 *  -0- @table_catalog, @table_schema, @table_name, @index_name
5069 			 *  -1- @table_catalog, @table_schema, @table_name
5070 			 */
5071 			const GValue *iname = NULL;
5072 			const GValue *tabname = NULL;
5073 			i = check_parameters (context, error, 2,
5074 					      &catalog, G_TYPE_STRING,
5075 					      &schema, G_TYPE_STRING,
5076 					      &iname, G_TYPE_STRING,
5077 					      &tabname, G_TYPE_STRING, NULL,
5078 					      "table_catalog", &catalog, "table_schema", &schema, "table_name", &tabname, "index_name", &iname, NULL,
5079 					      "table_catalog", &catalog, "table_schema", &schema, "table_name", &tabname, NULL);
5080 
5081 			if (i < 0)
5082 				return FALSE;
5083 
5084 			ASSERT_TABLE_NAME (tname, "table_indexes");
5085 			if (!PROV_CLASS (provider)->meta_funcs.indexes_tab) {
5086 				WARN_METHOD_NOT_IMPLEMENTED (provider, "indexes_tab");
5087 				break;
5088 			}
5089 			retval = PROV_CLASS (provider)->meta_funcs.indexes_tab (provider, cnc, store, context, error,
5090 										catalog, schema, tabname, iname);
5091 			WARN_META_UPDATE_FAILURE (retval, "indexes_tab");
5092 			return retval;
5093 		}
5094 		else if ((tname[1] == 'r') && (tname[2] == 'i')) {
5095 			/* _triggers,  params:
5096 			 *  -0- @trigger_catalog, @trigger_schema
5097 			 *  -1- @event_object_catalog, @event_object_schema, @event_object_table
5098 			 */
5099 			i = check_parameters (context, error, 2,
5100 					      &catalog, G_TYPE_STRING,
5101 					      &schema, G_TYPE_STRING,
5102 					      &name, G_TYPE_STRING, NULL,
5103 					      "trigger_catalog", &catalog, "trigger_schema", &schema, NULL,
5104 					      "event_object_catalog", &catalog, "event_object_schema", &schema, "event_object_table", &name, NULL);
5105 			if (i < 0)
5106 				return FALSE;
5107 
5108 			ASSERT_TABLE_NAME (tname, "triggers");
5109 			if (i == 1) {
5110 				if (!PROV_CLASS (provider)->meta_funcs.triggers) {
5111 					WARN_METHOD_NOT_IMPLEMENTED (provider, "triggers");
5112 					break;
5113 				}
5114 				retval = PROV_CLASS (provider)->meta_funcs.triggers (provider, cnc, store, context, error,
5115 										     catalog, schema, name);
5116 				WARN_META_UPDATE_FAILURE (retval, "triggers");
5117 				return retval;
5118 			}
5119 			else {
5120 				/* nothing to do */
5121 				return TRUE;
5122 			}
5123 		}
5124 		break;
5125 
5126 	case 'u':
5127 		if ((tname[1] == 'd') && (tname[2] == 't') && (tname[3] == 0)) {
5128 			/* _udt, params:
5129 			 *  -0- @udt_catalog, @udt_schema
5130 			 */
5131 			i = check_parameters (context, error, 1,
5132 					      &catalog, G_TYPE_STRING,
5133 					      &schema, G_TYPE_STRING, NULL,
5134 					      "udt_catalog", &catalog, "udt_schema", &schema, NULL);
5135 			if (i < 0)
5136 				return FALSE;
5137 
5138 			ASSERT_TABLE_NAME (tname, "udt");
5139 			if (!PROV_CLASS (provider)->meta_funcs.udt) {
5140 				WARN_METHOD_NOT_IMPLEMENTED (provider, "udt");
5141 				break;
5142 			}
5143 			retval = PROV_CLASS (provider)->meta_funcs.udt (provider, cnc, store, context, error,
5144 									catalog, schema);
5145 			WARN_META_UPDATE_FAILURE (retval, "udt");
5146 			return retval;
5147 		}
5148 		else if ((tname[1] == 'd') && (tname[2] == 't') && (tname[3] == '_')) {
5149 			/* _udt_columns, params:
5150 			 *  -0- @udt_catalog, @udt_schema, @udt_name
5151 			 */
5152 			i = check_parameters (context, error, 1,
5153 					      &catalog, G_TYPE_STRING,
5154 					      &schema, G_TYPE_STRING,
5155 					      &name, G_TYPE_STRING, NULL,
5156 					      "udt_catalog", &catalog, "udt_schema", &schema, "udt_name", &name, NULL);
5157 			if (i < 0)
5158 				return FALSE;
5159 
5160 			ASSERT_TABLE_NAME (tname, "udt_columns");
5161 			if (!PROV_CLASS (provider)->meta_funcs.udt_cols) {
5162 				WARN_METHOD_NOT_IMPLEMENTED (provider, "udt_cols");
5163 				break;
5164 			}
5165 			retval = PROV_CLASS (provider)->meta_funcs.udt_cols (provider, cnc, store, context, error,
5166 									     catalog, schema, name);
5167 			WARN_META_UPDATE_FAILURE (retval, "udt_cols");
5168 			return retval;
5169 		}
5170 		break;
5171 
5172 	case 'v': {
5173 		/* _view_column_usage,  params:
5174 		 *  -0- @view_catalog, @view_schema, @view_name
5175 		 *  -1- @table_catalog, @table_schema, @table_name, @column_name
5176 		 */
5177 		const GValue *colname = NULL;
5178 		i = check_parameters (context, error, 2,
5179 				      &catalog, G_TYPE_STRING,
5180 				      &schema, G_TYPE_STRING,
5181 				      &colname, G_TYPE_STRING,
5182 				      &name, G_TYPE_STRING, NULL,
5183 				      "view_catalog", &catalog, "view_schema", &schema, "view_name", &name, NULL,
5184 				      "table_catalog", &catalog, "table_schema", &schema, "table_name", &name,
5185 				      "column_name", &colname, NULL);
5186 		if (i < 0)
5187 			return FALSE;
5188 
5189 		ASSERT_TABLE_NAME (tname, "view_column_usage");
5190 		if (i == 0) {
5191 			if (!PROV_CLASS (provider)->meta_funcs.view_cols) {
5192 				WARN_METHOD_NOT_IMPLEMENTED (provider, "view_cols");
5193 				break;
5194 			}
5195 			retval = PROV_CLASS (provider)->meta_funcs.view_cols (provider, cnc, store, context, error,
5196 									      catalog, schema, name);
5197 			WARN_META_UPDATE_FAILURE (retval, "view_cols");
5198 			return retval;
5199 		}
5200 		else {
5201 			/* nothing to do */
5202 			return TRUE;
5203 		}
5204 		break;
5205 	}
5206 	default:
5207 		break;
5208 	}
5209 	return TRUE;
5210 }
5211 
5212 typedef struct {
5213 	GdaServerProvider  *prov;
5214 	GdaConnection      *cnc;
5215 	GError             *error;
5216 	GSList             *context_templates;
5217 	GHashTable         *context_templates_hash;
5218 } DownstreamCallbackData;
5219 
5220 static GError *
suggest_update_cb_downstream(G_GNUC_UNUSED GdaMetaStore * store,GdaMetaContext * suggest,DownstreamCallbackData * data)5221 suggest_update_cb_downstream (G_GNUC_UNUSED GdaMetaStore *store, GdaMetaContext *suggest, DownstreamCallbackData *data)
5222 {
5223 #define MAX_CONTEXT_SIZE 10
5224 	if (data->error)
5225 		return data->error;
5226 
5227 	GdaMetaContext *templ_context;
5228 	GdaMetaContext loc_suggest;
5229 	gchar *column_names[MAX_CONTEXT_SIZE];
5230 	GValue *column_values[MAX_CONTEXT_SIZE];
5231 
5232 	/* if there is no context with the same table name in the templates, then exit right now */
5233 	templ_context = g_hash_table_lookup (data->context_templates_hash, suggest->table_name);
5234 	if (!templ_context)
5235 		return NULL;
5236 
5237 	if (templ_context->size > 0) {
5238 		/* setup @loc_suggest */
5239 		gint i, j;
5240 
5241 		if (suggest->size > MAX_CONTEXT_SIZE) {
5242 			g_warning ("Internal limitation at %s(), limitation should be at least %d, please report a bug",
5243 				   __FUNCTION__, suggest->size);
5244 			return NULL;
5245 		}
5246 		loc_suggest.size = suggest->size;
5247 		loc_suggest.table_name = suggest->table_name;
5248 		loc_suggest.column_names = column_names;
5249 		loc_suggest.column_values = column_values;
5250 		memcpy (loc_suggest.column_names, suggest->column_names, sizeof (gchar *) * suggest->size); /* Flawfinder: ignore */
5251 		memcpy (loc_suggest.column_values, suggest->column_values, sizeof (GValue *) * suggest->size); /* Flawfinder: ignore */
5252 
5253 		/* check that any @suggest's columns which is in @templ_context's has the same values */
5254 		for (j = 0; j < suggest->size; j++) {
5255 			for (i = 0; i < templ_context->size; i++) {
5256 				if (!strcmp (templ_context->column_names[i], suggest->column_names[j])) {
5257 					/* same column name, now check column value */
5258 					if (G_VALUE_TYPE (templ_context->column_values[i]) !=
5259 					    G_VALUE_TYPE (suggest->column_values[j])) {
5260 						g_warning ("Internal error: column types mismatch for GdaMetaContext "
5261 							   "table '%s' and column '%s' (%s/%s)",
5262 							   templ_context->table_name, templ_context->column_names[i],
5263 							   g_type_name (G_VALUE_TYPE (templ_context->column_values[i])),
5264 							   g_type_name (G_VALUE_TYPE (suggest->column_values[j])));
5265 						return NULL;
5266 					}
5267 					if (gda_value_compare (templ_context->column_values[i], suggest->column_values[j]))
5268 						/* different values */
5269 						return NULL;
5270 					break;
5271 				}
5272 			}
5273 		}
5274 
5275 		/* @templ_context may contain some more columns => add them to @loc_suggest */
5276 		for (i = 0; i < templ_context->size; i++) {
5277 			for (j = 0; j < suggest->size; j++) {
5278 				if (!strcmp (templ_context->column_names[i], suggest->column_names[j])) {
5279 					j = -1;
5280 					break;
5281 				}
5282 			}
5283 			if (j >= 0) {
5284 				if (loc_suggest.size >= MAX_CONTEXT_SIZE) {
5285 					g_warning ("Internal limitation at %s(), limitation should be at least %d, please report a bug",
5286 						   __FUNCTION__, loc_suggest.size + 1);
5287 					return NULL;
5288 				}
5289 				loc_suggest.column_names [loc_suggest.size] = templ_context->column_names [i];
5290 				loc_suggest.column_values [loc_suggest.size] = templ_context->column_values [i];
5291 				loc_suggest.size ++;
5292 			}
5293 		}
5294 
5295 		suggest = &loc_suggest;
5296 	}
5297 
5298 	GError *lerror = NULL;
5299 	if (!local_meta_update (data->prov, data->cnc, suggest, &lerror)) {
5300 		if (lerror)
5301 			data->error = lerror;
5302 		else {
5303 			g_set_error (&lerror,GDA_CONNECTION_ERROR,
5304 				     GDA_CONNECTION_META_DATA_CONTEXT_ERROR,
5305 				      "%s", _("Meta update error"));
5306 			data->error = lerror;
5307 		}
5308 
5309 		return data->error;
5310 	}
5311 
5312 	return NULL;
5313 }
5314 
5315 /**
5316  * gda_connection_update_meta_store:
5317  * @cnc: a #GdaConnection object.
5318  * @context: (allow-none): description of which part of @cnc's associated #GdaMetaStore should be updated, or %NULL
5319  * @error: a place to store errors, or %NULL
5320  *
5321  * Updates @cnc's associated #GdaMetaStore. If @context is not %NULL, then only the parts described by
5322  * @context will be updated, and if it is %NULL, then the complete meta store will be updated. Detailed
5323  * explanations follow:
5324  *
5325  * In order to keep the meta store's contents in a consistent state, the update process involves updating
5326  * the contents of all the tables related to one where the contents change. For example the "_columns"
5327  * table (which lists all the columns of a table) depends on the "_tables" table (which lists all the tables
5328  * in a schema), so if a row is added, removed or modified in the "_tables", then the "_columns" table's contents
5329  * needs to be updated as well regarding that row.
5330  *
5331  * If @context is %NULL, then the update process will simply overwrite any data that was present in all the
5332  * meta store's tables with new (up to date) data even if nothing has changed, without having to build the
5333  * tables' dependency tree. This is the recommended way of proceeding when dealing with a meta store which
5334  * might be outdated.
5335  *
5336  * On the other hand, if @context is not %NULL, then a tree of the dependencies has to be built (depending on
5337  * @context) and only some parts of the meta store are updated following that dependencies tree. Specifying a
5338  * context may be useful for example in the following situations:
5339  * <itemizedlist>
5340  *   <listitem><para>One knows that a database object has changed (for example a table created), and
5341  *                   may use the @context to request that only the information about that table be updated
5342  *             </para></listitem>
5343  *   <listitem><para>One is only interested in the list of views, and may request that only the information
5344  *                   about views may be updated</para></listitem>
5345  * </itemizedlist>
5346  *
5347  * When @context is not %NULL, and contains specified SQL identifiers (for example the "table_name" of the "_tables"
5348  * table), then each SQL identifier has to match the convention the #GdaMetaStore has adopted regarding
5349  * case sensitivity, using gda_connection_quote_sql_identifier() or gda_meta_store_sql_identifier_quote().
5350  *
5351  * see the <link linkend="information_schema:sql_identifiers">
5352  * meta data section about SQL identifiers</link> for more information, and the documentation about the
5353  * gda_sql_identifier_quote() function which will be most useful.
5354  *
5355  * Note however that usually <emphasis>more</emphasis> information will be updated than strictly requested by
5356  * the @context argument.
5357  *
5358  * For more information, see the <link linkend="information_schema">Database structure</link> section, and
5359  * the <link linkend="howto-meta2">Update the meta data about a table</link> howto.
5360  *
5361  * Returns: TRUE if no error occurred
5362  */
5363 gboolean
gda_connection_update_meta_store(GdaConnection * cnc,GdaMetaContext * context,GError ** error)5364 gda_connection_update_meta_store (GdaConnection *cnc, GdaMetaContext *context, GError **error)
5365 {
5366 	GdaMetaStore *store;
5367 
5368 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
5369 	g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
5370 
5371 	gda_connection_lock ((GdaLockable*) cnc);
5372 
5373 	/* Get or create the GdaMetaStore object */
5374 	store = gda_connection_get_meta_store (cnc);
5375 	g_assert (store);
5376 
5377 	/* unlock connection */
5378 	gda_connection_unlock ((GdaLockable*) cnc);
5379 
5380 	if (context) {
5381 		GdaMetaContext *lcontext;
5382 		GSList *list;
5383 		GSList *up_templates;
5384 		GSList *dn_templates;
5385 		GError *lerror = NULL;
5386 
5387 		lcontext = _gda_meta_store_validate_context (store, context, error);
5388 		if (!lcontext)
5389 			return FALSE;
5390 		/* alter local context because "_tables" and "_views" always go together so only
5391 		   "_tables" should be updated and providers should always update "_tables" and "_views"
5392 		*/
5393 		if (!strcmp (lcontext->table_name, "_views"))
5394 			lcontext->table_name = "_tables";
5395 
5396 		/* build context templates */
5397 		up_templates = build_upstream_context_templates (store, lcontext, NULL, &lerror);
5398 		if (!up_templates) {
5399 			if (lerror) {
5400 				g_propagate_error (error, lerror);
5401 				return FALSE;
5402 			}
5403 		}
5404 		dn_templates = build_downstream_context_templates (store, lcontext, NULL, &lerror);
5405 		if (!dn_templates) {
5406 			if (lerror) {
5407 				g_propagate_error (error, lerror);
5408 				return FALSE;
5409 			}
5410 		}
5411 
5412 #ifdef GDA_DEBUG_META_STORE_UPDATE
5413 		g_print ("\n*********** TEMPLATES:\n");
5414 		for (list = up_templates; list; list = list->next) {
5415 			g_print ("UP: ");
5416 			meta_context_dump ((GdaMetaContext*) list->data);
5417 		}
5418 		g_print ("->: ");
5419 		meta_context_dump (lcontext);
5420 		for (list = dn_templates; list; list = list->next) {
5421 			g_print ("DN: ");
5422 			meta_context_dump ((GdaMetaContext*) list->data);
5423 		}
5424 #endif
5425 
5426 		gulong signal_id;
5427 		DownstreamCallbackData cbd;
5428 		gboolean retval = TRUE;
5429 
5430 		cbd.prov = cnc->priv->provider_obj;
5431 		cbd.cnc = cnc;
5432 		cbd.error = NULL;
5433 		cbd.context_templates = g_slist_concat (g_slist_append (up_templates, lcontext), dn_templates);
5434 		cbd.context_templates_hash = g_hash_table_new (g_str_hash, g_str_equal);
5435 		for (list = cbd.context_templates; list; list = list->next)
5436 			g_hash_table_insert (cbd.context_templates_hash, ((GdaMetaContext*)list->data)->table_name,
5437 					     list->data);
5438 
5439 		signal_id = g_signal_connect (store, "suggest-update",
5440 					      G_CALLBACK (suggest_update_cb_downstream), &cbd);
5441 
5442 		retval = local_meta_update (cnc->priv->provider_obj, cnc,
5443 					    (GdaMetaContext*) (cbd.context_templates->data), error);
5444 
5445 		g_signal_handler_disconnect (store, signal_id);
5446 
5447 		/* free the memory associated with each template */
5448 		for (list = cbd.context_templates; list; list = list->next) {
5449 			GdaMetaContext *c = (GdaMetaContext *) list->data;
5450 			if (c == lcontext) {
5451 				gint i;
5452 				for (i = 0; i < c->size; i++) {
5453 					g_free (c->column_names [i]);
5454 					if (c->column_values [i])
5455 						gda_value_free (c->column_values [i]);
5456 				}
5457 			}
5458 			if (c->size > 0) {
5459 				g_free (c->column_names);
5460 				g_free (c->column_values);
5461 			}
5462 			g_free (c);
5463 		}
5464 		g_slist_free (cbd.context_templates);
5465 		g_hash_table_destroy (cbd.context_templates_hash);
5466 
5467 		return retval;
5468 	}
5469 	else {
5470 		typedef gboolean (*RFunc) (GdaServerProvider *, GdaConnection *, GdaMetaStore *,
5471 					   GdaMetaContext *, GError **);
5472 		typedef struct {
5473 			gchar *table_name;
5474 			gchar *func_name;
5475 			RFunc  func;
5476 		} RMeta;
5477 
5478 		GdaMetaContext lcontext;
5479 		gint nb = 0, i;
5480 		RMeta rmeta[] = {
5481 			{"_information_schema_catalog_name", "_info", NULL},
5482 			{"_builtin_data_types", "_btypes", NULL},
5483 			{"_udt", "_udt", NULL},
5484 			{"_udt_columns", "_udt_cols", NULL},
5485 			{"_enums", "_enums", NULL},
5486 			{"_domains", "_domains", NULL},
5487 			{"_domain_constraints", "_constraints_dom", NULL},
5488 			{"_element_types", "_el_types", NULL},
5489 			{"_collations", "_collations", NULL},
5490 			{"_character_sets", "_character_sets", NULL},
5491 			{"_schemata", "_schemata", NULL},
5492 			{"_tables_views", "_tables_views", NULL},
5493 			{"_columns", "_columns", NULL},
5494 			{"_view_column_usage", "_view_cols", NULL},
5495 			{"_table_constraints", "_constraints_tab", NULL},
5496 			{"_referential_constraints", "_constraints_ref", NULL},
5497 			{"_key_column_usage", "_key_columns", NULL},
5498 			{"_check_column_usage", "_check_columns", NULL},
5499 			{"_triggers", "_triggers", NULL},
5500 			{"_routines", "_routines", NULL},
5501 			{"_routine_columns", "_routine_col", NULL},
5502 			{"_parameters", "_routine_par", NULL},
5503 			{"_table_indexes", "_indexes_tab", NULL},
5504 			{"_index_column_usage", "_index_cols", NULL}
5505 		};
5506 		GdaServerProvider *provider = cnc->priv->provider_obj;
5507 		gboolean retval;
5508 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._info;
5509 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._btypes;
5510 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._udt;
5511 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._udt_cols;
5512 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._enums;
5513 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._domains;
5514 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._constraints_dom;
5515 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._el_types;
5516 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._collations;
5517 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._character_sets;
5518 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._schemata;
5519 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._tables_views;
5520 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._columns;
5521 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._view_cols;
5522 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._constraints_tab;
5523 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._constraints_ref;
5524 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._key_columns;
5525 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._check_columns;
5526 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._triggers;
5527 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._routines;
5528 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._routine_col;
5529 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._routine_par;
5530 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._indexes_tab;
5531 		rmeta [nb++].func = PROV_CLASS (provider)->meta_funcs._index_cols;
5532 		g_assert (nb == sizeof (rmeta) / sizeof (RMeta));
5533 
5534 		if (! _gda_meta_store_begin_data_reset (store, error)) {
5535 			return FALSE;
5536 		}
5537 
5538 		lcontext.size = 0;
5539 		for (i = 0; i < nb; i++) {
5540 			/*g_print ("TH %p %s(cnc=>%p store=>%p)\n", g_thread_self(), rmeta [i].func_name, cnc, store);*/
5541 			if (! rmeta [i].func)
5542 				WARN_METHOD_NOT_IMPLEMENTED (provider, rmeta [i].func_name);
5543 			else {
5544 				lcontext.table_name = rmeta [i].table_name;
5545 				if (!rmeta [i].func (provider, cnc, store, &lcontext, error)) {
5546 					/*
5547 					g_print ("TH %p CNC %p ERROR, prov=%p (%s)\n", g_thread_self(), cnc,
5548 						 gda_connection_get_provider (cnc),
5549 						 gda_connection_get_provider_name (cnc));
5550 					*/
5551 					/*if (error && *error)
5552 						g_warning ("%s (Provider %s)\n", (*error)->message,
5553 							   gda_connection_get_provider_name (cnc));
5554 					*/
5555 
5556 					WARN_META_UPDATE_FAILURE (FALSE, rmeta [i].func_name);
5557 					goto onerror;
5558 				}
5559 			}
5560 		}
5561 		retval = _gda_meta_store_finish_data_reset (store, error);
5562 		return retval;
5563 
5564 	onerror:
5565 		_gda_meta_store_cancel_data_reset (store, NULL);
5566 		return FALSE;
5567 	}
5568 }
5569 
5570 /*
5571  * predefined statements for meta store data retrieval
5572  */
5573 typedef struct {
5574 	GdaConnectionMetaType  meta_type;
5575 	gint                   nb_filters;
5576 	gchar                **filters;
5577 } MetaKey;
5578 
5579 static guint
meta_key_hash(gconstpointer key)5580 meta_key_hash (gconstpointer key)
5581 {
5582 	return ((((MetaKey*) key)->meta_type) << 2) + ((MetaKey*) key)->nb_filters;
5583 }
5584 
5585 static gboolean
meta_key_equal(gconstpointer a,gconstpointer b)5586 meta_key_equal (gconstpointer a, gconstpointer b)
5587 {
5588 	MetaKey* ak = (MetaKey*) a;
5589 	MetaKey* bk = (MetaKey*) b;
5590 	gint i;
5591 
5592 	if ((ak->meta_type != bk->meta_type) ||
5593 	    (ak->nb_filters != bk->nb_filters))
5594 		return FALSE;
5595 	for (i = 0; i < ak->nb_filters; i++)
5596 		if (strcmp (ak->filters[i], bk->filters[i]))
5597 			return FALSE;
5598 
5599 	return TRUE;
5600 }
5601 
5602 static GHashTable *
prepare_meta_statements_hash(void)5603 prepare_meta_statements_hash (void)
5604 {
5605 	GHashTable *h;
5606 	MetaKey *key;
5607 	GdaStatement *stmt;
5608 	GdaSqlParser *parser = gda_sql_parser_new ();
5609 	const gchar *sql;
5610 
5611 	gchar **name_array = g_new (gchar *, 1);
5612 	name_array[0] = "name";
5613 
5614 	gchar **name_col_array = g_new (gchar *, 2);
5615 	name_col_array[0] = "name";
5616 	name_col_array[1] = "field_name";
5617 
5618 	gchar **name_index_array = g_new (gchar *, 2);
5619 	name_index_array[0] = "name";
5620 	name_index_array[1] = "index_name";
5621 
5622 	h = g_hash_table_new (meta_key_hash, meta_key_equal);
5623 
5624 	/* GDA_CONNECTION_META_NAMESPACES */
5625 	key = g_new0 (MetaKey, 1);
5626 	key->meta_type = GDA_CONNECTION_META_NAMESPACES;
5627 	sql = "SELECT schema_name, schema_owner, schema_internal FROM _schemata";
5628 	stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL);
5629 	if (!stmt)
5630 		g_error ("Could not parse internal statement: %s\n", sql);
5631 	g_hash_table_insert (h, key, stmt);
5632 
5633 	key = g_new0 (MetaKey, 1);
5634 	key->meta_type = GDA_CONNECTION_META_NAMESPACES;
5635 	key->nb_filters = 1;
5636 	key->filters = name_array;
5637 	sql = "SELECT schema_name, schema_owner, schema_internal FROM _schemata WHERE schema_name=##name::string";
5638 	stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL);
5639 	if (!stmt)
5640 		g_error ("Could not parse internal statement: %s\n", sql);
5641 	g_hash_table_insert (h, key, stmt);
5642 
5643 	/* GDA_CONNECTION_META_TYPES */
5644 	key = g_new0 (MetaKey, 1);
5645 	key->meta_type = GDA_CONNECTION_META_TYPES;
5646 	sql = "SELECT short_type_name, gtype, comments, synonyms FROM _all_types WHERE NOT internal";
5647 	stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL);
5648 	if (!stmt)
5649 		g_error ("Could not parse internal statement: %s\n", sql);
5650 	g_hash_table_insert (h, key, stmt);
5651 
5652 	key = g_new0 (MetaKey, 1);
5653 	key->meta_type = GDA_CONNECTION_META_TYPES;
5654 	key->nb_filters = 1;
5655 	key->filters = name_array;
5656 	sql = "SELECT short_type_name, gtype, comments, synonyms FROM _all_types WHERE NOT internal AND short_type_name=##name::string";
5657 	stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL);
5658 	if (!stmt)
5659 		g_error ("Could not parse internal statement: %s\n", sql);
5660 	g_hash_table_insert (h, key, stmt);
5661 
5662 	/* GDA_CONNECTION_META_TABLES */
5663 	key = g_new0 (MetaKey, 1);
5664 	key->meta_type = GDA_CONNECTION_META_TABLES;
5665 	sql = "SELECT table_short_name, table_schema, table_full_name, table_owner, table_comments FROM _tables WHERE table_type LIKE '%TABLE%' AND table_short_name != table_full_name";
5666 	stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL);
5667 	if (!stmt)
5668 		g_error ("Could not parse internal statement: %s\n", sql);
5669 	g_hash_table_insert (h, key, stmt);
5670 
5671 	key = g_new0 (MetaKey, 1);
5672 	key->meta_type = GDA_CONNECTION_META_TABLES;
5673 	key->nb_filters = 1;
5674 	key->filters = name_array;
5675 	sql = "SELECT table_short_name, table_schema, table_full_name, table_owner, table_comments FROM _tables WHERE table_type LIKE '%TABLE%' AND table_short_name != table_full_name AND table_short_name=##name::string";
5676 	stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL);
5677 	if (!stmt)
5678 		g_error ("Could not parse internal statement: %s\n", sql);
5679 	g_hash_table_insert (h, key, stmt);
5680 
5681 	/* GDA_CONNECTION_META_VIEWS */
5682 	key = g_new0 (MetaKey, 1);
5683 	key->meta_type = GDA_CONNECTION_META_VIEWS;
5684 	sql = "SELECT t.table_short_name, t.table_schema, t.table_full_name, t.table_owner, t.table_comments, v.view_definition FROM _views as v NATURAL JOIN _tables as t WHERE t.table_short_name != t.table_full_name";
5685 	stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL);
5686 	if (!stmt)
5687 		g_error ("Could not parse internal statement: %s\n", sql);
5688 	g_hash_table_insert (h, key, stmt);
5689 
5690 	key = g_new0 (MetaKey, 1);
5691 	key->meta_type = GDA_CONNECTION_META_VIEWS;
5692 	key->nb_filters = 1;
5693 	key->filters = name_array;
5694 	sql = "SELECT t.table_short_name, t.table_schema, t.table_full_name, t.table_owner, t.table_comments, v.view_definition FROM _views as v NATURAL JOIN _tables as t WHERE t.table_short_name != t.table_full_name AND table_short_name=##name::string";
5695 	stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL);
5696 	if (!stmt)
5697 		g_error ("Could not parse internal statement: %s\n", sql);
5698 	g_hash_table_insert (h, key, stmt);
5699 
5700 	/* GDA_CONNECTION_META_FIELDS */
5701 	key = g_new0 (MetaKey, 1);
5702 	key->meta_type = GDA_CONNECTION_META_FIELDS;
5703 	key->nb_filters = 1;
5704 	key->filters = name_array;
5705 	sql = "SELECT c.column_name, c.data_type, c.gtype, c.numeric_precision, c.numeric_scale, c.is_nullable AS 'Nullable', c.column_default, c.extra FROM _columns as c NATURAL JOIN _tables as t WHERE t.table_short_name=##name::string ORDER BY c.ordinal_position";
5706 	stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL);
5707 	if (!stmt)
5708 		g_error ("Could not parse internal statement: %s\n", sql);
5709 	g_hash_table_insert (h, key, stmt);
5710 
5711 	key = g_new0 (MetaKey, 1);
5712 	key->meta_type = GDA_CONNECTION_META_FIELDS;
5713 	key->nb_filters = 2;
5714 	key->filters = name_col_array;
5715 	sql = "SELECT c.column_name, c.data_type, c.gtype, c.numeric_precision, c.numeric_scale, c.is_nullable AS 'Nullable', c.column_default, c.extra FROM _columns as c NATURAL JOIN _tables as t WHERE t.table_short_name=##name::string AND c.column_name = ##field_name::string ORDER BY c.ordinal_position";
5716 	stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL);
5717 	if (!stmt)
5718 		g_error ("Could not parse internal statement: %s\n", sql);
5719 	g_hash_table_insert (h, key, stmt);
5720 
5721 	/* GDA_CONNECTION_META_INDEXES */
5722 	key = g_new0 (MetaKey, 1);
5723 	key->meta_type = GDA_CONNECTION_META_INDEXES;
5724 	key->nb_filters = 1;
5725 	key->filters = name_array;
5726 	sql = "SELECT i.table_name, i.table_schema, i.index_name, d.column_name, d.ordinal_position, i.index_type FROM _table_indexes as i INNER JOIN _index_column_usage as d ON (d.table_catalog = i.table_catalog AND d.table_schema = i.table_schema AND d.table_name = i.table_name) INNER JOIN _tables t ON (t.table_catalog = i.table_catalog AND t.table_schema = i.table_schema AND t.table_name = i.table_name) WHERE t.table_short_name=##name::string";
5727 	stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL);
5728 	if (!stmt)
5729 		g_error ("Could not parse internal statement: %s\n", sql);
5730 	g_hash_table_insert (h, key, stmt);
5731 
5732 	key = g_new0 (MetaKey, 1);
5733 	key->meta_type = GDA_CONNECTION_META_INDEXES;
5734 	key->nb_filters = 2;
5735 	key->filters = name_index_array;
5736 	sql = "SELECT i.table_name, i.table_schema, i.index_name, d.column_name, d.ordinal_position, i.index_type FROM _table_indexes as i INNER JOIN _index_column_usage as d ON (d.table_catalog = i.table_catalog AND d.table_schema = i.table_schema AND d.table_name = i.table_name) INNER JOIN _tables t ON (t.table_catalog = i.table_catalog AND t.table_schema = i.table_schema AND t.table_name = i.table_name) WHERE t.table_short_name=##name::string AND i.index_name=##index_name::string";
5737 	stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL);
5738 	if (!stmt)
5739 		g_error ("Could not parse internal statement: %s\n", sql);
5740 	g_hash_table_insert (h, key, stmt);
5741 
5742 	return h;
5743 }
5744 
5745 /**
5746  * gda_connection_get_meta_store_data:
5747  * @cnc: a #GdaConnection object.
5748  * @meta_type: describes which data to get.
5749  * @error: a place to store errors, or %NULL
5750  * @nb_filters: the number of filters in the @... argument
5751  * @...: a list of (filter name (gchar *), filter value (GValue*)) pairs specifying
5752  * the filter to apply to the returned data model's contents (there must be @nb_filters pairs)
5753  *
5754  * Retrieves data stored in @cnc's associated #GdaMetaStore object. This method is useful
5755  * to easily get some information about the meta-data associated to @cnc, such as the list of
5756  * tables, views, and other database objects.
5757  *
5758  * Note: it's up to the caller to make sure the information contained within @cnc's associated #GdaMetaStore
5759  * is up to date using gda_connection_update_meta_store() (it can become outdated if the database's schema
5760  * is modified).
5761  *
5762  * For more information about the returned data model's attributes, or about the @meta_type and ... filter arguments,
5763  * see <link linkend="GdaConnectionMetaTypeHead">this description</link>.
5764  *
5765  * Also, when using filters involving data which are SQL identifiers, make sure each SQL identifier
5766  * is represented using the #GdaMetaStore convention, using gda_meta_store_sql_identifier_quote() or
5767  * gda_meta_store_sql_identifier_quote().
5768  *
5769  * See the <link linkend="information_schema:sql_identifiers">
5770  * meta data section about SQL identifiers</link> for more information, and the documentation about the
5771  * gda_sql_identifier_quote() function which will be most useful.
5772  *
5773  * Returns: (transfer full): a #GdaDataModel containing the data required. The caller is responsible
5774  * for freeing the returned model using g_object_unref().
5775  */
5776 GdaDataModel *
gda_connection_get_meta_store_data(GdaConnection * cnc,GdaConnectionMetaType meta_type,GError ** error,gint nb_filters,...)5777 gda_connection_get_meta_store_data (GdaConnection *cnc,
5778 				    GdaConnectionMetaType meta_type,
5779 				    GError **error, gint nb_filters, ...)
5780 {
5781 	GList* filters = NULL;
5782 	GdaDataModel* model = NULL;
5783 	gint i;
5784 
5785 	if (nb_filters > 0) {
5786 		va_list ap;
5787 		va_start (ap, nb_filters);
5788 		for (i = 0; (i < nb_filters); i++) {
5789 			GdaHolder *h;
5790 			GValue *v;
5791 			gchar* fname;
5792 
5793 			fname = va_arg (ap, gchar*);
5794 			if (!fname)
5795 				break;
5796 			v = va_arg (ap, GValue*);
5797 			if (!v || gda_value_is_null (v))
5798 				continue;
5799 			h = g_object_new (GDA_TYPE_HOLDER, "g-type", G_VALUE_TYPE (v), "id", fname, NULL);
5800 			filters = g_list_append (filters, h);
5801 			if (!gda_holder_set_value (h, v, error)) {
5802 				va_end (ap);
5803 				goto onerror;
5804 			}
5805 		}
5806 		va_end (ap);
5807 	}
5808 	model = gda_connection_get_meta_store_data_v (cnc, meta_type, filters, error);
5809 
5810  onerror:
5811 	g_list_foreach (filters, (GFunc) g_object_unref, NULL);
5812 	g_list_free (filters);
5813 
5814 	return model;
5815 }
5816 
5817 /**
5818  * gda_connection_get_meta_store_data_v:
5819  * @cnc: a #GdaConnection object.
5820  * @meta_type: describes which data to get.
5821  * @error: a place to store errors, or %NULL
5822  * @filters: (element-type GdaHolder): a #GList of #GdaHolder objects
5823  *
5824  * see #gda_connection_get_meta_store_data
5825  *
5826  * Returns: (transfer full): a #GdaDataModel containing the data required. The caller is responsible
5827  * for freeing the returned model using g_object_unref().
5828  */
5829 GdaDataModel *
gda_connection_get_meta_store_data_v(GdaConnection * cnc,GdaConnectionMetaType meta_type,GList * filters,GError ** error)5830 gda_connection_get_meta_store_data_v (GdaConnection *cnc, GdaConnectionMetaType meta_type,
5831 				      GList* filters, GError **error)
5832 {
5833 	GdaMetaStore *store;
5834 	GdaDataModel *model = NULL;
5835 	static GHashTable *stmt_hash = NULL;
5836 	GdaStatement *stmt;
5837 	GdaSet *set = NULL;
5838 	GList* node;
5839 
5840 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
5841 	g_return_val_if_fail (cnc->priv->provider_obj, NULL);
5842 
5843 	/* Get or create the GdaMetaStore object */
5844 	store = gda_connection_get_meta_store (cnc);
5845 	g_assert (store);
5846 
5847 	/* fetch the statement */
5848 	MetaKey key;
5849 	gint i;
5850 	if (!stmt_hash)
5851 		stmt_hash = prepare_meta_statements_hash ();
5852 	key.meta_type = meta_type;
5853 	key.nb_filters = g_list_length (filters);
5854 	key.filters = NULL;
5855 	if (key.nb_filters > 0)
5856 		key.filters = g_new (gchar *, key.nb_filters);
5857 	for (node = filters, i = 0;
5858 	     node;
5859 	     node = node->next, i++) {
5860 		if (!set)
5861 			set = g_object_new (GDA_TYPE_SET, NULL);
5862 		gda_set_add_holder (set, GDA_HOLDER (node->data));
5863 		key.filters[i] = (gchar*) gda_holder_get_id (GDA_HOLDER (node->data));
5864 	}
5865 	stmt = g_hash_table_lookup (stmt_hash, &key);
5866 	g_free (key.filters);
5867 	if (!stmt) {
5868 		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR,
5869 			      "%s", _("Wrong filter arguments"));
5870 		if (set)
5871 			g_object_unref (set);
5872 		return NULL;
5873 	}
5874 
5875 	/* execute statement to fetch the requested result from the meta store's connection
5876 	 * REM: at a latter time the data model should be specific and update itself whenever
5877 	 * the meta store is updated
5878 	 */
5879 	model = gda_connection_statement_execute_select (gda_meta_store_get_internal_connection (store),
5880 							 stmt, set, error);
5881 	if (set)
5882 		g_object_unref (set);
5883 
5884 	return model;
5885 }
5886 
5887 
5888 /**
5889  * gda_connection_get_events:
5890  * @cnc: a #GdaConnection.
5891  *
5892  * Retrieves a list of the last errors occurred during the connection. The returned list is
5893  * chronologically ordered such as that the most recent event is the #GdaConnectionEvent of the first node.
5894  *
5895  * Warning: the @cnc object may change the list if connection events occur
5896  *
5897  * Returns: (transfer none) (element-type Gda.ConnectionEvent): a #GList of #GdaConnectionEvent objects (the list should not be modified)
5898  */
5899 const GList *
gda_connection_get_events(GdaConnection * cnc)5900 gda_connection_get_events (GdaConnection *cnc)
5901 {
5902 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
5903 
5904 	if (cnc->priv->events_list)
5905 		return cnc->priv->events_list;
5906 
5907 
5908 	/* a new list of the GdaConnectionEvent objects is created, the
5909 	 * ownership of each GdaConnectionEvent object is transfered to the list */
5910 	GList *list = NULL;
5911 	if (cnc->priv->events_array_full) {
5912 		gint i;
5913 		for (i = cnc->priv->events_array_next + 1; ; i++) {
5914 			if (i == cnc->priv->events_array_size)
5915 				i = 0;
5916 			if (i == cnc->priv->events_array_next)
5917 				break;
5918 			GdaConnectionEvent *ev;
5919 			ev = cnc->priv->events_array [i];
5920 			cnc->priv->events_array [i] = NULL;
5921 			g_assert (ev);
5922 			list = g_list_prepend (list, ev);
5923 		}
5924 	}
5925 	else {
5926 		gint i;
5927 		for (i = 0; i < cnc->priv->events_array_next; i++) {
5928 			GdaConnectionEvent *ev;
5929 			ev = cnc->priv->events_array [i];
5930 			g_assert (ev);
5931 			list = g_list_prepend (list, ev);
5932 			cnc->priv->events_array [i] = NULL;
5933 		}
5934 	}
5935 	cnc->priv->events_list = g_list_reverse (list);
5936 
5937 	/* reset events */
5938 	cnc->priv->events_array_full = FALSE;
5939 	cnc->priv->events_array_next = 0;
5940 
5941 	return cnc->priv->events_list;
5942 }
5943 
5944 /**
5945  * gda_connection_value_to_sql_string:
5946  * @cnc: a #GdaConnection object.
5947  * @from: #GValue to convert from
5948  *
5949  * Produces a fully quoted and escaped string from a GValue
5950  *
5951  * Returns: escaped and quoted value or NULL if not supported.
5952  */
5953 gchar *
gda_connection_value_to_sql_string(GdaConnection * cnc,GValue * from)5954 gda_connection_value_to_sql_string (GdaConnection *cnc, GValue *from)
5955 {
5956 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
5957 	g_return_val_if_fail (from != NULL, FALSE);
5958 	g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
5959 
5960 	/* execute the command on the provider */
5961 	return gda_server_provider_value_to_sql_string (cnc->priv->provider_obj, cnc, from);
5962 }
5963 
5964 /**
5965  * gda_connection_internal_transaction_started: (skip)
5966  * @cnc: a #GdaConnection
5967  * @parent_trans: (allow-none): name of the parent transaction, or %NULL
5968  * @trans_name: transaction's name, or %NULL
5969  * @isol_level: isolation level.
5970  *
5971  * Internal functions to be called by database providers when a transaction has been started
5972  * to keep track of the transaction status of the connection.
5973  *
5974  * Note: this function should not be called if gda_connection_internal_statement_executed()
5975  * has already been called because a statement's execution was necessary to perform
5976  * the action.
5977  */
5978 void
gda_connection_internal_transaction_started(GdaConnection * cnc,const gchar * parent_trans,const gchar * trans_name,GdaTransactionIsolation isol_level)5979 gda_connection_internal_transaction_started (GdaConnection *cnc, const gchar *parent_trans, const gchar *trans_name,
5980 					     GdaTransactionIsolation isol_level)
5981 {
5982 	GdaTransactionStatus *parent, *st;
5983 
5984 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
5985 
5986 	st = gda_transaction_status_new (trans_name);
5987 	st->isolation_level = isol_level;
5988 
5989 	gda_connection_lock ((GdaLockable*) cnc);
5990 
5991 	parent = gda_transaction_status_find (cnc->priv->trans_status, parent_trans, NULL);
5992 	if (!parent)
5993 		cnc->priv->trans_status = st;
5994 	else {
5995 		gda_transaction_status_add_event_sub (parent, st);
5996 		g_object_unref (st);
5997 	}
5998 #ifdef GDA_DEBUG_signal
5999         g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
6000 #endif
6001         g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0);
6002 #ifdef GDA_DEBUG_signal
6003         g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
6004 #endif
6005 
6006 #ifdef GDA_DEBUG_NO
6007 	if (cnc->priv->trans_status)
6008 		gda_transaction_status_dump (cnc->priv->trans_status, 5);
6009 #endif
6010 
6011 	gda_connection_unlock ((GdaLockable*) cnc);
6012 }
6013 
6014 /**
6015  * gda_connection_internal_transaction_rolledback: (skip)
6016  * @cnc: a #GdaConnection
6017  * @trans_name: (allow-none): transaction's name, or %NULL
6018  *
6019  * Internal functions to be called by database providers when a transaction has been rolled
6020  * back to keep track of the transaction status of the connection
6021  *
6022  * Note: this function should not be called if gda_connection_internal_statement_executed()
6023  * has already been called because a statement's execution was necessary to perform
6024  * the action.
6025  */
6026 void
gda_connection_internal_transaction_rolledback(GdaConnection * cnc,const gchar * trans_name)6027 gda_connection_internal_transaction_rolledback (GdaConnection *cnc, const gchar *trans_name)
6028 {
6029 	GdaTransactionStatus *st = NULL;
6030 	GdaTransactionStatusEvent *ev = NULL;
6031 
6032 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
6033 
6034 	gda_connection_lock ((GdaLockable*) cnc);
6035 
6036 	if (cnc->priv->trans_status)
6037 		st = gda_transaction_status_find (cnc->priv->trans_status, trans_name, &ev);
6038 	if (st) {
6039 		if (ev) {
6040 			/* there is a parent transaction */
6041 			gda_transaction_status_free_events (ev->trans, ev, TRUE);
6042 		}
6043 		else {
6044 			/* no parent transaction */
6045 			g_object_unref (cnc->priv->trans_status);
6046 			cnc->priv->trans_status = NULL;
6047 		}
6048 #ifdef GDA_DEBUG_signal
6049 		g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
6050 #endif
6051 		g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0);
6052 #ifdef GDA_DEBUG_signal
6053 		g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
6054 #endif
6055 	}
6056 	else {
6057 		g_warning (_("Connection transaction status tracking: no transaction exists for %s"), "ROLLBACK");
6058 	}
6059 #ifdef GDA_DEBUG_NO
6060 	if (cnc->priv->trans_status)
6061 		gda_transaction_status_dump (cnc->priv->trans_status, 5);
6062 #endif
6063 
6064 	gda_connection_unlock ((GdaLockable*) cnc);
6065 }
6066 
6067 /**
6068  * gda_connection_internal_transaction_committed: (skip)
6069  * @cnc: a #GdaConnection
6070  * @trans_name: (allow-none): transaction's name, or %NULL
6071  *
6072  * Internal functions to be called by database providers when a transaction has been committed
6073  * to keep track of the transaction status of the connection
6074  *
6075  * Note: this function should not be called if gda_connection_internal_statement_executed()
6076  * has already been called because a statement's execution was necessary to perform
6077  * the action.
6078  */
6079 void
gda_connection_internal_transaction_committed(GdaConnection * cnc,const gchar * trans_name)6080 gda_connection_internal_transaction_committed (GdaConnection *cnc, const gchar *trans_name)
6081 {
6082 	GdaTransactionStatus *st = NULL;
6083 	GdaTransactionStatusEvent *ev = NULL;
6084 
6085 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
6086 
6087 	gda_connection_lock ((GdaLockable*) cnc);
6088 
6089 	if (cnc->priv->trans_status)
6090 		st = gda_transaction_status_find (cnc->priv->trans_status, trans_name, &ev);
6091 	if (st) {
6092 		if (ev) {
6093 			/* there is a parent transaction */
6094 			gda_transaction_status_free_events (ev->trans, ev, TRUE);
6095 		}
6096 		else {
6097 			/* no parent transaction */
6098 			g_object_unref (cnc->priv->trans_status);
6099 			cnc->priv->trans_status = NULL;
6100 		}
6101 #ifdef GDA_DEBUG_signal
6102 		g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
6103 #endif
6104 		g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0);
6105 #ifdef GDA_DEBUG_signal
6106 		g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
6107 #endif
6108 	}
6109 	else {
6110 		g_warning (_("Connection transaction status tracking: no transaction exists for %s"), "COMMIT");
6111 	}
6112 #ifdef GDA_DEBUG_NO
6113 	if (cnc->priv->trans_status)
6114 		gda_transaction_status_dump (cnc->priv->trans_status, 5);
6115 #endif
6116 
6117 	gda_connection_unlock ((GdaLockable*) cnc);
6118 }
6119 
6120 /**
6121  * gda_connection_internal_savepoint_added: (skip)
6122  * @cnc: a #GdaConnection
6123  * @parent_trans: (allow-none): name of the parent transaction, or %NULL
6124  * @svp_name: savepoint's name, or %NULL
6125  *
6126  * Internal functions to be called by database providers when a savepoint has been added
6127  * to keep track of the transaction status of the connection
6128  *
6129  * Note: this function should not be called if gda_connection_internal_statement_executed()
6130  * has already been called because a statement's execution was necessary to perform
6131  * the action.
6132  */
6133 void
gda_connection_internal_savepoint_added(GdaConnection * cnc,const gchar * parent_trans,const gchar * svp_name)6134 gda_connection_internal_savepoint_added (GdaConnection *cnc, const gchar *parent_trans, const gchar *svp_name)
6135 {
6136 	GdaTransactionStatus *st;
6137 
6138 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
6139 
6140 	gda_connection_lock ((GdaLockable*) cnc);
6141 
6142 	st = gda_transaction_status_find (cnc->priv->trans_status, parent_trans, NULL);
6143 	if (st) {
6144 		gda_transaction_status_add_event_svp (st, svp_name);
6145 #ifdef GDA_DEBUG_signal
6146 		g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
6147 #endif
6148 		g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0);
6149 #ifdef GDA_DEBUG_signal
6150 		g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
6151 #endif
6152 	}
6153 	else {
6154 		g_warning (_("Connection transaction status tracking: no transaction exists for %s"), "ADD SAVEPOINT");
6155 	}
6156 #ifdef GDA_DEBUG_NO
6157 	if (cnc->priv->trans_status)
6158 		gda_transaction_status_dump (cnc->priv->trans_status, 5);
6159 #endif
6160 
6161 	gda_connection_unlock ((GdaLockable*) cnc);
6162 }
6163 
6164 /**
6165  * gda_connection_internal_savepoint_rolledback: (skip)
6166  * @cnc: a #GdaConnection
6167  * @svp_name: (allow-none): savepoint's name, or %NULL
6168  *
6169  * Internal functions to be called by database providers when a savepoint has been rolled back
6170  * to keep track of the transaction status of the connection
6171  *
6172  * Note: this function should not be called if gda_connection_internal_statement_executed()
6173  * has already been called because a statement's execution was necessary to perform
6174  * the action.
6175  */
6176 void
gda_connection_internal_savepoint_rolledback(GdaConnection * cnc,const gchar * svp_name)6177 gda_connection_internal_savepoint_rolledback (GdaConnection *cnc, const gchar *svp_name)
6178 {
6179 	GdaTransactionStatus *st;
6180 	GdaTransactionStatusEvent *ev = NULL;
6181 
6182 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
6183 
6184 	gda_connection_lock ((GdaLockable*) cnc);
6185 
6186 	st = gda_transaction_status_find (cnc->priv->trans_status, svp_name, &ev);
6187 	if (st) {
6188 		gda_transaction_status_free_events (st, ev, TRUE);
6189 #ifdef GDA_DEBUG_signal
6190 		g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
6191 #endif
6192 		g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0);
6193 #ifdef GDA_DEBUG_signal
6194 		g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
6195 #endif
6196 	}
6197 	else {
6198 		g_warning (_("Connection transaction status tracking: no transaction exists for %s"), "ROLLBACK SAVEPOINT");
6199 	}
6200 #ifdef GDA_DEBUG_NO
6201 	if (cnc->priv->trans_status)
6202 		gda_transaction_status_dump (cnc->priv->trans_status, 5);
6203 #endif
6204 
6205 	gda_connection_unlock ((GdaLockable*) cnc);
6206 }
6207 
6208 /**
6209  * gda_connection_internal_savepoint_removed: (skip)
6210  * @cnc: a #GdaConnection
6211  * @svp_name: (allow-none): savepoint's name, or %NULL
6212  *
6213  * Internal functions to be called by database providers when a savepoint has been removed
6214  * to keep track of the transaction status of the connection
6215  *
6216  * Note: this function should not be called if gda_connection_internal_statement_executed()
6217  * has already been called because a statement's execution was necessary to perform
6218  * the action.
6219  */
6220 void
gda_connection_internal_savepoint_removed(GdaConnection * cnc,const gchar * svp_name)6221 gda_connection_internal_savepoint_removed (GdaConnection *cnc, const gchar *svp_name)
6222 {
6223 	GdaTransactionStatus *st;
6224 	GdaTransactionStatusEvent *ev = NULL;
6225 
6226 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
6227 
6228 	gda_connection_lock ((GdaLockable*) cnc);
6229 
6230 	st = gda_transaction_status_find (cnc->priv->trans_status, svp_name, &ev);
6231 	if (st) {
6232 		gda_transaction_status_free_events (st, ev, FALSE);
6233 #ifdef GDA_DEBUG_signal
6234 		g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
6235 #endif
6236 		g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0);
6237 #ifdef GDA_DEBUG_signal
6238 		g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
6239 #endif
6240 	}
6241 	else {
6242 		g_warning (_("Connection transaction status tracking: no transaction exists for %s"), "REMOVE SAVEPOINT");
6243 	}
6244 #ifdef GDA_DEBUG_NO
6245 	if (cnc->priv->trans_status)
6246 		gda_transaction_status_dump (cnc->priv->trans_status, 5);
6247 #endif
6248 
6249 	gda_connection_unlock ((GdaLockable*) cnc);
6250 }
6251 
6252 /**
6253  * gda_connection_internal_statement_executed: (skip)
6254  * @cnc: a #GdaConnection
6255  * @stmt: a #GdaStatement which has been executed
6256  * @params: (allow-none): execution's parameters
6257  * @error: a #GdaConnectionEvent if the execution failed, or %NULL
6258  *
6259  * Internal functions to be called by database providers when a statement has been executed
6260  * to keep track of the transaction status of the connection
6261  */
6262 void
gda_connection_internal_statement_executed(GdaConnection * cnc,GdaStatement * stmt,G_GNUC_UNUSED GdaSet * params,GdaConnectionEvent * error)6263 gda_connection_internal_statement_executed (GdaConnection *cnc, GdaStatement *stmt,
6264 					    G_GNUC_UNUSED GdaSet *params, GdaConnectionEvent *error)
6265 {
6266 	if (!error || (error && (gda_connection_event_get_event_type (error) != GDA_CONNECTION_EVENT_ERROR))) {
6267 		const GdaSqlStatement *sqlst;
6268 		GdaSqlStatementTransaction *trans;
6269 		sqlst = _gda_statement_get_internal_struct (stmt);
6270 		trans = (GdaSqlStatementTransaction*) sqlst->contents; /* warning: this may be inaccurate if stmt_type is not
6271 									  a transaction type, but the compiler does not care */
6272 
6273 		switch (sqlst->stmt_type) {
6274 		case GDA_SQL_STATEMENT_BEGIN:
6275 			gda_connection_internal_transaction_started (cnc, NULL, trans->trans_name,
6276 								     trans->isolation_level);
6277 			break;
6278 		case GDA_SQL_STATEMENT_ROLLBACK:
6279 			gda_connection_internal_transaction_rolledback (cnc, trans->trans_name);
6280 			break;
6281 		case GDA_SQL_STATEMENT_COMMIT:
6282 			gda_connection_internal_transaction_committed (cnc, trans->trans_name);
6283 			break;
6284 		case GDA_SQL_STATEMENT_SAVEPOINT:
6285 			gda_connection_internal_savepoint_added (cnc, NULL, trans->trans_name);
6286 			break;
6287 		case GDA_SQL_STATEMENT_ROLLBACK_SAVEPOINT:
6288 			gda_connection_internal_savepoint_rolledback (cnc, trans->trans_name);
6289 			break;
6290 		case GDA_SQL_STATEMENT_DELETE_SAVEPOINT:
6291 			gda_connection_internal_savepoint_removed (cnc, trans->trans_name);
6292 			break;
6293 		default: {
6294 			GdaTransactionStatus *st = NULL;
6295 
6296 			gda_connection_lock ((GdaLockable*) cnc);
6297 
6298 			if (cnc->priv->trans_status)
6299 				st = gda_transaction_status_find_current (cnc->priv->trans_status, NULL, FALSE);
6300 			if (st) {
6301 				if (sqlst->sql)
6302 					gda_transaction_status_add_event_sql (st, sqlst->sql, error);
6303 				else {
6304 					gchar *sql;
6305 					sql = gda_statement_to_sql_extended (stmt, cnc, NULL,
6306 									     GDA_STATEMENT_SQL_PARAMS_SHORT,
6307 									     NULL, NULL);
6308 					gda_transaction_status_add_event_sql (st, sql, error);
6309 					g_free (sql);
6310 				}
6311 			}
6312 #ifdef GDA_DEBUG_signal
6313 			g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
6314 #endif
6315 			g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0);
6316 #ifdef GDA_DEBUG_signal
6317 			g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
6318 #endif
6319 #ifdef GDA_DEBUG_NO
6320 			if (cnc->priv->trans_status)
6321 				gda_transaction_status_dump (cnc->priv->trans_status, 5);
6322 #endif
6323 			gda_connection_unlock ((GdaLockable*) cnc);
6324 			break;
6325 		}
6326 		}
6327 	}
6328 }
6329 
6330 /**
6331  * gda_connection_internal_change_transaction_state: (skip)
6332  * @cnc: a #GdaConnection
6333  * @newstate: the new state
6334  *
6335  * Internal function to be called by database providers to force a transaction status
6336  * change.
6337  */
6338 void
gda_connection_internal_change_transaction_state(GdaConnection * cnc,GdaTransactionStatusState newstate)6339 gda_connection_internal_change_transaction_state (GdaConnection *cnc,
6340 						  GdaTransactionStatusState newstate)
6341 {
6342 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
6343 
6344 	gda_connection_lock ((GdaLockable*) cnc);
6345 
6346 	g_return_if_fail (cnc->priv->trans_status);
6347 
6348 	if (cnc->priv->trans_status->state == newstate)
6349 		return;
6350 
6351 	cnc->priv->trans_status->state = newstate;
6352 #ifdef GDA_DEBUG_signal
6353 	g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
6354 #endif
6355 	g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0);
6356 #ifdef GDA_DEBUG_signal
6357 	g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
6358 #endif
6359 	gda_connection_unlock ((GdaLockable*) cnc);
6360 }
6361 
6362 /**
6363  * gda_connection_internal_reset_transaction_status: (skip)
6364  * @cnc: a #GdaConnection
6365  *
6366  * Internal function to be called by database providers to reset the transaction status.
6367  */
6368 void
gda_connection_internal_reset_transaction_status(GdaConnection * cnc)6369 gda_connection_internal_reset_transaction_status (GdaConnection *cnc)
6370 {
6371 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
6372 
6373 	gda_connection_lock ((GdaLockable*) cnc);
6374 	if (cnc->priv->trans_status) {
6375 		g_object_unref (cnc->priv->trans_status);
6376 		cnc->priv->trans_status = NULL;
6377 #ifdef GDA_DEBUG_signal
6378 		g_print (">> 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
6379 #endif
6380 		g_signal_emit (G_OBJECT (cnc), gda_connection_signals[TRANSACTION_STATUS_CHANGED], 0);
6381 #ifdef GDA_DEBUG_signal
6382 		g_print ("<< 'TRANSACTION_STATUS_CHANGED' from %s\n", __FUNCTION__);
6383 #endif
6384 	}
6385 	gda_connection_unlock ((GdaLockable*) cnc);
6386 }
6387 
6388 /*
6389  * Prepared statements handling
6390  */
6391 
6392 static void prepared_stmts_stmt_reset_cb (GdaStatement *gda_stmt, GdaConnection *cnc);
6393 
6394 static void
prepared_stmts_stmt_reset_cb(GdaStatement * gda_stmt,GdaConnection * cnc)6395 prepared_stmts_stmt_reset_cb (GdaStatement *gda_stmt, GdaConnection *cnc)
6396 {
6397 	gda_connection_lock ((GdaLockable*) cnc);
6398 	g_object_ref (gda_stmt);
6399 
6400 	g_signal_handlers_disconnect_by_func (gda_stmt, G_CALLBACK (prepared_stmts_stmt_reset_cb), cnc);
6401 	g_assert (cnc->priv->prepared_stmts);
6402 	g_hash_table_remove (cnc->priv->prepared_stmts, gda_stmt);
6403 
6404 	g_object_unref (gda_stmt);
6405 	gda_connection_unlock ((GdaLockable*) cnc);
6406 }
6407 
6408 static void
prepared_stms_foreach_func(GdaStatement * gda_stmt,G_GNUC_UNUSED GdaPStmt * prepared_stmt,GdaConnection * cnc)6409 prepared_stms_foreach_func (GdaStatement *gda_stmt, G_GNUC_UNUSED GdaPStmt *prepared_stmt, GdaConnection *cnc)
6410 {
6411 	g_object_ref (gda_stmt);
6412 	g_signal_handlers_disconnect_by_func (gda_stmt, G_CALLBACK (prepared_stmts_stmt_reset_cb), cnc);
6413 	g_object_unref (gda_stmt);
6414 }
6415 
6416 typedef struct {
6417 	GdaStatement   *statement;
6418 	GdaPStmt       *prepared_stmt;
6419 } PreparedStatementRef;
6420 
6421 PreparedStatementRef*
_gda_prepared_estatement_new(GdaStatement * stmt,GdaPStmt * pstmt)6422 _gda_prepared_estatement_new (GdaStatement *stmt, GdaPStmt *pstmt) {
6423 	PreparedStatementRef *nps = g_new0(PreparedStatementRef,1);
6424 	nps->statement = g_object_ref (stmt);
6425 	nps->prepared_stmt = g_object_ref (pstmt);
6426 	return nps;
6427 }
6428 
6429 void
_gda_prepared_estatement_free(PreparedStatementRef * ps)6430 _gda_prepared_estatement_free (PreparedStatementRef *ps) {
6431 	g_object_unref (ps->statement);
6432 	g_object_unref (ps->prepared_stmt);
6433 }
6434 
6435 /**
6436  * gda_connection_add_prepared_statement:
6437  * @cnc: a #GdaConnection object
6438  * @gda_stmt: a #GdaStatement object
6439  * @prepared_stmt: a prepared statement object (as a #GdaPStmt object, or more likely a descendant)
6440  *
6441  * Declares that @prepared_stmt is a prepared statement object associated to @gda_stmt within the connection
6442  * (meaning the connection increments the reference counter of @prepared_stmt).
6443  *
6444  * If @gda_stmt changes or is destroyed, the the association will be lost and the connection will lose the
6445  * reference it has on @prepared_stmt.
6446  */
6447 void
gda_connection_add_prepared_statement(GdaConnection * cnc,GdaStatement * gda_stmt,GdaPStmt * prepared_stmt)6448 gda_connection_add_prepared_statement (GdaConnection *cnc, GdaStatement *gda_stmt, GdaPStmt *prepared_stmt)
6449 {
6450 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
6451 	g_return_if_fail (GDA_IS_STATEMENT (gda_stmt));
6452 	g_return_if_fail (GDA_IS_PSTMT (prepared_stmt));
6453 	// Hold a reference until the end of the method
6454 	g_object_ref (prepared_stmt);
6455 	g_object_ref (gda_stmt);
6456 
6457 	gda_connection_lock ((GdaLockable*) cnc);
6458 
6459 	if (!cnc->priv->prepared_stmts)
6460 		cnc->priv->prepared_stmts = g_hash_table_new_full (g_direct_hash, g_direct_equal,
6461 								   NULL, _gda_prepared_estatement_free);
6462 	g_hash_table_remove (cnc->priv->prepared_stmts, gda_stmt);
6463 	PreparedStatementRef *ref = _gda_prepared_estatement_new (gda_stmt, prepared_stmt);
6464 	g_hash_table_insert (cnc->priv->prepared_stmts, gda_stmt, ref);
6465 
6466 	g_signal_connect (G_OBJECT (gda_stmt), "reset",
6467 			  G_CALLBACK (prepared_stmts_stmt_reset_cb), cnc);
6468 
6469 	gda_connection_unlock ((GdaLockable*) cnc);
6470 	g_object_unref (prepared_stmt);
6471 	g_object_unref (gda_stmt);
6472 }
6473 
6474 /**
6475  * gda_connection_get_prepared_statement:
6476  * @cnc: a #GdaConnection object
6477  * @gda_stmt: a #GdaStatement object
6478  *
6479  * Retrieves a pointer to an object representing a prepared statement for @gda_stmt within @cnc. The
6480  * association must have been done using gda_connection_add_prepared_statement().
6481  *
6482  * Returns: (transfer none): the prepared statement, or %NULL if no association exists
6483  */
6484 GdaPStmt *
gda_connection_get_prepared_statement(GdaConnection * cnc,GdaStatement * gda_stmt)6485 gda_connection_get_prepared_statement (GdaConnection *cnc, GdaStatement *gda_stmt)
6486 {
6487 	GdaPStmt *retval = NULL;
6488 
6489 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
6490 
6491 	gda_connection_lock ((GdaLockable*) cnc);
6492 	if (cnc->priv->prepared_stmts) {
6493 		PreparedStatementRef *ref = g_hash_table_lookup (cnc->priv->prepared_stmts, gda_stmt);
6494 		if (ref)
6495 			retval = ref->prepared_stmt;
6496 	}
6497 	gda_connection_unlock ((GdaLockable*) cnc);
6498 
6499 	return retval;
6500 }
6501 
6502 /**
6503  * gda_connection_del_prepared_statement:
6504  * @cnc: a #GdaConnection object
6505  * @gda_stmt: a #GdaStatement object
6506  *
6507  * Removes any prepared statement associated to @gda_stmt in @cnc: this undoes what
6508  * gda_connection_add_prepared_statement() does.
6509  */
6510 void
gda_connection_del_prepared_statement(GdaConnection * cnc,GdaStatement * gda_stmt)6511 gda_connection_del_prepared_statement (GdaConnection *cnc, GdaStatement *gda_stmt)
6512 {
6513 	g_return_if_fail (cnc != NULL);
6514 
6515 	gda_connection_lock ((GdaLockable*) cnc);
6516 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
6517 	g_object_ref (gda_stmt);
6518 	if (gda_connection_get_prepared_statement (cnc, gda_stmt))
6519 		prepared_stmts_stmt_reset_cb (gda_stmt, cnc);
6520 	g_object_unref (gda_stmt);
6521 	gda_connection_unlock ((GdaLockable*) cnc);
6522 }
6523 
6524 /*
6525  * Provider's specific connection data management
6526  */
6527 
6528 /**
6529  * gda_connection_internal_set_provider_data: (skip)
6530  * @cnc: a #GdaConnection object
6531  * @data: an opaque structure, known only to the provider for which @cnc is opened
6532  * @destroy_func: function to call when the connection closes and @data needs to be destroyed
6533  *
6534  * Note: calling this function more than once will not make it call @destroy_func on any previously
6535  * set opaque @data, you'll have to do it yourself.
6536  */
6537 void
gda_connection_internal_set_provider_data(GdaConnection * cnc,gpointer data,GDestroyNotify destroy_func)6538 gda_connection_internal_set_provider_data (GdaConnection *cnc, gpointer data, GDestroyNotify destroy_func)
6539 {
6540 
6541 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
6542 
6543 	gda_connection_lock ((GdaLockable*) cnc);
6544 	cnc->priv->provider_data = data;
6545 	cnc->priv->provider_data_destroy_func = destroy_func;
6546 	gda_connection_unlock ((GdaLockable*) cnc);
6547 }
6548 
6549 /**
6550  * gda_connection_internal_get_provider_data: (skip)
6551  * @cnc: a #GdaConnection object
6552  *
6553  * Get the opaque pointer previously set using gda_connection_internal_set_provider_data().
6554  * If it's not set, then add a connection event and returns %NULL
6555  *
6556  * Returns: (allow-none): the pointer to the opaque structure set using gda_connection_internal_set_provider_data(), or %NULL
6557  */
6558 gpointer
gda_connection_internal_get_provider_data(GdaConnection * cnc)6559 gda_connection_internal_get_provider_data (GdaConnection *cnc)
6560 {
6561 	return gda_connection_internal_get_provider_data_error (cnc, NULL);
6562 }
6563 
6564 /**
6565  * gda_connection_internal_get_provider_data_error: (skip)
6566  * @cnc: a #GdaConnection object
6567  * @error: (allow-none): a place to store errors, or %NULL
6568  *
6569  * Get the opaque pointer previously set using gda_connection_internal_set_provider_data().
6570  * If it's not set, then add a connection event and returns %NULL
6571  *
6572  * Returns: (allow-none): the pointer to the opaque structure set using gda_connection_internal_set_provider_data(), or %NULL
6573  *
6574  * Since: 5.0.2
6575  */
6576 gpointer
gda_connection_internal_get_provider_data_error(GdaConnection * cnc,GError ** error)6577 gda_connection_internal_get_provider_data_error (GdaConnection *cnc, GError **error)
6578 {
6579 	gpointer retval;
6580 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
6581 
6582 	retval = cnc->priv->provider_data;
6583 	if (!retval)
6584 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_CLOSED_ERROR,
6585                              _("Connection is closed"));
6586 	return retval;
6587 }
6588 
6589 /**
6590  * gda_connection_get_meta_store:
6591  * @cnc: a #GdaConnection object
6592  *
6593  * Get or initializes the #GdaMetaStore associated to @cnc
6594  *
6595  * Returns: (transfer none): a #GdaMetaStore object
6596  */
6597 GdaMetaStore *
gda_connection_get_meta_store(GdaConnection * cnc)6598 gda_connection_get_meta_store (GdaConnection *cnc)
6599 {
6600 	GdaMetaStore *store = NULL;
6601 
6602 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
6603 	g_mutex_lock (& cnc->priv->object_mutex);
6604 	if (!cnc->priv->meta_store) {
6605 		ThreadConnectionData *cdata = NULL;
6606 		if (cnc->priv->is_thread_wrapper) {
6607 			cdata = (ThreadConnectionData*) gda_connection_internal_get_provider_data (cnc);
6608 			if (cdata && cdata->sub_connection->priv->meta_store) {
6609 				cnc->priv->meta_store = g_object_ref (cdata->sub_connection->priv->meta_store);
6610 				store = cnc->priv->meta_store;
6611 			}
6612 		}
6613 		if (!store) {
6614 			cnc->priv->meta_store = gda_meta_store_new (NULL);
6615 			if (cnc->priv->is_thread_wrapper)
6616 				cdata->sub_connection->priv->meta_store =
6617 					g_object_ref (cnc->priv->meta_store);
6618 		}
6619 	}
6620 	store = cnc->priv->meta_store;
6621 	g_mutex_unlock (& cnc->priv->object_mutex);
6622 	return store;
6623 }
6624 
6625 /*
6626  * This method is useful only in a multi threading environment (it has no effect in a
6627  * single thread program).
6628  * Locks @cnc for the current thread. If the lock can't be obtained, then the current thread
6629  * will be blocked until it can acquire @cnc's lock.
6630  *
6631  * The cases when the connection can't be locked are:
6632  * <itemizedlist>
6633  *   <listitem><para>another thread is already using the connection</para></listitem>
6634  *   <listitem><para>the connection can only be used by a single thread (see the
6635  *     <link linkend="GdaConnection--thread-owner">thread-owner</link> property)</para></listitem>
6636  * </itemizedlist>
6637  *
6638  * To avoid the thread being blocked (possibly forever if the single thread which can use the
6639  * connection is not the current thead), then it is possible to use gda_connection_trylock() instead.
6640  */
6641 static void
gda_connection_lock(GdaLockable * lockable)6642 gda_connection_lock (GdaLockable *lockable)
6643 {
6644 	GdaConnection *cnc = (GdaConnection *) lockable;
6645 
6646 	g_rec_mutex_lock (& cnc->priv->rmutex);
6647 	if (cnc->priv->unique_possible_thread &&
6648 	    (cnc->priv->unique_possible_thread != g_thread_self ())) {
6649 		g_rec_mutex_unlock (& cnc->priv->rmutex);
6650 		g_mutex_lock (& cnc->priv->object_mutex);
6651 
6652 		while (1) {
6653 			if (cnc->priv->unique_possible_thread &&
6654 			    (cnc->priv->unique_possible_thread != g_thread_self ())) {
6655 #ifdef GDA_DEBUG_CNC_LOCK
6656 				g_print ("Wainting th %p, now %p (cond %p, mutex%p)\n", g_thread_self(),
6657 					 cnc->priv->unique_possible_thread, &cnc->priv->unique_possible_cond,
6658 					 cnc->priv->object_mutex);
6659 #endif
6660 				gint64 end_time;
6661 				end_time = g_get_monotonic_time () + 5 * G_TIME_SPAN_SECOND;
6662 				while (! g_cond_wait_until (& cnc->priv->unique_possible_cond,
6663 							    & cnc->priv->object_mutex, end_time));
6664 			}
6665 			else if (g_rec_mutex_trylock (& cnc->priv->rmutex)) {
6666 				g_mutex_unlock (& cnc->priv->object_mutex);
6667 				break;
6668 			}
6669 		}
6670 	}
6671 }
6672 
6673 /*
6674  * Tries to lock @cnc for the exclusive usage of the current thread, as gda_connection_lock(), except
6675  * that if it can't, then the calling thread is not locked by it simply returns FALSE.
6676  *
6677  * Returns: TRUE if successfully locked, or FALSE if lock could not be acquired
6678  */
6679 static gboolean
gda_connection_trylock(GdaLockable * lockable)6680 gda_connection_trylock (GdaLockable *lockable)
6681 {
6682 	gboolean retval;
6683 	GdaConnection *cnc = (GdaConnection *) lockable;
6684 
6685 	retval = g_rec_mutex_trylock (& cnc->priv->rmutex);
6686 	if (retval && cnc->priv->unique_possible_thread &&
6687 	    (cnc->priv->unique_possible_thread != g_thread_self ())) {
6688 		retval = FALSE;
6689 		g_rec_mutex_unlock (& cnc->priv->rmutex);
6690 	}
6691 	return retval;
6692 }
6693 
6694 /*
6695  * Unlocks @cnc's usage. Any other thread blocked (after having called gda_connection_lock()) gets
6696  * the opportunity to lock the connection.
6697  */
6698 static void
gda_connection_unlock(GdaLockable * lockable)6699 gda_connection_unlock  (GdaLockable *lockable)
6700 {
6701 	GdaConnection *cnc = (GdaConnection *) lockable;
6702 	g_rec_mutex_unlock (& cnc->priv->rmutex);
6703 }
6704 
6705 /*
6706  * REM: if @for_ident is %FALSE, then the keywords are converted to upper case
6707  */
6708 static gchar *
get_next_word(gchar * str,gboolean for_ident,gchar ** out_next)6709 get_next_word (gchar *str, gboolean for_ident, gchar **out_next)
6710 {
6711 	if (!str) {
6712 		*out_next = NULL;
6713 		return NULL;
6714 	}
6715 
6716 	gchar *start;
6717 	gchar *ptr;
6718 	gboolean inquotes = FALSE;
6719 	for (ptr = str; *ptr; ptr++) {
6720 		if ((*ptr == ' ') || (*ptr == '\n') || (*ptr == '\t') || (*ptr == '\r'))
6721 			continue;
6722 		break;
6723 	}
6724 	start = ptr;
6725 	/*g_print ("%s ([%s]) => [%s]", __FUNCTION__, str, start);*/
6726 	for (; *ptr; ptr++) {
6727 		if ((*ptr >= 'a') && (*ptr <= 'z')) {
6728 			if (! for_ident)
6729 				*ptr += 'A' - 'a';
6730 			continue;
6731 		}
6732 		else if ((*ptr >= 'A') && (*ptr <= 'Z'))
6733 			continue;
6734 		else if ((*ptr >= '0') && (*ptr <= '9'))
6735 			continue;
6736 		else if (*ptr == '_')
6737 			continue;
6738 		else if (for_ident) {
6739 			if ((*ptr == '"') || (*ptr == '\'') || (*ptr == '`')) {
6740 				if (inquotes) {
6741 					*ptr = '"';
6742 					inquotes = FALSE;
6743 					ptr++;
6744 					break;
6745 				}
6746 				else {
6747 					*ptr = '"';
6748 					inquotes = TRUE;
6749 				}
6750 				continue;
6751 			}
6752 		}
6753 		else if (inquotes)
6754 			continue;
6755 		break;
6756 	}
6757 	if (ptr != start) {
6758 		if (*ptr) {
6759 			*ptr = 0;
6760 			*out_next = ptr + 1;
6761 		}
6762 		else
6763 			*out_next = ptr;
6764 	}
6765 	else
6766 		*out_next = NULL;
6767 	/*g_print (" -- [%s]\n", *out_next);*/
6768 	return start;
6769 }
6770 
6771 
6772 /*
6773  * the contexts in returned list have:
6774  *  - the @table_name attribute as a static string
6775  *  - the @column_names[x] as a static string, not the @column_names array itself which has to be freed
6776  *
6777  * Returns: a new list of new #GdaMetaContext
6778  */
6779 static GSList *
meta_data_context_from_statement(GdaConnection * cnc,GdaStatement * stmt,GdaSet * params)6780 meta_data_context_from_statement (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params)
6781 {
6782 	gboolean ignore_create_drop = FALSE;
6783 	if (GDA_IS_VCONNECTION_DATA_MODEL (cnc))
6784 		/* meta data is updated when the virtual connection emits the
6785 		 * "vtable-created" or "vtable-dropped" signals
6786 		 */
6787 		ignore_create_drop = TRUE;
6788 
6789 	GdaMetaContext *context = NULL;
6790 	gchar *sql, *current, *next;
6791 	sql = gda_statement_to_sql (stmt, params, NULL);
6792 	if (!sql)
6793 		return NULL;
6794 
6795 	GSList *clist = NULL;
6796 	current = get_next_word (sql, FALSE, &next);
6797 	if (!current)
6798 		goto out;
6799 
6800 	if (!strcmp (current, "ALTER") ||
6801 	    (!ignore_create_drop && (!strcmp (current, "CREATE") || !strcmp (current, "DROP")))) {
6802 		const gchar *tname = NULL;
6803 		const gchar *opname;
6804 		opname = current;
6805 		current = get_next_word (next, FALSE, &next);
6806 		if (current && (!strcmp (current, "TABLE") || !strcmp (current, "VIEW"))) {
6807 			tname = get_next_word (next, TRUE, &next);
6808 			if ((! strcmp (opname, "CREATE") || !strcmp (opname, "DROP"))
6809 			    && !g_ascii_strcasecmp (tname, "IF")) {
6810 				gchar *tmpnext;
6811 				tmpnext = next;
6812 				if (! strcmp (opname, "CREATE")) {
6813 					const gchar *s1, *s2;
6814 					s1 = get_next_word (tmpnext, FALSE, &tmpnext);
6815 					s2 = get_next_word (tmpnext, FALSE, &tmpnext);
6816 					if (! strcmp (s1, "NOT") &&
6817 					    ! strcmp (s2, "EXISTS")) {
6818 						next = tmpnext;
6819 						tname = get_next_word (next, TRUE, &next);
6820 					}
6821 				}
6822 				else {
6823 					const gchar *s1;
6824 					s1 = get_next_word (tmpnext, FALSE, &tmpnext);
6825 					if (! strcmp (s1, "EXISTS")) {
6826 						next = tmpnext;
6827 						tname = get_next_word (next, TRUE, &next);
6828 					}
6829 				}
6830 			}
6831 		}
6832 		if (tname) {
6833 			gchar *tmp;
6834 			/*g_print ("CONTEXT: update for table [%s]\n", tname);*/
6835 			context = g_new0 (GdaMetaContext, 1);
6836 			context->table_name = "_tables";
6837 			context->size = 1;
6838 			context->column_names = g_new0 (gchar *, 1);
6839 			context->column_names[0] = "table_name";
6840 			context->column_values = g_new0 (GValue *, 1);
6841 			tmp = gda_sql_identifier_quote (tname, cnc, cnc->priv->provider_obj,
6842 							TRUE,
6843 							cnc->priv->options & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE);
6844 			g_value_take_string ((context->column_values[0] = gda_value_new (G_TYPE_STRING)),
6845 					     tmp);
6846 			clist = g_slist_prepend (clist, context);
6847 
6848 			/* seek RENAME TO */
6849 			current = get_next_word (next, FALSE, &next);
6850 			if (!current || strcmp (current, "RENAME"))
6851 				goto out;
6852 			current = get_next_word (next, FALSE, &next);
6853 			if (!current || strcmp (current, "TO"))
6854 				goto out;
6855 			tname = get_next_word (next, TRUE, &next);
6856 			if (tname) {
6857 				gchar *tmp;
6858 				/*g_print ("CONTEXT: update for table [%s]\n", tname);*/
6859 				context = g_new0 (GdaMetaContext, 1);
6860 				context->table_name = "_tables";
6861 				context->size = 1;
6862 				context->column_names = g_new0 (gchar *, 1);
6863 				context->column_names[0] = "table_name";
6864 				context->column_values = g_new0 (GValue *, 1);
6865 				tmp = gda_sql_identifier_quote (tname, cnc, cnc->priv->provider_obj,
6866 								TRUE,
6867 								cnc->priv->options & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE);
6868 				g_value_take_string ((context->column_values[0] = gda_value_new (G_TYPE_STRING)),
6869 						     tmp);
6870 				clist = g_slist_prepend (clist, context);
6871 			}
6872 		}
6873 	}
6874 
6875  out:
6876 	g_free (sql);
6877 	return clist;
6878 }
6879 
6880 /*
6881  * update_meta_store_after_statement_exec
6882  *
6883  * Updates the meta store associated to @cnc if it exists and if @cnc has the
6884  * GDA_CONNECTION_OPTIONS_AUTO_META_DATA flag.
6885  */
6886 static void
update_meta_store_after_statement_exec(GdaConnection * cnc,GdaStatement * stmt,GdaSet * params)6887 update_meta_store_after_statement_exec (GdaConnection *cnc, GdaStatement *stmt, GdaSet *params)
6888 {
6889 	if (! cnc->priv->meta_store ||
6890 	    ! (cnc->priv->options & GDA_CONNECTION_OPTIONS_AUTO_META_DATA))
6891 		return;
6892 
6893 	GdaSqlStatementType type;
6894 	type = gda_statement_get_statement_type (stmt);
6895 	if (type == GDA_SQL_STATEMENT_BEGIN) {
6896 		/* initialize cnc->priv->trans_meta_context if meta store's connection is not @cnc */
6897 		GdaConnection *mscnc;
6898 		mscnc = gda_meta_store_get_internal_connection (cnc->priv->meta_store);
6899 		if (cnc != mscnc) {
6900 			g_assert (! cnc->priv->trans_meta_context);
6901 			cnc->priv->trans_meta_context = g_array_new (FALSE, FALSE, sizeof (GdaMetaContext*));
6902 		}
6903 		return;
6904 	}
6905 	else if (type == GDA_SQL_STATEMENT_ROLLBACK) {
6906 		/* re-run all the meta store updates started since the BEGIN */
6907 		GdaConnection *mscnc;
6908 		mscnc = gda_meta_store_get_internal_connection (cnc->priv->meta_store);
6909 		if (cnc != mscnc) {
6910 			gsize i;
6911 			g_assert (cnc->priv->trans_meta_context);
6912 			for (i = 0; i < cnc->priv->trans_meta_context->len; i++) {
6913 				GdaMetaContext *context;
6914 				GError *lerror = NULL;
6915 				context = g_array_index (cnc->priv->trans_meta_context, GdaMetaContext*, i);
6916 				if (! gda_connection_update_meta_store (cnc, context, &lerror))
6917 					add_connection_event_from_error (cnc, &lerror);
6918 				auto_update_meta_context_free (context);
6919 			}
6920 			g_array_free (cnc->priv->trans_meta_context, TRUE);
6921 			cnc->priv->trans_meta_context = NULL;
6922 		}
6923 		return;
6924 	}
6925 	else if (type == GDA_SQL_STATEMENT_COMMIT) {
6926 		/* get rid of the meta store updates */
6927 		GdaConnection *mscnc;
6928 		mscnc = gda_meta_store_get_internal_connection (cnc->priv->meta_store);
6929 		if (cnc != mscnc) {
6930 			gsize i;
6931 			g_assert (cnc->priv->trans_meta_context);
6932 			for (i = 0; i < cnc->priv->trans_meta_context->len; i++) {
6933 				GdaMetaContext *context;
6934 				context = g_array_index (cnc->priv->trans_meta_context, GdaMetaContext*, i);
6935 				auto_update_meta_context_free (context);
6936 			}
6937 			g_array_free (cnc->priv->trans_meta_context, TRUE);
6938 			cnc->priv->trans_meta_context = NULL;
6939 		}
6940 		return;
6941 	}
6942 	else if (type != GDA_SQL_STATEMENT_UNKNOWN)
6943 		return;
6944 
6945 	GSList *clist, *list;
6946 	clist = meta_data_context_from_statement (cnc, stmt, params);
6947 	for (list = clist; list; list = list->next) {
6948 		GdaMetaContext *context;
6949 		context = (GdaMetaContext*) list->data;
6950 		if (context) {
6951 			GError *lerror = NULL;
6952 			if (! gda_connection_update_meta_store (cnc, context, &lerror))
6953 				add_connection_event_from_error (cnc, &lerror);
6954 
6955 			if (cnc->priv->trans_meta_context)
6956 				g_array_prepend_val (cnc->priv->trans_meta_context, context);
6957 			else
6958 				auto_update_meta_context_free (context);
6959 		}
6960 	}
6961 	g_slist_free (clist);
6962 }
6963 
6964 void
_gda_connection_signal_meta_table_update(GdaConnection * cnc,const gchar * table_name)6965 _gda_connection_signal_meta_table_update (GdaConnection *cnc, const gchar *table_name)
6966 {
6967 	if (! cnc->priv->meta_store ||
6968 	    ! (cnc->priv->options & GDA_CONNECTION_OPTIONS_AUTO_META_DATA))
6969 		return;
6970 
6971 	GdaMetaContext *context;
6972 	gchar **split;
6973 	gchar *tmp;
6974 	/*g_print ("CONTEXT: update for table [%s]\n", table_name);*/
6975 	split = gda_sql_identifier_split (table_name);
6976 	if (!split)
6977 		return;
6978 	if (!split [0]) {
6979 		g_strfreev (split);
6980 		return;
6981 	}
6982 
6983 	context = g_new0 (GdaMetaContext, 1);
6984 	context->table_name = "_tables";
6985 
6986 	if (split [1]) {
6987 		context->size = 2;
6988 		context->column_names = g_new0 (gchar *, context->size);
6989 		context->column_names[0] = "table_schema";
6990 		context->column_names[1] = "table_name";
6991 		context->column_values = g_new0 (GValue *, context->size);
6992 		tmp = gda_sql_identifier_quote (split[0], cnc, cnc->priv->provider_obj,
6993 						TRUE,
6994 						cnc->priv->options & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE);
6995 		g_value_take_string ((context->column_values[0] = gda_value_new (G_TYPE_STRING)),
6996 				     tmp);
6997 		tmp = gda_sql_identifier_quote (split[1], cnc, cnc->priv->provider_obj,
6998 						TRUE,
6999 						cnc->priv->options & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE);
7000 		g_value_take_string ((context->column_values[1] = gda_value_new (G_TYPE_STRING)),
7001 				     tmp);
7002 	}
7003 	else {
7004 		context->size = 1;
7005 		context->column_names = g_new0 (gchar *, context->size);
7006 		context->column_names[0] = "table_name";
7007 		context->column_values = g_new0 (GValue *, context->size);
7008 		tmp = gda_sql_identifier_quote (split[0], cnc, cnc->priv->provider_obj,
7009 						TRUE,
7010 						cnc->priv->options & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE);
7011 		g_value_take_string ((context->column_values[0] = gda_value_new (G_TYPE_STRING)),
7012 				     tmp);
7013 	}
7014 
7015 	GError *lerror = NULL;
7016 	if (! gda_connection_update_meta_store (cnc, context, &lerror))
7017 		add_connection_event_from_error (cnc, &lerror);
7018 
7019 	if (cnc->priv->trans_meta_context)
7020 		g_array_prepend_val (cnc->priv->trans_meta_context, context);
7021 	else
7022 		auto_update_meta_context_free (context);
7023 
7024 	g_strfreev (split);
7025 }
7026 
7027 /*
7028  * Free @context which must have been created by meta_data_context_from_statement()
7029  */
7030 static void
auto_update_meta_context_free(GdaMetaContext * context)7031 auto_update_meta_context_free (GdaMetaContext *context)
7032 {
7033 	gint i;
7034 	context->table_name = NULL; /* don't free */
7035 	g_free (context->column_names); /* don't free the strings in the array */
7036 	for (i = 0; i < context->size; i++)
7037 		gda_value_free (context->column_values[i]);
7038 	g_free (context->column_values);
7039 	g_free (context);
7040 }
7041 
7042 
7043 /*
7044  * _gda_connection_get_table_virtual_name
7045  * @table_name: a non %NULL string
7046  *
7047  * Returns: a new string.
7048  */
7049 gchar *
_gda_connection_compute_table_virtual_name(GdaConnection * cnc,const gchar * table_name)7050 _gda_connection_compute_table_virtual_name (GdaConnection *cnc, const gchar *table_name)
7051 {
7052 	gchar **array;
7053 
7054 	g_assert (table_name && *table_name);
7055 	array = gda_sql_identifier_split (table_name);
7056 	if (array) {
7057 		GString *string = NULL;
7058 		gint i;
7059 		gchar *tmp;
7060 		for (i = 0; ; i++) {
7061 			if (array [i]) {
7062 				tmp = gda_sql_identifier_quote (array[i], cnc, NULL, TRUE, FALSE);
7063 				if (string) {
7064 					g_string_append_c (string, '.');
7065 					g_string_append (string, tmp);
7066 				}
7067 				else
7068 					string = g_string_new (tmp);
7069 			}
7070 			else
7071 				break;
7072 		}
7073 		g_strfreev (array);
7074 		return g_string_free (string, FALSE);
7075 	}
7076 	else {
7077 		/*
7078 		** If X is a character that can be used in an identifier then
7079 		** IdChar(X) will be true.  Otherwise it is false.
7080 		**
7081 		** For ASCII, any character with the high-order bit set is
7082 		** allowed in an identifier.  For 7-bit characters,
7083 		** sqlite3IsIdChar[X] must be 1.
7084 		*/
7085 		static const char AsciiIdChar[] = {
7086 			/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
7087 			0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 2x */
7088 			1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,  /* 3x */
7089 			0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 4x */
7090 			1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,  /* 5x */
7091 			0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 6x */
7092 			1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,  /* 7x */
7093 		};
7094 #define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && AsciiIdChar[c-0x20]))
7095 		gchar *tmp, *ptr, c;
7096 		tmp = g_strdup (table_name);
7097 
7098 		/* first try removing some double quotes only */
7099 		for (ptr = tmp; *ptr; ptr++) {
7100 			if (! IdChar(*ptr)) {
7101 				if ((*ptr == '"') && (ptr[1] == '"')) {
7102 					gchar *ptr2;
7103 					for (ptr2 = ptr; ptr2[2]; ptr2++)
7104 						*ptr2 = ptr2[2];
7105 					*ptr2 = 0;
7106 				}
7107 				else if ((*ptr != '"') && (*ptr != '.'))
7108 					*ptr = '_';
7109 			}
7110 		}
7111 
7112 		ptr = NULL;
7113 		if (strcmp (tmp, table_name))
7114 			ptr = _gda_connection_compute_table_virtual_name (cnc, tmp);
7115 
7116 		/* if it dow not work, replace all non IdChar character with '_' */
7117 		if (!ptr) {
7118 			for (ptr = tmp; *ptr; ptr++) {
7119 				if (! IdChar(*ptr))
7120 					*ptr = '_';
7121 			}
7122 			ptr = _gda_connection_compute_table_virtual_name (cnc, tmp);
7123 		}
7124 		g_free (tmp);
7125 		return ptr;
7126 	}
7127 }
7128 
7129 /*
7130  * Free connection's specific data
7131  */
7132 static gpointer
sub_thread_unref_connection(GdaConnection * cnc,G_GNUC_UNUSED GError ** error)7133 sub_thread_unref_connection (GdaConnection *cnc, G_GNUC_UNUSED GError **error)
7134 {
7135 	/* WARNING: function executed in sub thread! */
7136 	g_object_unref (cnc);
7137 #ifdef GDA_DEBUG_NO
7138 	g_print ("/%s()\n", __FUNCTION__);
7139 #endif
7140 	return NULL;
7141 }
7142 
7143 void
_gda_thread_connection_data_free(ThreadConnectionData * cdata)7144 _gda_thread_connection_data_free (ThreadConnectionData *cdata)
7145 {
7146 	if (!cdata)
7147 		return;
7148 
7149 	/* disconnect signals handlers */
7150 	gsize i;
7151 	for (i = 0; i < cdata->handlers_ids->len; i++) {
7152 		gulong hid = g_array_index (cdata->handlers_ids, gulong, i);
7153 		gda_thread_wrapper_disconnect (cdata->wrapper, hid);
7154 	}
7155 
7156 	/* unref cdata->sub_connection in sub thread */
7157 	guint jid;
7158 	jid = gda_thread_wrapper_execute (cdata->wrapper,
7159 					  (GdaThreadWrapperFunc) sub_thread_unref_connection,
7160 					  cdata->sub_connection, NULL, NULL);
7161 	gda_thread_wrapper_fetch_result (cdata->wrapper, TRUE, jid, NULL);
7162 	g_object_unref (cdata->wrapper);
7163 
7164 	/* free async data */
7165 	if (cdata->async_tasks) {
7166 		g_slist_foreach (cdata->async_tasks, (GFunc) _ThreadConnectionAsyncTask_free, NULL);
7167 		g_slist_free (cdata->async_tasks);
7168 	}
7169 
7170 	g_object_unref (cdata->cnc_provider);
7171 
7172 	g_free (cdata);
7173 }
7174 
7175 void
_gda_thread_connection_set_data(GdaConnection * cnc,ThreadConnectionData * cdata)7176 _gda_thread_connection_set_data (GdaConnection *cnc, ThreadConnectionData *cdata)
7177 {
7178 	g_rec_mutex_lock (& cnc->priv->rmutex);
7179 	if (cnc->priv->th_data)
7180 		_gda_thread_connection_data_free (cnc->priv->th_data);
7181 	cnc->priv->th_data = cdata;
7182 	g_rec_mutex_unlock (& cnc->priv->rmutex);
7183 }
7184 
7185 ThreadConnectionData *
_gda_thread_connection_get_data(GdaConnection * cnc)7186 _gda_thread_connection_get_data (GdaConnection *cnc)
7187 {
7188 	return cnc->priv->th_data;
7189 }
7190