1 /*
2 * Copyright (C) 2009 - 2013 Vivien Malerba <malerba@gnome-db.org>
3 * Copyright (C) 2010 David King <davidk@openismus.com>
4 * Copyright (C) 2010 Murray Cumming <murrayc@murrayc.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21 #include <string.h>
22 #include <glib/gi18n-lib.h>
23 #include "../tool-utils.h"
24 #include "browser-connection.h"
25 #include <libgda/thread-wrapper/gda-thread-wrapper.h>
26 #include "support.h"
27 #include "marshal.h"
28 #include <sql-parser/gda-sql-parser.h>
29 #include <libgda/gda-sql-builder.h>
30 #include <libgda-ui/gdaui-enums.h>
31 #include "../config-info.h"
32 #include "browser-virtual-connection.h"
33 #include <sqlite/virtual/gda-virtual-connection.h>
34 #include <libgda/gda-debug-macros.h>
35 #include "browser-connection-priv.h"
36
37 #define CHECK_RESULTS_SHORT_TIMER 200
38 #define CHECK_RESULTS_LONG_TIMER 2
39
40 typedef struct {
41 GObject *result;
42 GError *error;
43 GdaSet *last_inserted_row;
44 } StatementResult;
45
46 static void
statement_result_free(StatementResult * res)47 statement_result_free (StatementResult *res)
48 {
49 if (res->result)
50 g_object_unref (res->result);
51 if (res->last_inserted_row)
52 g_object_unref (res->last_inserted_row);
53 g_clear_error (&(res->error));
54 g_free (res);
55 }
56
57 /* signals */
58 enum {
59 BUSY,
60 META_CHANGED,
61 FAV_CHANGED,
62 TRANSACTION_STATUS_CHANGED,
63 TABLE_COLUMN_PREF_CHANGED,
64 LAST_SIGNAL
65 };
66
67 gint browser_connection_signals [LAST_SIGNAL] = { 0, 0, 0, 0, 0 };
68
69 /* wrapper jobs handling */
70 static gboolean check_for_wrapper_result (BrowserConnection *bcnc);
71
72 typedef enum {
73 JOB_TYPE_META_STORE_UPDATE,
74 JOB_TYPE_META_STRUCT_SYNC,
75 JOB_TYPE_STATEMENT_EXECUTE,
76 JOB_TYPE_CALLBACK
77 } JobType;
78
79 typedef struct {
80 guint job_id;
81 JobType job_type;
82 gchar *reason;
83
84 /* the following may be %NULL for stmt execution and meta store updates */
85 BrowserConnectionJobCallback callback;
86 gpointer cb_data;
87 } WrapperJob;
88
89 static void
wrapper_job_free(WrapperJob * wj)90 wrapper_job_free (WrapperJob *wj)
91 {
92 g_free (wj->reason);
93 g_free (wj);
94 }
95
96 #ifdef GDA_DEBUG_MUTEX
97 static void
my_lock(GMutex * mutex,gint where)98 my_lock (GMutex *mutex, gint where)
99 {
100 GTimer *timer;
101 g_print ("wait to lock %p (th %p)@line %d\n", mutex, g_thread_self(), where);
102 timer = g_timer_new ();
103 g_mutex_lock (mutex);
104 g_timer_stop (timer);
105
106 if (g_timer_elapsed (timer, NULL) > 2.0)
107 g_print ("WARN: locking %p (th %p)@line %d: %02f\n", mutex, g_thread_self(), where,
108 g_timer_elapsed (timer, NULL));
109 g_print ("tmp LOC %p (th %p)@line %d took %02f\n", mutex, g_thread_self(), where,
110 g_timer_elapsed (timer, NULL));
111 g_timer_destroy (timer);
112 }
113 static void
my_unlock(GMutex * mutex,gint where)114 my_unlock (GMutex *mutex, gint where)
115 {
116 g_mutex_unlock (mutex);
117 g_print ("tmp UNL %p (th %p)@line %d\n", mutex, g_thread_self(), where);
118 }
119
120 #define MUTEX_LOCK(bcnc) g_mutex_lock (&((bcnc)->priv->mstruct_mutex))
121 #define MUTEX_UNLOCK(bcnc) g_mutex_unlock (&((bcnc)->priv->mstruct_mutex))
122 #else /* GDA_DEBUG_MUTEX */
123 #define MUTEX_LOCK(bcnc) g_mutex_lock (&((bcnc)->priv->mstruct_mutex))
124 #define MUTEX_UNLOCK(bcnc) g_mutex_unlock (&((bcnc)->priv->mstruct_mutex))
125 #endif /* GDA_DEBUG_MUTEX */
126
127 /*
128 * Returns: %TRUE if current timer should be removed
129 */
130 static gboolean
setup_results_timer(BrowserConnection * bcnc)131 setup_results_timer (BrowserConnection *bcnc)
132 {
133 gboolean short_timer = TRUE;
134
135 if (bcnc->priv->ioc_watch_id != 0)
136 return FALSE; /* nothing to do, we use notifications */
137
138 bcnc->priv->nb_no_job_waits ++;
139 if (bcnc->priv->nb_no_job_waits > 100)
140 short_timer = FALSE;
141
142 if ((bcnc->priv->wrapper_results_timer > 0) &&
143 (bcnc->priv->long_timer != short_timer))
144 return FALSE; /* nothing to do, timer already correctlyset up */
145
146 /* switch to a short/long timer to check for results */
147 if (bcnc->priv->long_timer == short_timer)
148 g_source_remove (bcnc->priv->wrapper_results_timer);
149
150 bcnc->priv->long_timer = !short_timer;
151 bcnc->priv->wrapper_results_timer = g_timeout_add (short_timer ? CHECK_RESULTS_SHORT_TIMER : CHECK_RESULTS_LONG_TIMER,
152 (GSourceFunc) check_for_wrapper_result,
153 bcnc);
154 bcnc->priv->nb_no_job_waits = 0;
155 return TRUE;
156 }
157
158 /*
159 * Pushes a job which has been asked to be exected in a sub thread using gda_thread_wrapper_execute()
160 */
161 static void
push_wrapper_job(BrowserConnection * bcnc,guint job_id,JobType job_type,const gchar * reason,BrowserConnectionJobCallback callback,gpointer cb_data)162 push_wrapper_job (BrowserConnection *bcnc, guint job_id, JobType job_type, const gchar *reason,
163 BrowserConnectionJobCallback callback, gpointer cb_data)
164 {
165 /* handle timers if necessary */
166 setup_results_timer (bcnc);
167
168 /* add WrapperJob structure */
169 WrapperJob *wj;
170 wj = g_new0 (WrapperJob, 1);
171 wj->job_id = job_id;
172 wj->job_type = job_type;
173 if (reason)
174 wj->reason = g_strdup (reason);
175 wj->callback = callback;
176 wj->cb_data = cb_data;
177
178 bcnc->priv->wrapper_jobs = g_slist_append (bcnc->priv->wrapper_jobs, wj);
179
180 if (! bcnc->priv->wrapper_jobs->next)
181 g_signal_emit (bcnc, browser_connection_signals [BUSY], 0, TRUE, wj->reason);
182 }
183
184 static void
pop_wrapper_job(BrowserConnection * bcnc,WrapperJob * wj)185 pop_wrapper_job (BrowserConnection *bcnc, WrapperJob *wj)
186 {
187 bcnc->priv->wrapper_jobs = g_slist_remove (bcnc->priv->wrapper_jobs, wj);
188 wrapper_job_free (wj);
189 g_signal_emit (bcnc, browser_connection_signals [BUSY], 0, FALSE, NULL);
190 }
191
192
193 /*
194 * Main static functions
195 */
196 static void browser_connection_class_init (BrowserConnectionClass *klass);
197 static void browser_connection_init (BrowserConnection *bcnc);
198 static void browser_connection_dispose (GObject *object);
199 static void browser_connection_set_property (GObject *object,
200 guint param_id,
201 const GValue *value,
202 GParamSpec *pspec);
203 static void browser_connection_get_property (GObject *object,
204 guint param_id,
205 GValue *value,
206 GParamSpec *pspec);
207 /* get a pointer to the parents to be able to call their destructor */
208 static GObjectClass *parent_class = NULL;
209
210 /* properties */
211 enum {
212 PROP_0,
213 PROP_GDA_CNC
214 };
215
216 GType
browser_connection_get_type(void)217 browser_connection_get_type (void)
218 {
219 static GType type = 0;
220
221 if (G_UNLIKELY (type == 0)) {
222 static GMutex registering;
223 static const GTypeInfo info = {
224 sizeof (BrowserConnectionClass),
225 (GBaseInitFunc) NULL,
226 (GBaseFinalizeFunc) NULL,
227 (GClassInitFunc) browser_connection_class_init,
228 NULL,
229 NULL,
230 sizeof (BrowserConnection),
231 0,
232 (GInstanceInitFunc) browser_connection_init,
233 0
234 };
235
236
237 g_mutex_lock (®istering);
238 if (type == 0)
239 type = g_type_register_static (G_TYPE_OBJECT, "BrowserConnection", &info, 0);
240 g_mutex_unlock (®istering);
241 }
242 return type;
243 }
244
245 static void
browser_connection_class_init(BrowserConnectionClass * klass)246 browser_connection_class_init (BrowserConnectionClass *klass)
247 {
248 GObjectClass *object_class = G_OBJECT_CLASS (klass);
249 parent_class = g_type_class_peek_parent (klass);
250
251 browser_connection_signals [BUSY] =
252 g_signal_new ("busy",
253 G_TYPE_FROM_CLASS (object_class),
254 G_SIGNAL_RUN_FIRST,
255 G_STRUCT_OFFSET (BrowserConnectionClass, busy),
256 NULL, NULL,
257 _marshal_VOID__BOOLEAN_STRING, G_TYPE_NONE,
258 2, G_TYPE_BOOLEAN, G_TYPE_STRING);
259 browser_connection_signals [META_CHANGED] =
260 g_signal_new ("meta-changed",
261 G_TYPE_FROM_CLASS (object_class),
262 G_SIGNAL_RUN_FIRST,
263 G_STRUCT_OFFSET (BrowserConnectionClass, meta_changed),
264 NULL, NULL,
265 g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE,
266 1, GDA_TYPE_META_STRUCT);
267 browser_connection_signals [FAV_CHANGED] =
268 g_signal_new ("favorites-changed",
269 G_TYPE_FROM_CLASS (object_class),
270 G_SIGNAL_RUN_FIRST,
271 G_STRUCT_OFFSET (BrowserConnectionClass, favorites_changed),
272 NULL, NULL,
273 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE,
274 0);
275 browser_connection_signals [TRANSACTION_STATUS_CHANGED] =
276 g_signal_new ("transaction-status-changed",
277 G_TYPE_FROM_CLASS (object_class),
278 G_SIGNAL_RUN_FIRST,
279 G_STRUCT_OFFSET (BrowserConnectionClass, transaction_status_changed),
280 NULL, NULL,
281 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE,
282 0);
283 browser_connection_signals [TABLE_COLUMN_PREF_CHANGED] =
284 g_signal_new ("table-column-pref-changed",
285 G_TYPE_FROM_CLASS (object_class),
286 G_SIGNAL_RUN_FIRST,
287 G_STRUCT_OFFSET (BrowserConnectionClass, table_column_pref_changed),
288 NULL, NULL,
289 _marshal_VOID__POINTER_POINTER_STRING_STRING, G_TYPE_NONE,
290 4, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING);
291
292 klass->busy = browser_connection_set_busy_state;
293 klass->meta_changed = NULL;
294 klass->favorites_changed = NULL;
295 klass->transaction_status_changed = NULL;
296 klass->table_column_pref_changed = NULL;
297
298 /* Properties */
299 object_class->set_property = browser_connection_set_property;
300 object_class->get_property = browser_connection_get_property;
301 g_object_class_install_property (object_class, PROP_GDA_CNC,
302 g_param_spec_object ("gda-connection", NULL, "Connection to use",
303 GDA_TYPE_CONNECTION,
304 G_PARAM_WRITABLE |
305 G_PARAM_CONSTRUCT_ONLY));
306
307 object_class->dispose = browser_connection_dispose;
308 }
309
310 static gboolean
wrapper_ioc_cb(GIOChannel * source,GIOCondition condition,BrowserConnection * bcnc)311 wrapper_ioc_cb (GIOChannel *source, GIOCondition condition, BrowserConnection *bcnc)
312 {
313 GIOStatus status;
314 gsize nread;
315 GdaThreadNotification notif;
316
317 g_assert (source == bcnc->priv->ioc);
318 //#define DEBUG_POLLING_SWITCH
319 #ifdef DEBUG_POLLING_SWITCH
320 static guint c = 0;
321 c++;
322 if (c == 4)
323 goto onerror;
324 #endif
325 if (condition & G_IO_IN) {
326 status = g_io_channel_read_chars (bcnc->priv->ioc, (gchar*) ¬if, sizeof (notif),
327 &nread, NULL);
328 if ((status != G_IO_STATUS_NORMAL) || (nread != sizeof (notif)))
329 goto onerror;
330
331 switch (notif.type) {
332 case GDA_THREAD_NOTIFICATION_JOB:
333 check_for_wrapper_result (bcnc);
334 break;
335 case GDA_THREAD_NOTIFICATION_SIGNAL:
336 gda_thread_wrapper_iterate (bcnc->priv->wrapper, FALSE);
337 break;
338 default:
339 /* an error occurred somewhere */
340 goto onerror;
341 }
342 }
343 if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
344 goto onerror;
345
346 return TRUE; /* keep callback */
347
348 onerror:
349 #ifdef GDA_DEBUG
350 g_print ("Switching to polling instead of notifications...\n");
351 #endif
352 g_source_remove (bcnc->priv->ioc_watch_id);
353 bcnc->priv->ioc_watch_id = 0;
354 g_io_channel_shutdown (bcnc->priv->ioc, FALSE, NULL);
355 g_io_channel_unref (bcnc->priv->ioc);
356 bcnc->priv->ioc = NULL;
357
358 setup_results_timer (bcnc);
359 return FALSE; /* remove callback */
360 }
361
362 static void
browser_connection_init(BrowserConnection * bcnc)363 browser_connection_init (BrowserConnection *bcnc)
364 {
365 static guint index = 1;
366 bcnc->priv = g_new0 (BrowserConnectionPrivate, 1);
367 bcnc->priv->wrapper = gda_thread_wrapper_new ();
368 bcnc->priv->ioc = gda_thread_wrapper_get_io_channel (bcnc->priv->wrapper);
369 if (bcnc->priv->ioc) {
370 g_io_channel_ref (bcnc->priv->ioc);
371 bcnc->priv->ioc_watch_id = g_io_add_watch (bcnc->priv->ioc,
372 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
373 (GIOFunc) wrapper_ioc_cb, bcnc);
374 }
375 else
376 bcnc->priv->ioc_watch_id = 0;
377 bcnc->priv->wrapper_jobs = NULL;
378 bcnc->priv->wrapper_results_timer = 0;
379 bcnc->priv->long_timer = FALSE;
380 bcnc->priv->nb_no_job_waits = 0;
381 bcnc->priv->executed_statements = NULL;
382
383 bcnc->priv->name = g_strdup_printf (_("c%u"), index++);
384 bcnc->priv->cnc = NULL;
385 bcnc->priv->parser = NULL;
386 bcnc->priv->variables = NULL;
387 memset (&(bcnc->priv->dsn_info), 0, sizeof (GdaDsnInfo));
388 g_mutex_init (&bcnc->priv->mstruct_mutex);
389 bcnc->priv->p_mstruct_list = NULL;
390 bcnc->priv->c_mstruct = NULL;
391 bcnc->priv->mstruct = NULL;
392
393 bcnc->priv->meta_store_signal = 0;
394
395 bcnc->priv->bfav = NULL;
396
397 bcnc->priv->store_cnc = NULL;
398
399 bcnc->priv->variables = NULL;
400 /*g_print ("Created BrowserConnection %p\n", bcnc);*/
401 }
402
403 static void
transaction_status_changed_cb(G_GNUC_UNUSED GdaThreadWrapper * wrapper,G_GNUC_UNUSED gpointer instance,G_GNUC_UNUSED const gchar * signame,G_GNUC_UNUSED gint n_param_values,G_GNUC_UNUSED const GValue * param_values,G_GNUC_UNUSED gpointer gda_reserved,BrowserConnection * bcnc)404 transaction_status_changed_cb (G_GNUC_UNUSED GdaThreadWrapper *wrapper, G_GNUC_UNUSED gpointer instance,
405 G_GNUC_UNUSED const gchar *signame, G_GNUC_UNUSED gint n_param_values,
406 G_GNUC_UNUSED const GValue *param_values, G_GNUC_UNUSED gpointer gda_reserved,
407 BrowserConnection *bcnc)
408 {
409 g_signal_emit (bcnc, browser_connection_signals [TRANSACTION_STATUS_CHANGED], 0);
410 }
411
412 /* executed in sub @bcnc->priv->wrapper's thread */
413 static gpointer
wrapper_meta_store_update(BrowserConnection * bcnc,GError ** error)414 wrapper_meta_store_update (BrowserConnection *bcnc, GError **error)
415 {
416 gboolean retval;
417 GdaMetaContext context = {"_tables", 0, NULL, NULL};
418 retval = gda_connection_update_meta_store (bcnc->priv->cnc, &context, error);
419
420 return GINT_TO_POINTER (retval ? 2 : 1);
421 }
422
423 /* executed in sub @bcnc->priv->wrapper's thread */
424 static gpointer
wrapper_meta_struct_sync(BrowserConnection * bcnc,GError ** error)425 wrapper_meta_struct_sync (BrowserConnection *bcnc, GError **error)
426 {
427 gboolean retval = TRUE;
428 GdaMetaStruct *mstruct;
429
430 MUTEX_LOCK (bcnc);
431 g_assert (bcnc->priv->p_mstruct_list);
432 mstruct = (GdaMetaStruct *) bcnc->priv->p_mstruct_list->data;
433 /*g_print ("%s() for GdaMetaStruct %p\n", __FUNCTION__, mstruct);*/
434 bcnc->priv->p_mstruct_list = g_slist_delete_link (bcnc->priv->p_mstruct_list,
435 bcnc->priv->p_mstruct_list);
436 if (bcnc->priv->p_mstruct_list) {
437 /* don't care about this one */
438 g_object_unref (G_OBJECT (mstruct));
439 MUTEX_UNLOCK (bcnc);
440 return GINT_TO_POINTER (3);
441 }
442 else {
443 if (bcnc->priv->c_mstruct)
444 g_object_unref (bcnc->priv->c_mstruct);
445 bcnc->priv->c_mstruct = mstruct;
446
447 /*g_print ("Meta struct sync for %p\n", mstruct);*/
448 retval = gda_meta_struct_complement_all (mstruct, error);
449 MUTEX_UNLOCK (bcnc);
450 }
451
452 #ifdef GDA_DEBUG_NO
453 GSList *all, *list;
454 g_print ("%s() %p:\n", __FUNCTION__, bcnc->priv->mstruct);
455 all = gda_meta_struct_get_all_db_objects (bcnc->priv->mstruct);
456 for (list = all; list; list = list->next) {
457 GdaMetaDbObject *dbo = (GdaMetaDbObject *) list->data;
458 g_print ("DBO, Type %d: short=>[%s] schema=>[%s] full=>[%s]\n", dbo->obj_type,
459 dbo->obj_short_name, dbo->obj_schema, dbo->obj_full_name);
460 }
461 g_slist_free (all);
462 #endif
463
464 return GINT_TO_POINTER (retval ? 2 : 1);
465 }
466
467 /*
468 * executed in main thread
469 */
470 static void
meta_changed_cb(G_GNUC_UNUSED GdaThreadWrapper * wrapper,G_GNUC_UNUSED GdaMetaStore * store,G_GNUC_UNUSED const gchar * signame,G_GNUC_UNUSED gint n_param_values,G_GNUC_UNUSED const GValue * param_values,G_GNUC_UNUSED gpointer gda_reserved,BrowserConnection * bcnc)471 meta_changed_cb (G_GNUC_UNUSED GdaThreadWrapper *wrapper,
472 G_GNUC_UNUSED GdaMetaStore *store,
473 G_GNUC_UNUSED const gchar *signame,
474 G_GNUC_UNUSED gint n_param_values,
475 G_GNUC_UNUSED const GValue *param_values,
476 G_GNUC_UNUSED gpointer gda_reserved,
477 BrowserConnection *bcnc)
478 {
479 guint job_id;
480 GError *lerror = NULL;
481 GdaMetaStruct *mstruct;
482
483 MUTEX_LOCK (bcnc);
484 mstruct = gda_meta_struct_new (gda_connection_get_meta_store (bcnc->priv->cnc),
485 GDA_META_STRUCT_FEATURE_ALL);
486 bcnc->priv->p_mstruct_list = g_slist_append (bcnc->priv->p_mstruct_list, mstruct);
487 /*g_print ("%s() Added %p to p_mstruct_list\n", __FUNCTION__, mstruct);*/
488 MUTEX_UNLOCK (bcnc);
489 job_id = gda_thread_wrapper_execute (bcnc->priv->wrapper,
490 (GdaThreadWrapperFunc) wrapper_meta_struct_sync,
491 g_object_ref (bcnc), g_object_unref, &lerror);
492 if (job_id > 0)
493 push_wrapper_job (bcnc, job_id, JOB_TYPE_META_STRUCT_SYNC,
494 _("Analysing database schema"), NULL, NULL);
495 else if (lerror) {
496 browser_show_error (NULL, _("Error while fetching meta data from the connection: %s"),
497 lerror->message ? lerror->message : _("No detail"));
498 g_error_free (lerror);
499 }
500 }
501
502 /**
503 * browser_connection_meta_data_changed
504 * @bcnc: a #BrowserConnection
505 *
506 * Call this function if the meta data has been changed directly (ie. for example after
507 * declaring or undeclaring a foreign key). This call creates a new #GdaMetaStruct internally used.
508 */
509 void
browser_connection_meta_data_changed(BrowserConnection * bcnc)510 browser_connection_meta_data_changed (BrowserConnection *bcnc)
511 {
512 g_return_if_fail (BROWSER_IS_CONNECTION (bcnc));
513 meta_changed_cb (NULL, NULL, NULL, 0, NULL, NULL, bcnc);
514 }
515
516 /*
517 * executed in bcnc->priv->wrapper's thread
518 */
519 static gpointer
wrapper_have_meta_store_ready(BrowserConnection * bcnc,GError ** error)520 wrapper_have_meta_store_ready (BrowserConnection *bcnc, GError **error)
521 {
522 gchar *dict_file_name = NULL;
523 gboolean update_store = FALSE;
524 GdaMetaStore *store;
525 gchar *cnc_string, *cnc_info;
526
527 g_object_get (G_OBJECT (bcnc->priv->cnc),
528 "dsn", &cnc_info,
529 "cnc-string", &cnc_string, NULL);
530 dict_file_name = config_info_compute_dict_file_name (cnc_info ? gda_config_get_dsn_info (cnc_info) : NULL,
531 cnc_string);
532 g_free (cnc_string);
533 if (dict_file_name) {
534 if (BROWSER_IS_VIRTUAL_CONNECTION (bcnc))
535 /* force meta store update in case of virtual connection */
536 update_store = TRUE;
537 else if (! g_file_test (dict_file_name, G_FILE_TEST_EXISTS))
538 update_store = TRUE;
539 store = gda_meta_store_new_with_file (dict_file_name);
540 }
541 else {
542 store = gda_meta_store_new (NULL);
543 if (store)
544 update_store = TRUE;
545 }
546 config_info_update_meta_store_properties (store, bcnc->priv->cnc);
547
548 bcnc->priv->dict_file_name = dict_file_name;
549 g_object_set (G_OBJECT (bcnc->priv->cnc), "meta-store", store, NULL);
550 if (update_store) {
551 gboolean retval;
552 GdaMetaContext context = {"_tables", 0, NULL, NULL};
553 retval = gda_connection_update_meta_store (bcnc->priv->cnc, &context, error);
554 if (!retval) {
555 g_object_unref (store);
556 return NULL;
557 }
558 }
559
560 gboolean retval = TRUE;
561 GdaMetaStruct *mstruct;
562 mstruct = gda_meta_struct_new (store, GDA_META_STRUCT_FEATURE_ALL);
563 MUTEX_LOCK (bcnc);
564 if (bcnc->priv->c_mstruct) {
565 g_object_unref (bcnc->priv->c_mstruct);
566 bcnc->priv->c_mstruct = NULL;
567 }
568 bcnc->priv->mstruct = mstruct;
569 retval = gda_meta_struct_complement_all (mstruct, error);
570 MUTEX_UNLOCK (bcnc);
571
572 #ifdef GDA_DEBUG_NO
573 GSList *all, *list;
574 g_print ("%s() %p:\n", __FUNCTION__, bcnc->priv->mstruct);
575 all = gda_meta_struct_get_all_db_objects (bcnc->priv->mstruct);
576 for (list = all; list; list = list->next) {
577 GdaMetaDbObject *dbo = (GdaMetaDbObject *) list->data;
578 g_print ("DBO, Type %d: short=>[%s] schema=>[%s] full=>[%s]\n", dbo->obj_type,
579 dbo->obj_short_name, dbo->obj_schema, dbo->obj_full_name);
580 }
581 g_slist_free (all);
582 #endif
583 g_object_unref (store);
584 return retval ? (void*) 0x01 : NULL;
585 }
586
587 typedef struct {
588 guint jid;
589 GMainLoop *loop;
590 GError **error;
591 GdaThreadWrapper *wrapper;
592
593 /* out */
594 gboolean retval;
595 } MainloopData;
596
597 static gboolean
check_for_meta_store_ready(MainloopData * data)598 check_for_meta_store_ready (MainloopData *data)
599 {
600 gpointer retval;
601 GError *lerror = NULL;
602
603 retval = gda_thread_wrapper_fetch_result (data->wrapper, FALSE, data->jid, &lerror);
604 if (retval || (!retval && lerror)) {
605 /* waiting is finished! */
606 data->retval = retval ? TRUE : FALSE;
607 if (lerror)
608 g_propagate_error (data->error, lerror);
609 g_main_loop_quit (data->loop);
610 return FALSE;
611 }
612 return TRUE;
613 }
614
615
616 static void
browser_connection_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)617 browser_connection_set_property (GObject *object,
618 guint param_id,
619 const GValue *value,
620 GParamSpec *pspec)
621 {
622 BrowserConnection *bcnc;
623
624 bcnc = BROWSER_CONNECTION (object);
625 if (bcnc->priv) {
626 switch (param_id) {
627 case PROP_GDA_CNC:
628 bcnc->priv->cnc = (GdaConnection*) g_value_get_object (value);
629 if (!bcnc->priv->cnc)
630 return;
631
632 /*g_print ("BrowserConnection %p [%s], wrapper %p, GdaConnection %p\n",
633 bcnc, bcnc->priv->name, bcnc->priv->wrapper, bcnc->priv->cnc);*/
634 g_object_ref (bcnc->priv->cnc);
635 g_object_set (G_OBJECT (bcnc->priv->cnc), "execution-timer", TRUE, NULL);
636 bcnc->priv->transaction_status_signal =
637 gda_thread_wrapper_connect_raw (bcnc->priv->wrapper,
638 bcnc->priv->cnc,
639 "transaction-status-changed",
640 FALSE, FALSE,
641 (GdaThreadWrapperCallback) transaction_status_changed_cb,
642 bcnc);
643
644
645 /* meta store, open it in a sub thread to avoid locking the GTK thread */
646 GError *lerror = NULL;
647 guint jid;
648 jid = gda_thread_wrapper_execute (bcnc->priv->wrapper,
649 (GdaThreadWrapperFunc) wrapper_have_meta_store_ready,
650 (gpointer) bcnc,
651 NULL, &lerror);
652 if (jid == 0) {
653 browser_show_error (NULL, _("Error while fetching meta data from the connection: %s"),
654 lerror->message ? lerror->message : _("No detail"));
655 g_clear_error (&lerror);
656 }
657 else {
658 GMainLoop *loop;
659 MainloopData data;
660
661 loop = g_main_loop_new (NULL, FALSE);
662 data.jid = jid;
663 data.loop = loop;
664 data.error = &lerror;
665 data.wrapper = bcnc->priv->wrapper;
666 g_timeout_add (200, (GSourceFunc) check_for_meta_store_ready, &data);
667 g_main_loop_run (loop);
668 g_main_loop_unref (loop);
669 if (!data.retval) {
670 browser_show_error (NULL, _("Error while fetching meta data from the connection: %s"),
671 lerror->message ? lerror->message : _("No detail"));
672 g_clear_error (&lerror);
673 }
674 else {
675 GdaMetaStore *store;
676 g_object_get (G_OBJECT (bcnc->priv->cnc), "meta-store", &store, NULL);
677 bcnc->priv->meta_store_signal =
678 gda_thread_wrapper_connect_raw (bcnc->priv->wrapper, store, "meta-changed",
679 FALSE, FALSE,
680 (GdaThreadWrapperCallback) meta_changed_cb,
681 bcnc);
682 g_object_unref (store);
683 }
684
685 }
686 break;
687 default:
688 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
689 break;
690 }
691 }
692 }
693
694
695
696 static void
browser_connection_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)697 browser_connection_get_property (GObject *object,
698 guint param_id,
699 GValue *value,
700 GParamSpec *pspec)
701 {
702 BrowserConnection *bcnc;
703
704 bcnc = BROWSER_CONNECTION (object);
705 if (bcnc->priv) {
706 switch (param_id) {
707 case PROP_GDA_CNC:
708 g_value_set_object (value, bcnc->priv->cnc);
709 break;
710 default:
711 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
712 break;
713 }
714 }
715 }
716
717 static void
clear_dsn_info(BrowserConnection * bcnc)718 clear_dsn_info (BrowserConnection *bcnc)
719 {
720 g_free (bcnc->priv->dsn_info.name);
721 bcnc->priv->dsn_info.name = NULL;
722
723 g_free (bcnc->priv->dsn_info.provider);
724 bcnc->priv->dsn_info.provider = NULL;
725
726 g_free (bcnc->priv->dsn_info.description);
727 bcnc->priv->dsn_info.description = NULL;
728
729 g_free (bcnc->priv->dsn_info.cnc_string);
730 bcnc->priv->dsn_info.cnc_string = NULL;
731
732 g_free (bcnc->priv->dsn_info.auth_string);
733 bcnc->priv->dsn_info.auth_string = NULL;
734 }
735
736 static void
fav_changed_cb(G_GNUC_UNUSED ToolsFavorites * bfav,BrowserConnection * bcnc)737 fav_changed_cb (G_GNUC_UNUSED ToolsFavorites *bfav, BrowserConnection *bcnc)
738 {
739 g_signal_emit (bcnc, browser_connection_signals [FAV_CHANGED], 0);
740 }
741
742 static void
browser_connection_dispose(GObject * object)743 browser_connection_dispose (GObject *object)
744 {
745 BrowserConnection *bcnc;
746
747 g_return_if_fail (object != NULL);
748 g_return_if_fail (BROWSER_IS_CONNECTION (object));
749
750 bcnc = BROWSER_CONNECTION (object);
751 if (bcnc->priv) {
752 if (bcnc->priv->results_timer_id) {
753 g_source_remove (bcnc->priv->results_timer_id);
754 bcnc->priv->results_timer_id = 0;
755 }
756 if (bcnc->priv->results_list) {
757 g_slist_foreach (bcnc->priv->results_list, (GFunc) g_free, NULL);
758 g_slist_free (bcnc->priv->results_list);
759 bcnc->priv->results_list = NULL;
760 }
761
762 if (bcnc->priv->variables)
763 g_object_unref (bcnc->priv->variables);
764
765 if (bcnc->priv->store_cnc)
766 g_object_unref (bcnc->priv->store_cnc);
767
768 if (bcnc->priv->executed_statements)
769 g_hash_table_destroy (bcnc->priv->executed_statements);
770
771 clear_dsn_info (bcnc);
772
773 g_free (bcnc->priv->dict_file_name);
774
775 if (bcnc->priv->wrapper_jobs) {
776 g_slist_foreach (bcnc->priv->wrapper_jobs, (GFunc) wrapper_job_free, NULL);
777 g_slist_free (bcnc->priv->wrapper_jobs);
778 }
779
780 if (bcnc->priv->wrapper_results_timer > 0)
781 g_source_remove (bcnc->priv->wrapper_results_timer);
782
783 if (bcnc->priv->meta_store_signal)
784 gda_thread_wrapper_disconnect (bcnc->priv->wrapper,
785 bcnc->priv->meta_store_signal);
786 if (bcnc->priv->transaction_status_signal)
787 gda_thread_wrapper_disconnect (bcnc->priv->wrapper,
788 bcnc->priv->transaction_status_signal);
789
790 g_object_unref (bcnc->priv->wrapper);
791 g_free (bcnc->priv->name);
792 if (bcnc->priv->c_mstruct)
793 g_object_unref (bcnc->priv->c_mstruct);
794 if (bcnc->priv->mstruct)
795 g_object_unref (bcnc->priv->mstruct);
796 if (bcnc->priv->p_mstruct_list) {
797 g_slist_foreach (bcnc->priv->p_mstruct_list, (GFunc) g_object_unref, NULL);
798 g_slist_free (bcnc->priv->p_mstruct_list);
799 }
800 g_mutex_clear (&bcnc->priv->mstruct_mutex);
801
802 if (bcnc->priv->cnc)
803 g_object_unref (bcnc->priv->cnc);
804
805 if (bcnc->priv->parser)
806 g_object_unref (bcnc->priv->parser);
807 if (bcnc->priv->bfav) {
808 g_signal_handlers_disconnect_by_func (bcnc->priv->bfav,
809 G_CALLBACK (fav_changed_cb), bcnc);
810 g_object_unref (bcnc->priv->bfav);
811 }
812 browser_connection_set_busy_state (bcnc, FALSE, NULL);
813
814 if (bcnc->priv->ioc_watch_id > 0) {
815 g_source_remove (bcnc->priv->ioc_watch_id);
816 bcnc->priv->ioc_watch_id = 0;
817 }
818
819 if (bcnc->priv->ioc) {
820 g_io_channel_unref (bcnc->priv->ioc);
821 bcnc->priv->ioc = NULL;
822 }
823
824 g_free (bcnc->priv);
825 bcnc->priv = NULL;
826 /*g_print ("Disposed BrowserConnection %p\n", bcnc);*/
827 }
828
829 /* parent class */
830 parent_class->dispose (object);
831 }
832
833 static gboolean
check_for_wrapper_result(BrowserConnection * bcnc)834 check_for_wrapper_result (BrowserConnection *bcnc)
835 {
836 GError *lerror = NULL;
837 gpointer exec_res = NULL;
838 WrapperJob *wj;
839 gboolean retval = TRUE; /* return FALSE to interrupt current timer */
840
841 retval = !setup_results_timer (bcnc);
842 if (!bcnc->priv->wrapper_jobs) {
843 gda_thread_wrapper_iterate (bcnc->priv->wrapper, FALSE);
844 return retval;
845 }
846
847 wj = (WrapperJob*) bcnc->priv->wrapper_jobs->data;
848 exec_res = gda_thread_wrapper_fetch_result (bcnc->priv->wrapper,
849 FALSE,
850 wj->job_id, &lerror);
851 if (exec_res) {
852 switch (wj->job_type) {
853 case JOB_TYPE_META_STORE_UPDATE: {
854 if (GPOINTER_TO_INT (exec_res) == 1) {
855 browser_show_error (NULL, _("Error while analysing database schema: %s"),
856 lerror && lerror->message ? lerror->message : _("No detail"));
857 g_clear_error (&lerror);
858 }
859 else if (! bcnc->priv->meta_store_signal) {
860 GdaMetaStore *store;
861 store = gda_connection_get_meta_store (bcnc->priv->cnc);
862 meta_changed_cb (bcnc->priv->wrapper, store,
863 NULL, 0, NULL, NULL, bcnc);
864 bcnc->priv->meta_store_signal =
865 gda_thread_wrapper_connect_raw (bcnc->priv->wrapper, store, "meta-changed",
866 FALSE, FALSE,
867 (GdaThreadWrapperCallback) meta_changed_cb,
868 bcnc);
869
870 }
871 break;
872 }
873 case JOB_TYPE_META_STRUCT_SYNC: {
874 if (GPOINTER_TO_INT (exec_res) == 1) {
875 browser_show_error (NULL, _("Error while analysing database schema: %s"),
876 lerror && lerror->message ? lerror->message : _("No detail"));
877 g_clear_error (&lerror);
878 }
879 else if (GPOINTER_TO_INT (exec_res) == 3) {
880 /* nothing to do */
881 }
882 else {
883 MUTEX_LOCK (bcnc);
884
885 if (bcnc->priv->c_mstruct) {
886 GdaMetaStruct *old_mstruct;
887 old_mstruct = bcnc->priv->mstruct;
888 bcnc->priv->mstruct = bcnc->priv->c_mstruct;
889 bcnc->priv->c_mstruct = NULL;
890 if (old_mstruct)
891 g_object_unref (old_mstruct);
892 #ifdef GDA_DEBUG_NO
893 GSList *all, *list;
894 g_print ("Signalling change for GdaMetaStruct %p:\n", bcnc->priv->mstruct);
895 all = gda_meta_struct_get_all_db_objects (bcnc->priv->mstruct);
896 for (list = all; list; list = list->next) {
897 GdaMetaDbObject *dbo = (GdaMetaDbObject *) list->data;
898 g_print ("DBO, Type %d: short=>[%s] schema=>[%s] full=>[%s]\n", dbo->obj_type,
899 dbo->obj_short_name, dbo->obj_schema, dbo->obj_full_name);
900 }
901 g_slist_free (all);
902 #endif
903 g_signal_emit (bcnc, browser_connection_signals [META_CHANGED], 0, bcnc->priv->mstruct);
904 }
905 MUTEX_UNLOCK (bcnc);
906 }
907 break;
908 }
909 case JOB_TYPE_STATEMENT_EXECUTE: {
910 guint *id;
911 StatementResult *res;
912
913 if (! bcnc->priv->executed_statements)
914 bcnc->priv->executed_statements = g_hash_table_new_full (g_int_hash, g_int_equal,
915 g_free,
916 (GDestroyNotify) statement_result_free);
917 id = g_new (guint, 1);
918 *id = wj->job_id;
919 res = g_new0 (StatementResult, 1);
920 if (exec_res == (gpointer) 0x01)
921 res->error = lerror;
922 else {
923 res->result = G_OBJECT (exec_res);
924 res->last_inserted_row = g_object_get_data (exec_res, "__bcnc_last_inserted_row");
925 if (res->last_inserted_row)
926 g_object_set_data (exec_res, "__bcnc_last_inserted_row", NULL);
927 }
928 g_hash_table_insert (bcnc->priv->executed_statements, id, res);
929 break;
930 }
931 case JOB_TYPE_CALLBACK:
932 if (wj->callback) {
933 wj->callback (bcnc, exec_res == (gpointer) 0x01 ? NULL : exec_res,
934 wj->cb_data, lerror);
935 g_clear_error (&lerror);
936 }
937 break;
938 default:
939 g_assert_not_reached ();
940 break;
941 }
942
943 pop_wrapper_job (bcnc, wj);
944 }
945
946 if (bcnc->priv->wrapper_jobs) {
947 wj = (WrapperJob*) bcnc->priv->wrapper_jobs->data;
948 if (exec_res)
949 g_signal_emit (bcnc, browser_connection_signals [BUSY], 0, TRUE, wj->reason);
950 }
951 return retval;
952 }
953
954 /**
955 * browser_connection_new
956 * @cnc: a #GdaConnection
957 *
958 * Creates a new #BrowserConnection object wrapping @cnc. The browser_core_take_connection() method
959 * must be called on the new object to mahe it managed by the browser.
960 *
961 * To close the new connection, use browser_core_close_connection().
962 *
963 * Returns: a new object
964 */
965 BrowserConnection*
browser_connection_new(GdaConnection * cnc)966 browser_connection_new (GdaConnection *cnc)
967 {
968 BrowserConnection *bcnc;
969
970 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
971
972 bcnc = BROWSER_CONNECTION (g_object_new (BROWSER_TYPE_CONNECTION, "gda-connection", cnc, NULL));
973
974 return bcnc;
975 }
976
977 /**
978 * browser_connection_get_name
979 * @bcnc: a #BrowserConnection
980 *
981 * Returns: @bcnc's name
982 */
983 const gchar *
browser_connection_get_name(BrowserConnection * bcnc)984 browser_connection_get_name (BrowserConnection *bcnc)
985 {
986 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
987 return bcnc->priv->name;
988 }
989
990 /**
991 * browser_connection_get_long_name:
992 * @bcnc: a #BrowserConnection
993 *
994 * Get the "long" name of @bcnc
995 *
996 * Returns: a new string
997 */
998 gchar *
browser_connection_get_long_name(BrowserConnection * bcnc)999 browser_connection_get_long_name (BrowserConnection *bcnc)
1000 {
1001 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
1002 const gchar *cncname;
1003 const GdaDsnInfo *dsn;
1004 GString *title;
1005
1006 dsn = browser_connection_get_information (bcnc);
1007 cncname = browser_connection_get_name (bcnc);
1008 title = g_string_new (_("Connection"));
1009 g_string_append (title, " ");
1010 g_string_append_printf (title, "'%s'", cncname ? cncname : _("unnamed"));
1011 if (dsn) {
1012 if (dsn->name)
1013 g_string_append_printf (title, ", %s '%s'", _("data source"), dsn->name);
1014 if (dsn->provider)
1015 g_string_append_printf (title, " (%s)", dsn->provider);
1016 }
1017 return g_string_free (title, FALSE);
1018 }
1019
1020 /**
1021 * browser_connection_get_information
1022 * @bcnc: a #BrowserConnection
1023 *
1024 * Get some information about the connection
1025 *
1026 * Returns: a pointer to the associated #GdaDsnInfo
1027 */
1028 const GdaDsnInfo *
browser_connection_get_information(BrowserConnection * bcnc)1029 browser_connection_get_information (BrowserConnection *bcnc)
1030 {
1031 gboolean is_wrapper;
1032 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
1033
1034 clear_dsn_info (bcnc);
1035 if (!bcnc->priv->cnc)
1036 return NULL;
1037
1038 g_object_get (G_OBJECT (bcnc->priv->cnc), "is-wrapper", &is_wrapper, NULL);
1039
1040 if (!is_wrapper && gda_connection_get_provider_name (bcnc->priv->cnc))
1041 bcnc->priv->dsn_info.provider = g_strdup (gda_connection_get_provider_name (bcnc->priv->cnc));
1042 if (gda_connection_get_dsn (bcnc->priv->cnc)) {
1043 bcnc->priv->dsn_info.name = g_strdup (gda_connection_get_dsn (bcnc->priv->cnc));
1044 if (! bcnc->priv->dsn_info.provider) {
1045 GdaDsnInfo *cinfo;
1046 cinfo = gda_config_get_dsn_info (bcnc->priv->dsn_info.name);
1047 if (cinfo && cinfo->provider)
1048 bcnc->priv->dsn_info.provider = g_strdup (cinfo->provider);
1049 }
1050 }
1051 if (gda_connection_get_cnc_string (bcnc->priv->cnc))
1052 bcnc->priv->dsn_info.cnc_string = g_strdup (gda_connection_get_cnc_string (bcnc->priv->cnc));
1053 if (is_wrapper && bcnc->priv->dsn_info.cnc_string) {
1054 GdaQuarkList *ql;
1055 const gchar *prov;
1056 ql = gda_quark_list_new_from_string (bcnc->priv->dsn_info.cnc_string);
1057 prov = gda_quark_list_find (ql, "PROVIDER_NAME");
1058 if (prov)
1059 bcnc->priv->dsn_info.provider = g_strdup (prov);
1060 gda_quark_list_free (ql);
1061 }
1062 if (gda_connection_get_authentication (bcnc->priv->cnc))
1063 bcnc->priv->dsn_info.auth_string = g_strdup (gda_connection_get_authentication (bcnc->priv->cnc));
1064
1065 return &(bcnc->priv->dsn_info);
1066 }
1067
1068 /**
1069 * browser_connection_is_virtual
1070 * @bcnc: a #BrowserConnection
1071 *
1072 * Tells if @bcnc is a virtual connection or not
1073 *
1074 * Returns: %TRUE if @bcnc is a virtual connection
1075 */
1076 gboolean
browser_connection_is_virtual(BrowserConnection * bcnc)1077 browser_connection_is_virtual (BrowserConnection *bcnc)
1078 {
1079 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), FALSE);
1080 if (GDA_IS_VIRTUAL_CONNECTION (bcnc->priv->cnc))
1081 return TRUE;
1082 else
1083 return FALSE;
1084 }
1085
1086 /**
1087 * browser_connection_is_busy
1088 * @bcnc: a #BrowserConnection
1089 * @out_reason: a pointer to store a copy of the reason @bcnc is busy (will be set
1090 * to %NULL if @bcnc is not busy), or %NULL
1091 *
1092 * Tells if @bcnc is currently busy or not.
1093 *
1094 * Returns: %TRUE if @bcnc is busy
1095 */
1096 gboolean
browser_connection_is_busy(BrowserConnection * bcnc,gchar ** out_reason)1097 browser_connection_is_busy (BrowserConnection *bcnc, gchar **out_reason)
1098 {
1099 if (out_reason)
1100 *out_reason = NULL;
1101 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), FALSE);
1102
1103 if (out_reason && bcnc->priv->busy_reason)
1104 *out_reason = g_strdup (bcnc->priv->busy_reason);
1105
1106 return bcnc->priv->busy;
1107 }
1108
1109 /**
1110 * browser_connection_update_meta_data
1111 * @bcnc: a #BrowserConnection
1112 *
1113 * Make @bcnc update its meta store in the background.
1114 */
1115 void
browser_connection_update_meta_data(BrowserConnection * bcnc)1116 browser_connection_update_meta_data (BrowserConnection *bcnc)
1117 {
1118 g_return_if_fail (BROWSER_IS_CONNECTION (bcnc));
1119
1120 if (bcnc->priv->wrapper_jobs) {
1121 WrapperJob *wj;
1122 wj = (WrapperJob*) g_slist_last (bcnc->priv->wrapper_jobs)->data;
1123 if (wj->job_type == JOB_TYPE_META_STORE_UPDATE) {
1124 /* nothing to do */
1125 return;
1126 }
1127 }
1128
1129 if (bcnc->priv->meta_store_signal) {
1130 gda_thread_wrapper_disconnect (bcnc->priv->wrapper,
1131 bcnc->priv->meta_store_signal);
1132 bcnc->priv->meta_store_signal = 0;
1133 }
1134
1135 guint job_id;
1136 GError *lerror = NULL;
1137 job_id = gda_thread_wrapper_execute (bcnc->priv->wrapper,
1138 (GdaThreadWrapperFunc) wrapper_meta_store_update,
1139 g_object_ref (bcnc), g_object_unref, &lerror);
1140 if (job_id > 0)
1141 push_wrapper_job (bcnc, job_id, JOB_TYPE_META_STORE_UPDATE,
1142 _("Getting database schema information"), NULL, NULL);
1143 else if (lerror) {
1144 browser_show_error (NULL, _("Error while fetching meta data from the connection: %s"),
1145 lerror->message ? lerror->message : _("No detail"));
1146 g_error_free (lerror);
1147 }
1148 }
1149
1150 /**
1151 * browser_connection_get_meta_struct
1152 * @bcnc: a #BrowserConnection
1153 *
1154 * Get the #GdaMetaStruct maintained up to date by @bcnc.
1155 *
1156 * Returns: a #GdaMetaStruct, the caller does not have any reference to it.
1157 */
1158 GdaMetaStruct *
browser_connection_get_meta_struct(BrowserConnection * bcnc)1159 browser_connection_get_meta_struct (BrowserConnection *bcnc)
1160 {
1161 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
1162 return bcnc->priv->mstruct;
1163 }
1164
1165 /**
1166 * browser_connection_get_meta_store
1167 * @bcnc: a #BrowserConnection
1168 *
1169 * Returns: @bcnc's #GdaMetaStore, the caller does not have any reference to it.
1170 */
1171 GdaMetaStore *
browser_connection_get_meta_store(BrowserConnection * bcnc)1172 browser_connection_get_meta_store (BrowserConnection *bcnc)
1173 {
1174 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
1175 return gda_connection_get_meta_store (bcnc->priv->cnc);
1176 }
1177
1178 /**
1179 * browser_connection_get_dictionary_file
1180 * @bcnc: a #BrowserConnection
1181 *
1182 * Returns: the dictionary file name used by @bcnc, or %NULL
1183 */
1184 const gchar *
browser_connection_get_dictionary_file(BrowserConnection * bcnc)1185 browser_connection_get_dictionary_file (BrowserConnection *bcnc)
1186 {
1187 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
1188 return bcnc->priv->dict_file_name;
1189 }
1190
1191 /**
1192 * browser_connection_get_transaction_status
1193 * @bcnc: a #BrowserConnection
1194 *
1195 * Retuns: the #GdaTransactionStatus of the connection, or %NULL
1196 */
1197 GdaTransactionStatus *
browser_connection_get_transaction_status(BrowserConnection * bcnc)1198 browser_connection_get_transaction_status (BrowserConnection *bcnc)
1199 {
1200 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
1201 return gda_connection_get_transaction_status (bcnc->priv->cnc);
1202 }
1203
1204 /**
1205 * browser_connection_begin
1206 * @bcnc: a #BrowserConnection
1207 * @error: a place to store errors, or %NULL
1208 *
1209 * Begins a transaction
1210 */
1211 gboolean
browser_connection_begin(BrowserConnection * bcnc,GError ** error)1212 browser_connection_begin (BrowserConnection *bcnc, GError **error)
1213 {
1214 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), FALSE);
1215 return gda_connection_begin_transaction (bcnc->priv->cnc, NULL,
1216 GDA_TRANSACTION_ISOLATION_UNKNOWN, error);
1217 }
1218
1219 /**
1220 * browser_connection_commit
1221 * @bcnc: a #BrowserConnection
1222 * @error: a place to store errors, or %NULL
1223 *
1224 * Commits a transaction
1225 */
1226 gboolean
browser_connection_commit(BrowserConnection * bcnc,GError ** error)1227 browser_connection_commit (BrowserConnection *bcnc, GError **error)
1228 {
1229 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), FALSE);
1230 return gda_connection_commit_transaction (bcnc->priv->cnc, NULL, error);
1231 }
1232
1233 /**
1234 * browser_connection_rollback
1235 * @bcnc: a #BrowserConnection
1236 * @error: a place to store errors, or %NULL
1237 *
1238 * Rolls back a transaction
1239 */
1240 gboolean
browser_connection_rollback(BrowserConnection * bcnc,GError ** error)1241 browser_connection_rollback (BrowserConnection *bcnc, GError **error)
1242 {
1243 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), FALSE);
1244 return gda_connection_rollback_transaction (bcnc->priv->cnc, NULL, error);
1245 }
1246
1247 /**
1248 * browser_connection_get_favorites
1249 * @bcnc: a #BrowserConnection
1250 *
1251 * Get @bcnc's favorites handler
1252 *
1253 * Returns: (transfer none): the #ToolsFavorites used by @bcnc
1254 */
1255 ToolsFavorites *
browser_connection_get_favorites(BrowserConnection * bcnc)1256 browser_connection_get_favorites (BrowserConnection *bcnc)
1257 {
1258 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
1259 if (!bcnc->priv->bfav && !BROWSER_IS_VIRTUAL_CONNECTION (bcnc)) {
1260 bcnc->priv->bfav = gda_tools_favorites_new (gda_connection_get_meta_store (bcnc->priv->cnc));
1261 g_signal_connect (bcnc->priv->bfav, "favorites-changed",
1262 G_CALLBACK (fav_changed_cb), bcnc);
1263 }
1264 return bcnc->priv->bfav;
1265 }
1266
1267 /**
1268 * browser_connection_get_completions
1269 * @bcnc: a #BrowserConnection
1270 * @sql:
1271 * @start:
1272 * @end:
1273 *
1274 * See gda_completion_list_get()
1275 *
1276 * Returns: a new array of strings, or NULL (use g_strfreev() to free the returned array)
1277 */
1278 gchar **
browser_connection_get_completions(BrowserConnection * bcnc,const gchar * sql,gint start,gint end)1279 browser_connection_get_completions (BrowserConnection *bcnc, const gchar *sql,
1280 gint start, gint end)
1281 {
1282 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
1283 return gda_completion_list_get (bcnc->priv->cnc, sql, start, end);
1284 }
1285
1286
1287 /**
1288 * browser_connection_create_parser
1289 * @bcnc: a #BrowserConnection
1290 *
1291 * Get a new #GdaSqlParser object for @bcnc
1292 *
1293 * Returns: a new #GdaSqlParser
1294 */
1295 GdaSqlParser *
browser_connection_create_parser(BrowserConnection * bcnc)1296 browser_connection_create_parser (BrowserConnection *bcnc)
1297 {
1298 GdaSqlParser *parser;
1299 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
1300
1301 parser = gda_connection_create_parser (bcnc->priv->cnc);
1302 if (!parser)
1303 parser = gda_sql_parser_new ();
1304 return parser;
1305 }
1306
1307 /**
1308 * browser_connection_render_pretty_sql
1309 * @bcnc: a #BrowserConnection
1310 * @stmt: a #GdaStatement
1311 *
1312 * Renders @stmt as SQL well indented
1313 *
1314 * Returns: a new string
1315 */
1316 gchar *
browser_connection_render_pretty_sql(BrowserConnection * bcnc,GdaStatement * stmt)1317 browser_connection_render_pretty_sql (BrowserConnection *bcnc, GdaStatement *stmt)
1318 {
1319 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
1320 g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
1321
1322 return gda_statement_to_sql_extended (stmt, bcnc->priv->cnc, NULL,
1323 GDA_STATEMENT_SQL_PRETTY |
1324 GDA_STATEMENT_SQL_PARAMS_SHORT,
1325 NULL, NULL);
1326 }
1327
1328 typedef struct {
1329 GdaConnection *cnc;
1330 GdaStatement *stmt;
1331 GdaSet *params;
1332 GdaStatementModelUsage model_usage;
1333 gboolean need_last_insert_row;
1334 } StmtExecData;
1335
1336 /* executed in sub @bcnc->priv->wrapper's thread */
1337 static gpointer
wrapper_statement_execute(StmtExecData * data,GError ** error)1338 wrapper_statement_execute (StmtExecData *data, GError **error)
1339 {
1340 GObject *obj;
1341 GdaSet *last_insert_row = NULL;
1342 GError *lerror = NULL;
1343 obj = gda_connection_statement_execute (data->cnc, data->stmt,
1344 data->params, data->model_usage,
1345 data->need_last_insert_row ? &last_insert_row : NULL,
1346 &lerror);
1347 if (obj) {
1348 if (GDA_IS_DATA_MODEL (obj))
1349 /* force loading of rows if necessary */
1350 gda_data_model_get_n_rows ((GdaDataModel*) obj);
1351 else if (last_insert_row)
1352 g_object_set_data (obj, "__bcnc_last_inserted_row", last_insert_row);
1353 }
1354 else {
1355 if (lerror)
1356 g_propagate_error (error, lerror);
1357 else {
1358 g_warning (_("Execution reported an undefined error, please report error to "
1359 "http://bugzilla.gnome.org/ for the \"libgda\" product"));
1360 g_set_error (error, GDA_TOOLS_ERROR, GDA_TOOLS_INTERNAL_COMMAND_ERROR,
1361 "%s", _("No detail"));
1362 }
1363 }
1364 return obj ? obj : (gpointer) 0x01;
1365 }
1366
1367 /**
1368 * browser_connection_execute_statement
1369 * @bcnc: a #BrowserConnection
1370 * @stmt: a #GdaStatement
1371 * @params: a #GdaSet as parameters, or %NULL
1372 * @model_usage: how the returned data model (if any) will be used
1373 * @need_last_insert_row: %TRUE if the values of the last interted row must be computed
1374 * @error: a place to store errors, or %NULL
1375 *
1376 * Executes @stmt by @bcnc. Unless specific requirements, it's easier to use
1377 * browser_connection_execute_statement_cb().
1378 *
1379 * Returns: a job ID, to be used with browser_connection_execution_get_result(), or %0 if an
1380 * error occurred
1381 */
1382 guint
browser_connection_execute_statement(BrowserConnection * bcnc,GdaStatement * stmt,GdaSet * params,GdaStatementModelUsage model_usage,gboolean need_last_insert_row,GError ** error)1383 browser_connection_execute_statement (BrowserConnection *bcnc,
1384 GdaStatement *stmt,
1385 GdaSet *params,
1386 GdaStatementModelUsage model_usage,
1387 gboolean need_last_insert_row,
1388 GError **error)
1389 {
1390 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), 0);
1391 g_return_val_if_fail (GDA_IS_STATEMENT (stmt), 0);
1392 g_return_val_if_fail (!params || GDA_IS_SET (params), 0);
1393
1394 StmtExecData *data;
1395 guint job_id;
1396
1397 data = g_new0 (StmtExecData, 1);
1398 data->cnc = bcnc->priv->cnc;
1399 data->stmt = stmt;
1400 data->params = params;
1401 data->model_usage = model_usage;
1402 data->need_last_insert_row = need_last_insert_row;
1403
1404 job_id = gda_thread_wrapper_execute (bcnc->priv->wrapper,
1405 (GdaThreadWrapperFunc) wrapper_statement_execute,
1406 data, (GDestroyNotify) g_free, error);
1407 if (job_id > 0)
1408 push_wrapper_job (bcnc, job_id, JOB_TYPE_STATEMENT_EXECUTE,
1409 _("Executing a query"), NULL, NULL);
1410
1411 return job_id;
1412 }
1413
1414 typedef struct {
1415 GdaConnection *cnc;
1416 GdaDataModel *model;
1417 } RerunSelectData;
1418
1419 /* executed in @bcnc->priv->wrapper's sub thread */
1420 static gpointer
wrapper_rerun_select(RerunSelectData * data,GError ** error)1421 wrapper_rerun_select (RerunSelectData *data, GError **error)
1422 {
1423 gboolean retval;
1424
1425 retval = gda_data_select_rerun (GDA_DATA_SELECT (data->model), error);
1426 return retval ? data->model : (gpointer) 0x01;
1427 }
1428
1429 /**
1430 * browser_connection_rerun_select
1431 * @bcnc: a #BrowserConnection object
1432 * @model: a #GdaDataModel, which has to ba a #GdaDataSelect
1433 * @error: a place to store errors, or %NULL
1434 *
1435 * Re-execute @model
1436 *
1437 * Returns: a job ID, or %0 if an error occurred
1438 */
1439 guint
browser_connection_rerun_select(BrowserConnection * bcnc,GdaDataModel * model,GError ** error)1440 browser_connection_rerun_select (BrowserConnection *bcnc,
1441 GdaDataModel *model,
1442 GError **error)
1443 {
1444 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), 0);
1445 g_return_val_if_fail (GDA_IS_DATA_SELECT (model), 0);
1446
1447 RerunSelectData *data;
1448 guint job_id;
1449
1450 data = g_new0 (RerunSelectData, 1);
1451 data->cnc = bcnc->priv->cnc;
1452 data->model = model;
1453
1454 job_id = gda_thread_wrapper_execute (bcnc->priv->wrapper,
1455 (GdaThreadWrapperFunc) wrapper_rerun_select,
1456 data, (GDestroyNotify) g_free, error);
1457 if (job_id > 0)
1458 push_wrapper_job (bcnc, job_id, JOB_TYPE_STATEMENT_EXECUTE,
1459 _("Executing a query"), NULL, NULL);
1460
1461 return job_id;
1462 }
1463
1464
1465 /**
1466 * browser_connection_execution_get_result
1467 * @bcnc: a #BrowserConnection
1468 * @exec_id: the ID of the excution
1469 * @last_insert_row: a place to store the last inserted row, if any, or %NULL
1470 * @error: a place to store errors, or %NULL
1471 *
1472 * Pick up the result of the @exec_id's execution.
1473 *
1474 * Returns: the execution result, or %NULL if either an error occurred or the result is not yet ready
1475 */
1476 GObject *
browser_connection_execution_get_result(BrowserConnection * bcnc,guint exec_id,GdaSet ** last_insert_row,GError ** error)1477 browser_connection_execution_get_result (BrowserConnection *bcnc, guint exec_id,
1478 GdaSet **last_insert_row, GError **error)
1479 {
1480 StatementResult *res;
1481 guint id;
1482 GObject *retval;
1483
1484 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
1485 g_return_val_if_fail (exec_id > 0, NULL);
1486
1487 if (! bcnc->priv->executed_statements)
1488 return NULL;
1489
1490 id = exec_id;
1491 res = g_hash_table_lookup (bcnc->priv->executed_statements, &id);
1492 if (!res)
1493 return NULL;
1494
1495 retval = res->result;
1496 res->result = NULL;
1497
1498 if (last_insert_row) {
1499 *last_insert_row = res->last_inserted_row;
1500 res->last_inserted_row = NULL;
1501 }
1502
1503 if (res->error) {
1504 g_propagate_error (error, res->error);
1505 res->error = NULL;
1506 }
1507
1508 g_hash_table_remove (bcnc->priv->executed_statements, &id);
1509 /*if (GDA_IS_DATA_MODEL (retval))
1510 gda_data_model_dump (GDA_DATA_MODEL (retval), NULL);*/
1511 return retval;
1512 }
1513
1514 /**
1515 * browser_connection_job_cancel:
1516 * @bcnc: a #BrowserConnection
1517 * @job_id: the job_id to cancel
1518 *
1519 * Cancel a job, from the job ID returned by browser_connection_ldap_describe_entry()
1520 * or browser_connection_ldap_get_entry_children().
1521 */
1522 void
browser_connection_job_cancel(BrowserConnection * bcnc,guint job_id)1523 browser_connection_job_cancel (BrowserConnection *bcnc, guint job_id)
1524 {
1525 g_return_if_fail (BROWSER_IS_CONNECTION (bcnc));
1526 g_return_if_fail (job_id > 0);
1527
1528 TO_IMPLEMENT;
1529 }
1530
1531 static gboolean query_exec_fetch_cb (BrowserConnection *bcnc);
1532
1533 typedef struct {
1534 guint exec_id;
1535 gboolean need_last_insert_row;
1536 BrowserConnectionExecuteCallback callback;
1537 gpointer cb_data;
1538 } ExecCallbackData;
1539
1540 /**
1541 * browser_connection_execute_statement_cb
1542 * @bcnc: a #BrowserConnection
1543 * @stmt: a #GdaStatement
1544 * @params: a #GdaSet as parameters, or %NULL
1545 * @model_usage: how the returned data model (if any) will be used
1546 * @need_last_insert_row: %TRUE if the values of the last interted row must be computed
1547 * @callback: the function to call when statement has been executed
1548 * @data: data to pass to @callback, or %NULL
1549 * @error: a place to store errors, or %NULL
1550 *
1551 * Executes @stmt by @bcnc and calls @callback when done. This occurs in the UI thread and avoids
1552 * having to set up a waiting mechanism to call browser_connection_execution_get_result()
1553 * repeatedly.
1554 *
1555 * Returns: a job ID, or %0 if an error occurred
1556 */
1557 guint
browser_connection_execute_statement_cb(BrowserConnection * bcnc,GdaStatement * stmt,GdaSet * params,GdaStatementModelUsage model_usage,gboolean need_last_insert_row,BrowserConnectionExecuteCallback callback,gpointer data,GError ** error)1558 browser_connection_execute_statement_cb (BrowserConnection *bcnc,
1559 GdaStatement *stmt,
1560 GdaSet *params,
1561 GdaStatementModelUsage model_usage,
1562 gboolean need_last_insert_row,
1563 BrowserConnectionExecuteCallback callback,
1564 gpointer data,
1565 GError **error)
1566 {
1567 guint exec_id;
1568 g_return_val_if_fail (callback, 0);
1569
1570 exec_id = browser_connection_execute_statement (bcnc, stmt, params, model_usage,
1571 need_last_insert_row, error);
1572 if (!exec_id)
1573 return 0;
1574 ExecCallbackData *cbdata;
1575 cbdata = g_new0 (ExecCallbackData, 1);
1576 cbdata->exec_id = exec_id;
1577 cbdata->need_last_insert_row = need_last_insert_row;
1578 cbdata->callback = callback;
1579 cbdata->cb_data = data;
1580
1581 bcnc->priv->results_list = g_slist_append (bcnc->priv->results_list, cbdata);
1582 if (! bcnc->priv->results_timer_id)
1583 bcnc->priv->results_timer_id = g_timeout_add (200,
1584 (GSourceFunc) query_exec_fetch_cb,
1585 bcnc);
1586 return exec_id;
1587 }
1588
1589 /**
1590 * browser_connection_rerun_select_cb
1591 * @bcnc: a #BrowserConnection object
1592 * @model: a #GdaDataModel, which has to ba a #GdaDataSelect
1593 * @callback: the function to call when statement has been executed
1594 * @data: data to pass to @callback, or %NULL
1595 * @error: a place to store errors, or %NULL
1596 *
1597 * Re-execute @model.
1598 *
1599 * Warning: gda_data_model_freeze() and gda_data_model_thaw() should be used
1600 * before and after this call since the model will signal its changes in a thread
1601 * which is not the GUI thread.
1602 *
1603 * Returns: a job ID, or %0 if an error occurred
1604 */
1605 guint
browser_connection_rerun_select_cb(BrowserConnection * bcnc,GdaDataModel * model,BrowserConnectionExecuteCallback callback,gpointer data,GError ** error)1606 browser_connection_rerun_select_cb (BrowserConnection *bcnc,
1607 GdaDataModel *model,
1608 BrowserConnectionExecuteCallback callback,
1609 gpointer data,
1610 GError **error)
1611 {
1612 guint exec_id;
1613 g_return_val_if_fail (callback, 0);
1614
1615 exec_id = browser_connection_rerun_select (bcnc, model, error);
1616 if (!exec_id)
1617 return 0;
1618 ExecCallbackData *cbdata;
1619 cbdata = g_new0 (ExecCallbackData, 1);
1620 cbdata->exec_id = exec_id;
1621 cbdata->need_last_insert_row = FALSE;
1622 cbdata->callback = callback;
1623 cbdata->cb_data = data;
1624
1625 bcnc->priv->results_list = g_slist_append (bcnc->priv->results_list, cbdata);
1626 if (! bcnc->priv->results_timer_id)
1627 bcnc->priv->results_timer_id = g_timeout_add (200,
1628 (GSourceFunc) query_exec_fetch_cb,
1629 bcnc);
1630 return exec_id;
1631 }
1632
1633
1634 static gboolean
query_exec_fetch_cb(BrowserConnection * bcnc)1635 query_exec_fetch_cb (BrowserConnection *bcnc)
1636 {
1637 GObject *res;
1638 GError *lerror = NULL;
1639 ExecCallbackData *cbdata;
1640 GdaSet *last_inserted_row = NULL;
1641
1642 if (!bcnc->priv->results_list)
1643 goto out;
1644
1645 cbdata = (ExecCallbackData *) bcnc->priv->results_list->data;
1646
1647 if (cbdata->need_last_insert_row)
1648 res = browser_connection_execution_get_result (bcnc,
1649 cbdata->exec_id,
1650 &last_inserted_row,
1651 &lerror);
1652 else
1653 res = browser_connection_execution_get_result (bcnc,
1654 cbdata->exec_id, NULL,
1655 &lerror);
1656
1657 if (res || lerror) {
1658 cbdata->callback (bcnc, cbdata->exec_id, res, last_inserted_row, lerror, cbdata->cb_data);
1659 if (res)
1660 g_object_unref (res);
1661 if (last_inserted_row)
1662 g_object_unref (last_inserted_row);
1663 g_clear_error (&lerror);
1664
1665 bcnc->priv->results_list = g_slist_remove (bcnc->priv->results_list, cbdata);
1666 g_free (cbdata);
1667 }
1668
1669 out:
1670 if (! bcnc->priv->results_list) {
1671 bcnc->priv->results_timer_id = 0;
1672 return FALSE;
1673 }
1674 else
1675 return TRUE; /* keep timer */
1676 }
1677
1678
1679 /**
1680 * browser_connection_normalize_sql_statement
1681 * @bcnc: a #BrowserConnection
1682 * @sqlst: a #GdaSqlStatement
1683 * @error: a place to store errors, or %NULL
1684 *
1685 * See gda_sql_statement_normalize().
1686 *
1687 * Returns: %TRUE if no error occurred
1688 */
1689 gboolean
browser_connection_normalize_sql_statement(BrowserConnection * bcnc,GdaSqlStatement * sqlst,GError ** error)1690 browser_connection_normalize_sql_statement (BrowserConnection *bcnc,
1691 GdaSqlStatement *sqlst, GError **error)
1692 {
1693 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), FALSE);
1694
1695 return gda_sql_statement_normalize (sqlst, bcnc->priv->cnc, error);
1696 }
1697
1698 /**
1699 * browser_connection_check_sql_statement_validify
1700 */
1701 gboolean
browser_connection_check_sql_statement_validify(BrowserConnection * bcnc,GdaSqlStatement * sqlst,GError ** error)1702 browser_connection_check_sql_statement_validify (BrowserConnection *bcnc,
1703 GdaSqlStatement *sqlst, GError **error)
1704 {
1705 g_return_val_if_fail (sqlst, FALSE);
1706 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), FALSE);
1707
1708 /* check the structure first */
1709 if (!gda_sql_statement_check_structure (sqlst, error))
1710 return FALSE;
1711
1712 return gda_sql_statement_check_validity_m (sqlst, bcnc->priv->mstruct, error);
1713 }
1714
1715
1716
1717 /*
1718 * DOES NOT emit any signal
1719 */
1720 void
browser_connection_set_busy_state(BrowserConnection * bcnc,gboolean busy,const gchar * busy_reason)1721 browser_connection_set_busy_state (BrowserConnection *bcnc, gboolean busy, const gchar *busy_reason)
1722 {
1723 if (bcnc->priv->busy_reason) {
1724 g_free (bcnc->priv->busy_reason);
1725 bcnc->priv->busy_reason = NULL;
1726 }
1727
1728 bcnc->priv->busy = busy;
1729 if (busy_reason)
1730 bcnc->priv->busy_reason = g_strdup (busy_reason);
1731 }
1732
1733 /*
1734 *
1735 * Preferences
1736 *
1737 */
1738 #define DBTABLE_PREFERENCES_TABLE_NAME "gda_sql_dbtable_preferences"
1739 #define DBTABLE_PREFERENCES_TABLE_DESC \
1740 "<table name=\"" DBTABLE_PREFERENCES_TABLE_NAME "\"> " \
1741 " <column name=\"table_schema\" pkey=\"TRUE\"/>" \
1742 " <column name=\"table_name\" pkey=\"TRUE\"/>" \
1743 " <column name=\"table_column\" nullok=\"TRUE\" pkey=\"TRUE\"/>" \
1744 " <column name=\"att_name\"/>" \
1745 " <column name=\"att_value\"/>" \
1746 "</table>"
1747
1748 static gboolean
meta_store_addons_init(BrowserConnection * bcnc,GError ** error)1749 meta_store_addons_init (BrowserConnection *bcnc, GError **error)
1750 {
1751 GError *lerror = NULL;
1752 GdaMetaStore *store;
1753
1754 if (!bcnc->priv->cnc) {
1755 g_set_error (error, GDA_TOOLS_ERROR, GDA_TOOLS_STORED_DATA_ERROR,
1756 "%s", _("Connection not yet opened"));
1757 return FALSE;
1758 }
1759 store = gda_connection_get_meta_store (bcnc->priv->cnc);
1760 if (!gda_meta_store_schema_add_custom_object (store, DBTABLE_PREFERENCES_TABLE_DESC, &lerror)) {
1761 g_set_error (error, GDA_TOOLS_ERROR, GDA_TOOLS_STORED_DATA_ERROR,
1762 "%s", _("Can't initialize dictionary to store table preferences"));
1763 g_warning ("Can't initialize dictionary to store dbtable_preferences :%s",
1764 lerror && lerror->message ? lerror->message : "No detail");
1765 if (lerror)
1766 g_error_free (lerror);
1767 return FALSE;
1768 }
1769
1770 bcnc->priv->store_cnc = g_object_ref (gda_meta_store_get_internal_connection (store));
1771 return TRUE;
1772 }
1773
1774
1775 /**
1776 * browser_connection_set_table_column_attribute
1777 * @bcnc:
1778 * @dbo:
1779 * @column:
1780 * @attr_name: attribute name, not %NULL
1781 * @value: value to set, or %NULL to unset
1782 * @error:
1783 *
1784 *
1785 * Returns: %TRUE if no error occurred
1786 */
1787 gboolean
browser_connection_set_table_column_attribute(BrowserConnection * bcnc,GdaMetaTable * table,GdaMetaTableColumn * column,const gchar * attr_name,const gchar * value,GError ** error)1788 browser_connection_set_table_column_attribute (BrowserConnection *bcnc,
1789 GdaMetaTable *table,
1790 GdaMetaTableColumn *column,
1791 const gchar *attr_name,
1792 const gchar *value, GError **error)
1793 {
1794 GdaConnection *store_cnc;
1795
1796 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), FALSE);
1797 g_return_val_if_fail (table, FALSE);
1798 g_return_val_if_fail (column, FALSE);
1799 g_return_val_if_fail (attr_name, FALSE);
1800
1801 if (! bcnc->priv->store_cnc &&
1802 ! meta_store_addons_init (bcnc, error))
1803 return FALSE;
1804
1805 store_cnc = bcnc->priv->store_cnc;
1806 if (! gda_lockable_trylock (GDA_LOCKABLE (store_cnc))) {
1807 g_set_error (error, GDA_TOOLS_ERROR, GDA_TOOLS_STORED_DATA_ERROR,
1808 "%s", _("Can't initialize transaction to access favorites"));
1809 return FALSE;
1810 }
1811 /* begin a transaction */
1812 if (! gda_connection_begin_transaction (store_cnc, NULL, GDA_TRANSACTION_ISOLATION_UNKNOWN, NULL)) {
1813 g_set_error (error, GDA_TOOLS_ERROR, GDA_TOOLS_STORED_DATA_ERROR,
1814 "%s", _("Can't initialize transaction to access favorites"));
1815 gda_lockable_unlock (GDA_LOCKABLE (store_cnc));
1816 return FALSE;
1817 }
1818
1819 /* delete existing attribute */
1820 GdaStatement *stmt;
1821 GdaSqlBuilder *builder;
1822 GdaSet *params;
1823 GdaSqlBuilderId op_ids[4];
1824 GdaMetaDbObject *dbo = (GdaMetaDbObject *) table;
1825
1826 params = gda_set_new_inline (5, "schema", G_TYPE_STRING, dbo->obj_schema,
1827 "name", G_TYPE_STRING, dbo->obj_name,
1828 "column", G_TYPE_STRING, column->column_name,
1829 "attname", G_TYPE_STRING, attr_name,
1830 "attvalue", G_TYPE_STRING, value);
1831
1832 builder = gda_sql_builder_new (GDA_SQL_STATEMENT_DELETE);
1833 gda_sql_builder_set_table (builder, DBTABLE_PREFERENCES_TABLE_NAME);
1834 op_ids[0] = gda_sql_builder_add_cond (builder, GDA_SQL_OPERATOR_TYPE_EQ,
1835 gda_sql_builder_add_id (builder, "table_schema"),
1836 gda_sql_builder_add_param (builder, "schema", G_TYPE_STRING,
1837 FALSE), 0);
1838 op_ids[1] = gda_sql_builder_add_cond (builder, GDA_SQL_OPERATOR_TYPE_EQ,
1839 gda_sql_builder_add_id (builder, "table_name"),
1840 gda_sql_builder_add_param (builder, "name", G_TYPE_STRING,
1841 FALSE), 0);
1842 op_ids[2] = gda_sql_builder_add_cond (builder, GDA_SQL_OPERATOR_TYPE_EQ,
1843 gda_sql_builder_add_id (builder, "table_column"),
1844 gda_sql_builder_add_param (builder, "column", G_TYPE_STRING,
1845 FALSE), 0);
1846 op_ids[3] = gda_sql_builder_add_cond (builder, GDA_SQL_OPERATOR_TYPE_EQ,
1847 gda_sql_builder_add_id (builder, "att_name"),
1848 gda_sql_builder_add_param (builder, "attname", G_TYPE_STRING,
1849 FALSE), 0);
1850 gda_sql_builder_set_where (builder,
1851 gda_sql_builder_add_cond_v (builder, GDA_SQL_OPERATOR_TYPE_AND,
1852 op_ids, 4));
1853 stmt = gda_sql_builder_get_statement (builder, error);
1854 g_object_unref (G_OBJECT (builder));
1855 if (!stmt)
1856 goto err;
1857 if (gda_connection_statement_execute_non_select (store_cnc, stmt, params, NULL, error) == -1) {
1858 g_object_unref (stmt);
1859 goto err;
1860 }
1861 g_object_unref (stmt);
1862
1863 /* insert new attribute if necessary */
1864 if (value) {
1865 builder = gda_sql_builder_new (GDA_SQL_STATEMENT_INSERT);
1866 gda_sql_builder_set_table (builder, DBTABLE_PREFERENCES_TABLE_NAME);
1867 gda_sql_builder_add_field_value_id (builder,
1868 gda_sql_builder_add_id (builder, "table_schema"),
1869 gda_sql_builder_add_param (builder, "schema", G_TYPE_STRING, FALSE));
1870 gda_sql_builder_add_field_value_id (builder,
1871 gda_sql_builder_add_id (builder, "table_name"),
1872 gda_sql_builder_add_param (builder, "name", G_TYPE_STRING, FALSE));
1873 gda_sql_builder_add_field_value_id (builder,
1874 gda_sql_builder_add_id (builder, "table_column"),
1875 gda_sql_builder_add_param (builder, "column", G_TYPE_STRING, FALSE));
1876 gda_sql_builder_add_field_value_id (builder,
1877 gda_sql_builder_add_id (builder, "att_name"),
1878 gda_sql_builder_add_param (builder, "attname", G_TYPE_STRING, FALSE));
1879 gda_sql_builder_add_field_value_id (builder,
1880 gda_sql_builder_add_id (builder, "att_value"),
1881 gda_sql_builder_add_param (builder, "attvalue", G_TYPE_STRING, FALSE));
1882 stmt = gda_sql_builder_get_statement (builder, error);
1883 g_object_unref (G_OBJECT (builder));
1884 if (!stmt)
1885 goto err;
1886 if (gda_connection_statement_execute_non_select (store_cnc, stmt, params, NULL, error) == -1) {
1887 g_object_unref (stmt);
1888 goto err;
1889 }
1890 g_object_unref (stmt);
1891 }
1892
1893 if (! gda_connection_commit_transaction (store_cnc, NULL, NULL)) {
1894 g_set_error (error, GDA_TOOLS_ERROR, GDA_TOOLS_STORED_DATA_ERROR,
1895 "%s", _("Can't commit transaction to access favorites"));
1896 goto err;
1897 }
1898
1899 g_object_unref (params);
1900 gda_lockable_unlock (GDA_LOCKABLE (store_cnc));
1901 /*
1902 g_print ("%s(table=>%s, column=>%s, value=>%s)\n", __FUNCTION__, GDA_META_DB_OBJECT (table)->obj_full_name,
1903 column->column_name, value);
1904 */
1905 g_signal_emit (bcnc, browser_connection_signals [TABLE_COLUMN_PREF_CHANGED], 0,
1906 table, column, attr_name, value);
1907
1908 return TRUE;
1909
1910 err:
1911 g_object_unref (params);
1912 gda_lockable_unlock (GDA_LOCKABLE (store_cnc));
1913 gda_connection_rollback_transaction (store_cnc, NULL, NULL);
1914 return FALSE;
1915 }
1916
1917 /**
1918 * browser_connection_get_table_column_attribute
1919 * @bcnc:
1920 * @dbo:
1921 * @column: may be %NULL
1922 * @attr_name: attribute name, not %NULL
1923 * @error:
1924 *
1925 *
1926 * Returns: the requested attribute (as a new string), or %NULL if not set or if an error occurred
1927 */
1928 gchar *
browser_connection_get_table_column_attribute(BrowserConnection * bcnc,GdaMetaTable * table,GdaMetaTableColumn * column,const gchar * attr_name,GError ** error)1929 browser_connection_get_table_column_attribute (BrowserConnection *bcnc,
1930 GdaMetaTable *table,
1931 GdaMetaTableColumn *column,
1932 const gchar *attr_name,
1933 GError **error)
1934 {
1935 GdaConnection *store_cnc;
1936 gchar *retval = NULL;
1937
1938 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), FALSE);
1939 g_return_val_if_fail (table, FALSE);
1940 g_return_val_if_fail (column, FALSE);
1941 g_return_val_if_fail (attr_name, FALSE);
1942
1943 if (! bcnc->priv->store_cnc &&
1944 ! meta_store_addons_init (bcnc, error))
1945 return FALSE;
1946
1947 store_cnc = bcnc->priv->store_cnc;
1948 if (! gda_lockable_trylock (GDA_LOCKABLE (store_cnc))) {
1949 g_set_error (error, GDA_TOOLS_ERROR, GDA_TOOLS_STORED_DATA_ERROR,
1950 "%s", _("Can't initialize transaction to access favorites"));
1951 return FALSE;
1952 }
1953
1954 /* SELECT */
1955 GdaStatement *stmt;
1956 GdaSqlBuilder *builder;
1957 GdaSet *params;
1958 GdaSqlBuilderId op_ids[4];
1959 GdaDataModel *model = NULL;
1960 const GValue *cvalue;
1961 GdaMetaDbObject *dbo = (GdaMetaDbObject *) table;
1962
1963 params = gda_set_new_inline (4, "schema", G_TYPE_STRING, dbo->obj_schema,
1964 "name", G_TYPE_STRING, dbo->obj_name,
1965 "column", G_TYPE_STRING, column->column_name,
1966 "attname", G_TYPE_STRING, attr_name);
1967
1968 builder = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT);
1969 gda_sql_builder_select_add_target_id (builder,
1970 gda_sql_builder_add_id (builder, DBTABLE_PREFERENCES_TABLE_NAME),
1971 NULL);
1972 gda_sql_builder_select_add_field (builder, "att_value", NULL, NULL);
1973 op_ids[0] = gda_sql_builder_add_cond (builder, GDA_SQL_OPERATOR_TYPE_EQ,
1974 gda_sql_builder_add_id (builder, "table_schema"),
1975 gda_sql_builder_add_param (builder, "schema", G_TYPE_STRING,
1976 FALSE), 0);
1977 op_ids[1] = gda_sql_builder_add_cond (builder, GDA_SQL_OPERATOR_TYPE_EQ,
1978 gda_sql_builder_add_id (builder, "table_name"),
1979 gda_sql_builder_add_param (builder, "name", G_TYPE_STRING,
1980 FALSE), 0);
1981 op_ids[2] = gda_sql_builder_add_cond (builder, GDA_SQL_OPERATOR_TYPE_EQ,
1982 gda_sql_builder_add_id (builder, "table_column"),
1983 gda_sql_builder_add_param (builder, "column", G_TYPE_STRING,
1984 FALSE), 0);
1985 op_ids[3] = gda_sql_builder_add_cond (builder, GDA_SQL_OPERATOR_TYPE_EQ,
1986 gda_sql_builder_add_id (builder, "att_name"),
1987 gda_sql_builder_add_param (builder, "attname", G_TYPE_STRING,
1988 FALSE), 0);
1989 gda_sql_builder_set_where (builder,
1990 gda_sql_builder_add_cond_v (builder, GDA_SQL_OPERATOR_TYPE_AND,
1991 op_ids, 4));
1992 stmt = gda_sql_builder_get_statement (builder, error);
1993 g_object_unref (G_OBJECT (builder));
1994 if (!stmt)
1995 goto out;
1996
1997 model = gda_connection_statement_execute_select (store_cnc, stmt, params, error);
1998 g_object_unref (stmt);
1999 if (!model)
2000 goto out;
2001
2002 /*gda_data_model_dump (model, NULL);*/
2003 if (gda_data_model_get_n_rows (model) == 0)
2004 goto out;
2005
2006 cvalue = gda_data_model_get_value_at (model, 0, 0, error);
2007 if (cvalue)
2008 retval = g_value_dup_string (cvalue);
2009
2010 out:
2011 if (model)
2012 g_object_unref (model);
2013 g_object_unref (params);
2014 gda_lockable_unlock (GDA_LOCKABLE (store_cnc));
2015
2016 return retval;
2017 }
2018
2019 /**
2020 * browser_connection_define_ui_plugins_for_batch
2021 * @bcnc: a #BrowserConnection object
2022 * @batch: a #GdaBatch
2023 * @params: a #GdaSet (usually created with gda_batch_get_parameters())
2024 *
2025 * Calls browser_connection_define_ui_plugins_for_stmt() for each statement in @batch
2026 */
2027 void
browser_connection_define_ui_plugins_for_batch(BrowserConnection * bcnc,GdaBatch * batch,GdaSet * params)2028 browser_connection_define_ui_plugins_for_batch (BrowserConnection *bcnc, GdaBatch *batch, GdaSet *params)
2029 {
2030 g_return_if_fail (BROWSER_IS_CONNECTION (bcnc));
2031 g_return_if_fail (GDA_IS_BATCH (batch));
2032 if (!params)
2033 return;
2034 g_return_if_fail (GDA_IS_SET (params));
2035
2036 const GSList *list;
2037 for (list = gda_batch_get_statements (batch); list; list = list->next)
2038 browser_connection_define_ui_plugins_for_stmt (bcnc, GDA_STATEMENT (list->data), params);
2039 }
2040
2041 /* remark: the current ABI leaves no room to add a
2042 * validity check to the GdaSqlExpr structure, and the following test
2043 * should be done in gda_sql_expr_check_validity() once the GdaSqlExpr
2044 * has the capacity to hold the information (ie. when ABI is broken)
2045 *
2046 * The code here is a modification from the gda_sql_select_field_check_validity()
2047 * adapted for the GdaSqlExpr.
2048 */
2049 static gboolean
_gda_sql_expr_check_validity(GdaSqlExpr * expr,GdaMetaStruct * mstruct,GdaMetaDbObject ** out_validity_meta_object,GdaMetaTableColumn ** out_validity_meta_table_column,GError ** error)2050 _gda_sql_expr_check_validity (GdaSqlExpr *expr, GdaMetaStruct *mstruct,
2051 GdaMetaDbObject **out_validity_meta_object,
2052 GdaMetaTableColumn **out_validity_meta_table_column, GError **error)
2053 {
2054 GdaMetaDbObject *dbo = NULL;
2055 const gchar *field_name;
2056
2057 *out_validity_meta_object = NULL;
2058 *out_validity_meta_table_column = NULL;
2059
2060 if (! expr->value || (G_VALUE_TYPE (expr->value) != G_TYPE_STRING))
2061 return TRUE;
2062 field_name = g_value_get_string (expr->value);
2063
2064
2065 GdaSqlAnyPart *any;
2066 GdaMetaTableColumn *tcol = NULL;
2067 GValue value;
2068
2069 memset (&value, 0, sizeof (GValue));
2070 for (any = GDA_SQL_ANY_PART(expr)->parent;
2071 any && (any->type != GDA_SQL_ANY_STMT_SELECT) && (any->type != GDA_SQL_ANY_STMT_DELETE) &&
2072 (any->type != GDA_SQL_ANY_STMT_UPDATE);
2073 any = any->parent);
2074 if (!any) {
2075 /* not in a structure which can be analysed */
2076 return TRUE;
2077 }
2078
2079 switch (any->type) {
2080 case GDA_SQL_ANY_STMT_SELECT: {
2081 /* go through all the SELECT's targets to see if
2082 * there is a table with the corresponding field */
2083 GSList *targets;
2084 if (((GdaSqlStatementSelect *)any)->from) {
2085 for (targets = ((GdaSqlStatementSelect *)any)->from->targets;
2086 targets;
2087 targets = targets->next) {
2088 GdaSqlSelectTarget *target = (GdaSqlSelectTarget *) targets->data;
2089 if (!target->validity_meta_object /*&&
2090 * commented out in the current context because
2091 * browser_connection_check_sql_statement_validify() has already been
2092 * called, will need to be re-added when movind to the
2093 * gda-statement-struct.c file.
2094 *
2095 * !gda_sql_select_target_check_validity (target, data, error)*/)
2096 return FALSE;
2097
2098 g_value_set_string (g_value_init (&value, G_TYPE_STRING), field_name);
2099 tcol = gda_meta_struct_get_table_column (mstruct,
2100 GDA_META_TABLE (target->validity_meta_object),
2101 &value);
2102 g_value_unset (&value);
2103 if (tcol) {
2104 /* found a candidate */
2105 if (dbo) {
2106 g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR,
2107 _("Could not identify table for field '%s'"), field_name);
2108 return FALSE;
2109 }
2110 dbo = target->validity_meta_object;
2111 }
2112 }
2113 }
2114 break;
2115 }
2116 case GDA_SQL_ANY_STMT_UPDATE: {
2117 GdaSqlTable *table;
2118 table = ((GdaSqlStatementUpdate *)any)->table;
2119 if (!table || !table->validity_meta_object /* ||
2120 * commented out in the current context because
2121 * browser_connection_check_sql_statement_validify() has already been
2122 * called, will need to be re-added when movind to the
2123 * gda-statement-struct.c file.
2124 *
2125 * !gda_sql_select_target_check_validity (target, data, error)*/)
2126 return FALSE;
2127 dbo = table->validity_meta_object;
2128 g_value_set_string (g_value_init (&value, G_TYPE_STRING), field_name);
2129 tcol = gda_meta_struct_get_table_column (mstruct,
2130 GDA_META_TABLE (table->validity_meta_object),
2131 &value);
2132 g_value_unset (&value);
2133 break;
2134 }
2135 case GDA_SQL_ANY_STMT_DELETE: {
2136 GdaSqlTable *table;
2137 table = ((GdaSqlStatementDelete *)any)->table;
2138 if (!table || !table->validity_meta_object /* ||
2139 * commented out in the current context because
2140 * browser_connection_check_sql_statement_validify() has already been
2141 * called, will need to be re-added when movind to the
2142 * gda-statement-struct.c file.
2143 *
2144 * !gda_sql_select_target_check_validity (target, data, error)*/)
2145 return FALSE;
2146 dbo = table->validity_meta_object;
2147 g_value_set_string (g_value_init (&value, G_TYPE_STRING), field_name);
2148 tcol = gda_meta_struct_get_table_column (mstruct,
2149 GDA_META_TABLE (table->validity_meta_object),
2150 &value);
2151 g_value_unset (&value);
2152 break;
2153 }
2154 default:
2155 g_assert_not_reached ();
2156 break;
2157 }
2158
2159 if (!dbo) {
2160 g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR,
2161 _("Could not identify table for field '%s'"), field_name);
2162 return FALSE;
2163 }
2164 *out_validity_meta_object = dbo;
2165 *out_validity_meta_table_column = tcol;
2166 return TRUE;
2167 }
2168
2169 typedef struct {
2170 BrowserConnection *bcnc;
2171 GdaSet *params;
2172 } ParamsData;
2173
2174 /*
2175 *
2176 * In this function we try to find for which table's column a parameter is and use
2177 * preferences to set the GdaHolder's plugin attribute
2178 */
2179 static gboolean
foreach_ui_plugins_for_params(GdaSqlAnyPart * part,ParamsData * data,G_GNUC_UNUSED GError ** error)2180 foreach_ui_plugins_for_params (GdaSqlAnyPart *part, ParamsData *data, G_GNUC_UNUSED GError **error)
2181 {
2182 if (part->type != GDA_SQL_ANY_EXPR)
2183 return TRUE;
2184 GdaSqlExpr *expr = (GdaSqlExpr*) part;
2185 if (!expr->param_spec)
2186 return TRUE;
2187
2188 GdaHolder *holder;
2189 holder = gda_set_get_holder (data->params, expr->param_spec->name);
2190 if (! holder)
2191 return TRUE;
2192
2193 GdaSqlAnyPart *uppart;
2194 gchar *plugin = NULL;
2195 uppart = part->parent;
2196 if (!uppart)
2197 return TRUE;
2198 else if (uppart->type == GDA_SQL_ANY_SQL_OPERATION) {
2199 GdaSqlOperation *op = (GdaSqlOperation*) uppart;
2200 /* look into condition */
2201 GSList *list;
2202 for (list = op->operands; list; list = list->next) {
2203 GdaSqlExpr *oexpr = (GdaSqlExpr*) list->data;
2204 if (oexpr == expr)
2205 continue;
2206
2207 GdaMetaDbObject *validity_meta_object;
2208 GdaMetaTableColumn *validity_meta_table_column;
2209 if (_gda_sql_expr_check_validity (oexpr,
2210 browser_connection_get_meta_struct (data->bcnc),
2211 &validity_meta_object,
2212 &validity_meta_table_column, NULL)) {
2213 plugin = browser_connection_get_table_column_attribute (data->bcnc,
2214 GDA_META_TABLE (validity_meta_object),
2215 validity_meta_table_column,
2216 BROWSER_CONNECTION_COLUMN_PLUGIN, NULL);
2217 break;
2218 }
2219 }
2220 }
2221 else if (uppart->type == GDA_SQL_ANY_STMT_UPDATE) {
2222 GdaSqlStatementUpdate *upd = (GdaSqlStatementUpdate*) uppart;
2223 GdaSqlField *field;
2224 field = g_slist_nth_data (upd->fields_list, g_slist_index (upd->expr_list, expr));
2225 if (field)
2226 plugin = browser_connection_get_table_column_attribute (data->bcnc,
2227 GDA_META_TABLE (upd->table->validity_meta_object),
2228 field->validity_meta_table_column,
2229 BROWSER_CONNECTION_COLUMN_PLUGIN, NULL);
2230 }
2231 else if (uppart->type == GDA_SQL_ANY_STMT_INSERT) {
2232 GdaSqlStatementInsert *ins = (GdaSqlStatementInsert*) uppart;
2233 GdaSqlField *field;
2234 gint expr_index = -1;
2235 GSList *slist;
2236 GdaMetaTableColumn *column = NULL;
2237 for (slist = ins->values_list; slist; slist = slist->next) {
2238 expr_index = g_slist_index ((GSList*) slist->data, expr);
2239 if (expr_index >= 0)
2240 break;
2241 }
2242 if (expr_index >= 0) {
2243 field = g_slist_nth_data (ins->fields_list, expr_index);
2244 if (field)
2245 column = field->validity_meta_table_column;
2246 else {
2247 /* no field specified => take the table's fields */
2248 GdaMetaTable *mtable = GDA_META_TABLE (ins->table->validity_meta_object);
2249 column = g_slist_nth_data (mtable->columns, expr_index);
2250 }
2251 }
2252 if (column)
2253 plugin = browser_connection_get_table_column_attribute (data->bcnc,
2254 GDA_META_TABLE (ins->table->validity_meta_object),
2255 column,
2256 BROWSER_CONNECTION_COLUMN_PLUGIN, NULL);
2257 }
2258
2259 if (plugin) {
2260 /*g_print ("Using plugin [%s]\n", plugin);*/
2261 GValue *value;
2262 g_value_take_string ((value = gda_value_new (G_TYPE_STRING)), plugin);
2263 gda_holder_set_attribute_static (holder, GDAUI_ATTRIBUTE_PLUGIN, value);
2264 gda_value_free (value);
2265 }
2266
2267 return TRUE;
2268 }
2269
2270 /**
2271 * browser_connection_define_ui_plugins_for_stmt
2272 * @bcnc: a #BrowserConnection object
2273 * @stmt: a #GdaStatement
2274 * @params: a #GdaSet (usually created with gda_statement_get_parameters())
2275 *
2276 * Analyses @stmt and assign plugins to each #GdaHolder in @params according to the preferences stored
2277 * for each table's field, defined at some point using browser_connection_set_table_column_attribute().
2278 */
2279 void
browser_connection_define_ui_plugins_for_stmt(BrowserConnection * bcnc,GdaStatement * stmt,GdaSet * params)2280 browser_connection_define_ui_plugins_for_stmt (BrowserConnection *bcnc, GdaStatement *stmt, GdaSet *params)
2281 {
2282 g_return_if_fail (BROWSER_IS_CONNECTION (bcnc));
2283 g_return_if_fail (GDA_IS_STATEMENT (stmt));
2284 if (!params)
2285 return;
2286 g_return_if_fail (GDA_IS_SET (params));
2287
2288 GdaSqlStatement *sqlst;
2289 GdaSqlAnyPart *rootpart;
2290 g_object_get ((GObject*) stmt, "structure", &sqlst, NULL);
2291 g_return_if_fail (sqlst);
2292 switch (sqlst->stmt_type) {
2293 case GDA_SQL_STATEMENT_INSERT:
2294 case GDA_SQL_STATEMENT_UPDATE:
2295 case GDA_SQL_STATEMENT_DELETE:
2296 case GDA_SQL_STATEMENT_SELECT:
2297 case GDA_SQL_STATEMENT_COMPOUND:
2298 rootpart = (GdaSqlAnyPart*) sqlst->contents;
2299 break;
2300 default:
2301 rootpart = NULL;
2302 break;
2303 }
2304 GError *lerror = NULL;
2305 if (!rootpart || !browser_connection_check_sql_statement_validify (bcnc, sqlst, &lerror)) {
2306 /*g_print ("ERROR: %s\n", lerror && lerror->message ? lerror->message : "No detail");*/
2307 g_clear_error (&lerror);
2308 gda_sql_statement_free (sqlst);
2309 return;
2310 }
2311
2312 ParamsData data;
2313 data.params = params;
2314 data.bcnc = bcnc;
2315 gda_sql_any_part_foreach (rootpart, (GdaSqlForeachFunc) foreach_ui_plugins_for_params,
2316 &data, NULL);
2317
2318 gda_sql_statement_free (sqlst);
2319
2320 /* REM: we also need to handle FK tables to propose a drop down list of possible values */
2321 }
2322
2323 /**
2324 * browser_connection_keep_variables
2325 * @bcnc: a #BrowserConnection object
2326 * @set: a #GdaSet containing variables for which a copy has to be done
2327 *
2328 * Makes a copy of the variables in @set and keep them in @bcnc. Retreive them
2329 * using browser_connection_load_variables()
2330 */
2331 void
browser_connection_keep_variables(BrowserConnection * bcnc,GdaSet * set)2332 browser_connection_keep_variables (BrowserConnection *bcnc, GdaSet *set)
2333 {
2334 g_return_if_fail (BROWSER_IS_CONNECTION (bcnc));
2335 if (!set)
2336 return;
2337 g_return_if_fail (GDA_IS_SET (set));
2338
2339 if (! bcnc->priv->variables) {
2340 bcnc->priv->variables = gda_set_copy (set);
2341 return;
2342 }
2343
2344 GSList *list;
2345 for (list = set->holders; list; list = list->next) {
2346 GdaHolder *nh, *eh;
2347 nh = GDA_HOLDER (list->data);
2348 eh = gda_set_get_holder (bcnc->priv->variables, gda_holder_get_id (nh));
2349 if (eh) {
2350 if (gda_holder_get_g_type (nh) == gda_holder_get_g_type (eh)) {
2351 const GValue *cvalue;
2352 cvalue = gda_holder_get_value (nh);
2353 gda_holder_set_value (eh, cvalue, NULL);
2354 }
2355 else {
2356 gda_set_remove_holder (bcnc->priv->variables, eh);
2357 eh = gda_holder_copy (nh);
2358 gda_set_add_holder (bcnc->priv->variables, eh);
2359 g_object_unref (eh);
2360 }
2361 }
2362 else {
2363 eh = gda_holder_copy (nh);
2364 gda_set_add_holder (bcnc->priv->variables, eh);
2365 g_object_unref (eh);
2366 }
2367 }
2368 }
2369
2370 /**
2371 * browser_connection_load_variables
2372 * @bcnc: a #BrowserConnection object
2373 * @set: a #GdaSet which will in the end contain (if any) variables stored in @bcnc
2374 *
2375 * For each #GdaHolder in @set, set the value if one is available in @bcnc.
2376 */
2377 void
browser_connection_load_variables(BrowserConnection * bcnc,GdaSet * set)2378 browser_connection_load_variables (BrowserConnection *bcnc, GdaSet *set)
2379 {
2380 g_return_if_fail (BROWSER_IS_CONNECTION (bcnc));
2381 if (!set)
2382 return;
2383 g_return_if_fail (GDA_IS_SET (set));
2384
2385 if (! bcnc->priv->variables)
2386 return;
2387
2388 GSList *list;
2389 for (list = set->holders; list; list = list->next) {
2390 GdaHolder *nh, *eh;
2391 nh = GDA_HOLDER (list->data);
2392 eh = gda_set_get_holder (bcnc->priv->variables, gda_holder_get_id (nh));
2393 if (eh) {
2394 if (gda_holder_get_g_type (nh) == gda_holder_get_g_type (eh)) {
2395 const GValue *cvalue;
2396 cvalue = gda_holder_get_value (eh);
2397 gda_holder_set_value (nh, cvalue, NULL);
2398 }
2399 else if (g_value_type_transformable (gda_holder_get_g_type (eh),
2400 gda_holder_get_g_type (nh))) {
2401 const GValue *evalue;
2402 GValue *nvalue;
2403 evalue = gda_holder_get_value (eh);
2404 nvalue = gda_value_new (gda_holder_get_g_type (nh));
2405 if (g_value_transform (evalue, nvalue))
2406 gda_holder_take_value (nh, nvalue, NULL);
2407 else
2408 gda_value_free (nvalue);
2409 }
2410 }
2411 }
2412 }
2413
2414 /**
2415 * browser_connection_is_ldap:
2416 * @bcnc: a #BrowserConnection
2417 *
2418 * Returns: %TRUE if @bcnc proxies an LDAP connection
2419 */
2420 gboolean
browser_connection_is_ldap(BrowserConnection * bcnc)2421 browser_connection_is_ldap (BrowserConnection *bcnc)
2422 {
2423 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), FALSE);
2424
2425 #ifdef HAVE_LDAP
2426 return GDA_IS_LDAP_CONNECTION (bcnc->priv->cnc) ? TRUE : FALSE;
2427 #endif
2428 return FALSE;
2429 }
2430
2431 #ifdef HAVE_LDAP
2432
2433 typedef struct {
2434 GdaConnection *cnc;
2435 gchar *base_dn;
2436 gchar *attributes;
2437 gchar *filter;
2438 GdaLdapSearchScope scope;
2439 } LdapSearchData;
2440 static void
ldap_search_data_free(LdapSearchData * data)2441 ldap_search_data_free (LdapSearchData *data)
2442 {
2443 g_free (data->base_dn);
2444 g_free (data->filter);
2445 g_free (data->attributes);
2446 g_free (data);
2447 }
2448
2449 /* executed in sub @bcnc->priv->wrapper's thread */
2450 static gpointer
wrapper_ldap_search(LdapSearchData * data,GError ** error)2451 wrapper_ldap_search (LdapSearchData *data, GError **error)
2452 {
2453 GdaDataModel *model;
2454 model = gda_data_model_ldap_new (GDA_CONNECTION (data->cnc), data->base_dn,
2455 data->filter, data->attributes, data->scope);
2456 if (!model) {
2457 g_set_error (error, GDA_TOOLS_ERROR, GDA_TOOLS_INTERNAL_COMMAND_ERROR,
2458 "%s", _("Could not execute LDAP search"));
2459 return (gpointer) 0x01;
2460 }
2461 else {
2462 GdaDataModel *wrapped;
2463 wrapped = gda_data_access_wrapper_new (model);
2464 g_object_unref (model);
2465 /* force loading all the LDAP entries in memory to avoid
2466 * having the GTK thread lock on LDAP searches */
2467 gda_data_model_get_n_rows (wrapped);
2468 return wrapped;
2469 }
2470 }
2471
2472 /**
2473 * browser_connection_ldap_search:
2474 *
2475 * Executes an LDAP search. Wrapper around gda_data_model_ldap_new()
2476 *
2477 * Returns: a job ID, or %0 if an error occurred
2478 */
2479 guint
browser_connection_ldap_search(BrowserConnection * bcnc,const gchar * base_dn,const gchar * filter,const gchar * attributes,GdaLdapSearchScope scope,BrowserConnectionJobCallback callback,gpointer cb_data,GError ** error)2480 browser_connection_ldap_search (BrowserConnection *bcnc,
2481 const gchar *base_dn, const gchar *filter,
2482 const gchar *attributes, GdaLdapSearchScope scope,
2483 BrowserConnectionJobCallback callback,
2484 gpointer cb_data, GError **error)
2485 {
2486 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), 0);
2487 g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (bcnc->priv->cnc), 0);
2488
2489 LdapSearchData *data;
2490 guint job_id;
2491 data = g_new0 (LdapSearchData, 1);
2492 data->cnc = bcnc->priv->cnc;
2493 data->base_dn = g_strdup (base_dn);
2494 data->filter = g_strdup (filter);
2495 data->attributes = g_strdup (attributes);
2496 data->scope = scope;
2497
2498 job_id = gda_thread_wrapper_execute (bcnc->priv->wrapper,
2499 (GdaThreadWrapperFunc) wrapper_ldap_search,
2500 data, (GDestroyNotify) ldap_search_data_free, error);
2501 if (job_id > 0)
2502 push_wrapper_job (bcnc, job_id, JOB_TYPE_CALLBACK,
2503 _("Executing LDAP search"), callback, cb_data);
2504 return job_id;
2505 }
2506
2507
2508 typedef struct {
2509 GdaConnection *cnc;
2510 gchar *dn;
2511 gchar **attributes;
2512 } LdapData;
2513 static void
ldap_data_free(LdapData * data)2514 ldap_data_free (LdapData *data)
2515 {
2516 g_free (data->dn);
2517 if (data->attributes)
2518 g_strfreev (data->attributes);
2519 g_free (data);
2520 }
2521
2522 /* executed in sub @bcnc->priv->wrapper's thread */
2523 static gpointer
wrapper_ldap_describe_entry(LdapData * data,GError ** error)2524 wrapper_ldap_describe_entry (LdapData *data, GError **error)
2525 {
2526 GdaLdapEntry *lentry;
2527 lentry = gda_ldap_describe_entry (GDA_LDAP_CONNECTION (data->cnc), data->dn, error);
2528 return lentry ? lentry : (gpointer) 0x01;
2529 }
2530
2531 /**
2532 * browser_connection_ldap_describe_entry:
2533 * @bcnc: a #BrowserConnection
2534 * @dn: the DN of the entry to describe
2535 * @callback: the callback to execute with the results
2536 * @cb_data: a pointer to pass to @callback
2537 * @error: a place to store errors, or %NULL
2538 *
2539 * Wrapper around gda_ldap_describe_entry().
2540 *
2541 * Returns: a job ID, or %0 if an error occurred
2542 */
2543 guint
browser_connection_ldap_describe_entry(BrowserConnection * bcnc,const gchar * dn,BrowserConnectionJobCallback callback,gpointer cb_data,GError ** error)2544 browser_connection_ldap_describe_entry (BrowserConnection *bcnc, const gchar *dn,
2545 BrowserConnectionJobCallback callback,
2546 gpointer cb_data, GError **error)
2547 {
2548 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), 0);
2549 g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (bcnc->priv->cnc), 0);
2550
2551 LdapData *data;
2552 guint job_id;
2553
2554 data = g_new0 (LdapData, 1);
2555 data->cnc = bcnc->priv->cnc;
2556 data->dn = g_strdup (dn);
2557
2558 job_id = gda_thread_wrapper_execute (bcnc->priv->wrapper,
2559 (GdaThreadWrapperFunc) wrapper_ldap_describe_entry,
2560 data, (GDestroyNotify) ldap_data_free, error);
2561 if (job_id > 0)
2562 push_wrapper_job (bcnc, job_id, JOB_TYPE_CALLBACK,
2563 _("Fetching LDAP entry's attributes"), callback, cb_data);
2564
2565 return job_id;
2566 }
2567
2568 /* executed in sub @bcnc->priv->wrapper's thread */
2569 static gpointer
wrapper_ldap_get_entry_children(LdapData * data,GError ** error)2570 wrapper_ldap_get_entry_children (LdapData *data, GError **error)
2571 {
2572 GdaLdapEntry **array;
2573 array = gda_ldap_get_entry_children (GDA_LDAP_CONNECTION (data->cnc), data->dn, data->attributes, error);
2574 return array ? array : (gpointer) 0x01;
2575 }
2576
2577 /**
2578 * browser_connection_ldap_get_entry_children:
2579 * @bcnc: a #BrowserConnection
2580 * @dn: the DN of the entry to get children from
2581 * @callback: the callback to execute with the results
2582 * @cb_data: a pointer to pass to @callback
2583 * @error: a place to store errors, or %NULL
2584 *
2585 * Wrapper around gda_ldap_get_entry_children().
2586 *
2587 * Returns: a job ID, or %0 if an error occurred
2588 */
2589 guint
browser_connection_ldap_get_entry_children(BrowserConnection * bcnc,const gchar * dn,gchar ** attributes,BrowserConnectionJobCallback callback,gpointer cb_data,GError ** error)2590 browser_connection_ldap_get_entry_children (BrowserConnection *bcnc, const gchar *dn,
2591 gchar **attributes,
2592 BrowserConnectionJobCallback callback,
2593 gpointer cb_data, GError **error)
2594 {
2595 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), 0);
2596 g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (bcnc->priv->cnc), 0);
2597
2598 LdapData *data;
2599 guint job_id;
2600
2601 data = g_new0 (LdapData, 1);
2602 data->cnc = bcnc->priv->cnc;
2603 data->dn = g_strdup (dn);
2604 if (attributes) {
2605 gint i;
2606 GArray *array = NULL;
2607 for (i = 0; attributes [i]; i++) {
2608 gchar *tmp;
2609 if (! array)
2610 array = g_array_new (TRUE, FALSE, sizeof (gchar*));
2611 tmp = g_strdup (attributes [i]);
2612 g_array_append_val (array, tmp);
2613 }
2614 if (array)
2615 data->attributes = (gchar**) g_array_free (array, FALSE);
2616 }
2617
2618 job_id = gda_thread_wrapper_execute (bcnc->priv->wrapper,
2619 (GdaThreadWrapperFunc) wrapper_ldap_get_entry_children,
2620 data, (GDestroyNotify) ldap_data_free, error);
2621 if (job_id > 0)
2622 push_wrapper_job (bcnc, job_id, JOB_TYPE_CALLBACK,
2623 _("Fetching LDAP entry's children"), callback, cb_data);
2624
2625 return job_id;
2626 }
2627
2628 /**
2629 * browser_connection_ldap_icon_for_class:
2630 * @objectclass: objectClass attribute
2631 *
2632 * Returns: the correct icon, or %NULL if it could not be determined
2633 */
2634 GdkPixbuf *
browser_connection_ldap_icon_for_class(GdaLdapAttribute * objectclass)2635 browser_connection_ldap_icon_for_class (GdaLdapAttribute *objectclass)
2636 {
2637 gint type = 0;
2638 if (objectclass) {
2639 guint i;
2640 for (i = 0; i < objectclass->nb_values; i++) {
2641 const gchar *class = g_value_get_string (objectclass->values[i]);
2642 if (!class)
2643 continue;
2644 else if (!strcmp (class, "organization"))
2645 type = MAX(type, 1);
2646 else if (!strcmp (class, "groupOfNames") ||
2647 !strcmp (class, "posixGroup"))
2648 type = MAX(type, 2);
2649 else if (!strcmp (class, "account") ||
2650 !strcmp (class, "mailUser") ||
2651 !strcmp (class, "organizationalPerson") ||
2652 !strcmp (class, "person") ||
2653 !strcmp (class, "pilotPerson") ||
2654 !strcmp (class, "newPilotPerson") ||
2655 !strcmp (class, "pkiUser") ||
2656 !strcmp (class, "posixUser") ||
2657 !strcmp (class, "posixAccount") ||
2658 !strcmp (class, "residentalPerson") ||
2659 !strcmp (class, "shadowAccount") ||
2660 !strcmp (class, "strongAuthenticationUser") ||
2661 !strcmp (class, "inetOrgPerson"))
2662 type = MAX(type, 3);
2663 }
2664 }
2665
2666 switch (type) {
2667 case 0:
2668 return browser_get_pixbuf_icon (BROWSER_ICON_LDAP_ENTRY);
2669 case 1:
2670 return browser_get_pixbuf_icon (BROWSER_ICON_LDAP_ORGANIZATION);
2671 case 2:
2672 return browser_get_pixbuf_icon (BROWSER_ICON_LDAP_GROUP);
2673 case 3:
2674 return browser_get_pixbuf_icon (BROWSER_ICON_LDAP_PERSON);
2675 default:
2676 g_assert_not_reached ();
2677 }
2678 return NULL;
2679 }
2680
2681 typedef struct {
2682 BrowserConnectionJobCallback callback;
2683 gpointer cb_data;
2684 } IconTypeData;
2685
2686 static void
fetch_classes_cb(G_GNUC_UNUSED BrowserConnection * bcnc,gpointer out_result,IconTypeData * data,G_GNUC_UNUSED GError * error)2687 fetch_classes_cb (G_GNUC_UNUSED BrowserConnection *bcnc,
2688 gpointer out_result, IconTypeData *data, G_GNUC_UNUSED GError *error)
2689 {
2690 GdkPixbuf *pixbuf = NULL;
2691 if (out_result) {
2692 GdaLdapEntry *lentry = (GdaLdapEntry*) out_result;
2693 GdaLdapAttribute *attr;
2694 attr = g_hash_table_lookup (lentry->attributes_hash, "objectClass");
2695 pixbuf = browser_connection_ldap_icon_for_class (attr);
2696 gda_ldap_entry_free (lentry);
2697 }
2698 if (data->callback)
2699 data->callback (bcnc, pixbuf, data->cb_data, error);
2700
2701 g_free (data);
2702 }
2703
2704 /**
2705 * browser_connection_ldap_icon_for_dn:
2706 * @bcnc: a #BrowserConnection
2707 * @dn: the DN of the entry
2708 * @callback: the callback to execute with the results
2709 * @cb_data: a pointer to pass to @callback
2710 * @error: a place to store errors, or %NULL
2711 *
2712 * Determines the correct icon type for @dn based on which class it belongs to
2713 *
2714 * Returns: a job ID, or %0 if an error occurred
2715 */
2716 guint
browser_connection_ldap_icon_for_dn(BrowserConnection * bcnc,const gchar * dn,BrowserConnectionJobCallback callback,gpointer cb_data,GError ** error)2717 browser_connection_ldap_icon_for_dn (BrowserConnection *bcnc, const gchar *dn,
2718 BrowserConnectionJobCallback callback,
2719 gpointer cb_data, GError **error)
2720 {
2721 IconTypeData *data;
2722 guint job_id;
2723 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), 0);
2724 g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (bcnc->priv->cnc), 0);
2725 g_return_val_if_fail (dn && *dn, 0);
2726
2727 data = g_new (IconTypeData, 1);
2728 data->callback = callback;
2729 data->cb_data = cb_data;
2730 job_id = browser_connection_ldap_describe_entry (bcnc, dn,
2731 BROWSER_CONNECTION_JOB_CALLBACK (fetch_classes_cb),
2732 data, error);
2733 return job_id;
2734 }
2735
2736 /**
2737 * browser_connection_ldap_get_base_dn:
2738 * @bcnc: a #BrowserConnection
2739 *
2740 * wrapper for gda_ldap_connection_get_base_dn()
2741 *
2742 * Returns: the base DN or %NULL
2743 */
2744 const gchar *
browser_connection_ldap_get_base_dn(BrowserConnection * bcnc)2745 browser_connection_ldap_get_base_dn (BrowserConnection *bcnc)
2746 {
2747 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
2748 g_return_val_if_fail (GDA_IS_LDAP_CONNECTION (bcnc->priv->cnc), NULL);
2749
2750 return gda_ldap_connection_get_base_dn (GDA_LDAP_CONNECTION (bcnc->priv->cnc));
2751 }
2752
2753 /**
2754 * browser_connection_describe_table:
2755 * @bcnc: a #BrowserConnection
2756 * @table_name: a table name, not %NULL
2757 * @out_base_dn: (allow-none) (transfer none): a place to store the LDAP search base DN, or %NULL
2758 * @out_filter: (allow-none) (transfer none): a place to store the LDAP search filter, or %NULL
2759 * @out_attributes: (allow-none) (transfer none): a place to store the LDAP search attributes, or %NULL
2760 * @out_scope: (allow-none) (transfer none): a place to store the LDAP search scope, or %NULL
2761 * @error: a place to store errors, or %NULL
2762 */
2763 gboolean
browser_connection_describe_table(BrowserConnection * bcnc,const gchar * table_name,const gchar ** out_base_dn,const gchar ** out_filter,const gchar ** out_attributes,GdaLdapSearchScope * out_scope,GError ** error)2764 browser_connection_describe_table (BrowserConnection *bcnc, const gchar *table_name,
2765 const gchar **out_base_dn, const gchar **out_filter,
2766 const gchar **out_attributes,
2767 GdaLdapSearchScope *out_scope, GError **error)
2768 {
2769 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), FALSE);
2770 g_return_val_if_fail (browser_connection_is_ldap (bcnc), FALSE);
2771 g_return_val_if_fail (table_name && *table_name, FALSE);
2772
2773 return gda_ldap_connection_describe_table (GDA_LDAP_CONNECTION (bcnc->priv->cnc),
2774 table_name, out_base_dn, out_filter,
2775 out_attributes, out_scope, error);
2776 }
2777
2778 /**
2779 * browser_connection_get_class_info:
2780 * @bcnc: a #BrowserConnection
2781 * @classname: a class name
2782 *
2783 * proxy for gda_ldap_get_class_info.
2784 */
2785 GdaLdapClass *
browser_connection_get_class_info(BrowserConnection * bcnc,const gchar * classname)2786 browser_connection_get_class_info (BrowserConnection *bcnc, const gchar *classname)
2787 {
2788 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
2789 g_return_val_if_fail (browser_connection_is_ldap (bcnc), NULL);
2790
2791 return gda_ldap_get_class_info (GDA_LDAP_CONNECTION (bcnc->priv->cnc), classname);
2792 }
2793
2794 /**
2795 * browser_connection_get_top_classes:
2796 * @bcnc: a #BrowserConnection
2797 *
2798 * proxy for gda_ldap_get_top_classes.
2799 */
2800 const GSList *
browser_connection_get_top_classes(BrowserConnection * bcnc)2801 browser_connection_get_top_classes (BrowserConnection *bcnc)
2802 {
2803 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
2804 g_return_val_if_fail (browser_connection_is_ldap (bcnc), NULL);
2805
2806 return gda_ldap_get_top_classes (GDA_LDAP_CONNECTION (bcnc->priv->cnc));
2807 }
2808
2809 /**
2810 * browser_connection_declare_table:
2811 * @bcnc: a #BrowserConnection
2812 *
2813 * Wrapper around gda_ldap_connection_declare_table()
2814 */
2815 gboolean
browser_connection_declare_table(BrowserConnection * bcnc,const gchar * table_name,const gchar * base_dn,const gchar * filter,const gchar * attributes,GdaLdapSearchScope scope,GError ** error)2816 browser_connection_declare_table (BrowserConnection *bcnc,
2817 const gchar *table_name,
2818 const gchar *base_dn,
2819 const gchar *filter,
2820 const gchar *attributes,
2821 GdaLdapSearchScope scope,
2822 GError **error)
2823 {
2824 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), FALSE);
2825 g_return_val_if_fail (browser_connection_is_ldap (bcnc), FALSE);
2826
2827 return gda_ldap_connection_declare_table (GDA_LDAP_CONNECTION (bcnc->priv->cnc),
2828 table_name, base_dn, filter,
2829 attributes, scope, error);
2830 }
2831
2832 /**
2833 * browser_connection_undeclare_table:
2834 * @bcnc: a #BrowserConnection
2835 *
2836 * Wrapper around gda_ldap_connection_undeclare_table()
2837 */
2838 gboolean
browser_connection_undeclare_table(BrowserConnection * bcnc,const gchar * table_name,GError ** error)2839 browser_connection_undeclare_table (BrowserConnection *bcnc,
2840 const gchar *table_name,
2841 GError **error)
2842 {
2843 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), FALSE);
2844 g_return_val_if_fail (browser_connection_is_ldap (bcnc), FALSE);
2845
2846 return gda_ldap_connection_undeclare_table (GDA_LDAP_CONNECTION (bcnc->priv->cnc),
2847 table_name, error);
2848 }
2849
2850 #endif /* HAVE_LDAP */
2851