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 (®istering);
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 (®istering);
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: "[<username>[:<password>]@]<DSN>"
1211 * (if <username> and/or <password> are provided, and @auth_string is %NULL, then these username
1212 * and passwords will be used). Note that if provided, <username> and <password>
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 <key>=<value> 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 * "[<provider>://][<username>[:<password>]@]<connection_params>"
1384 * (if <username> and/or <password> are provided, and @auth_string is %NULL, then these username
1385 * and passwords will be used, and if <provider> is provided and @provider_name is %NULL then this
1386 * provider will be used). Note that if provided, <username>, <password> and <provider>
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 "<provider_name>://<real cnc string>" 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 <table> (<column_name> [,...]) VALUES (<column_name> = <new_value> [,...]).
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 (>= 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 <table> (<column_name> [,...]) VALUES (<column_name> = <new_value> [,...]).
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 <table> SET <column_name> = <new_value> [,...] WHERE <condition_column_name> = <condition_value>.
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 (>= 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 <table> SET <column_name> = <new_value> [,...] WHERE <condition_column_name> = <condition_value>.
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 <table> WHERE <condition_column_name> = <condition_value>.
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 "+<column number>"
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 (>=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