1 /*
2 * Copyright (C) 2001 - 2004 Rodrigo Moya <rodrigo@gnome-db.org>
3 * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier <gonzalo@gnome-db.org>
4 * Copyright (C) 2002 Holger Thon <holger.thon@gnome-db.org>
5 * Copyright (C) 2003 Laurent Sansonetti <laurent@datarescue.be>
6 * Copyright (C) 2004 - 2005 Alan Knowles <alank@src.gnome.org>
7 * Copyright (C) 2004 Dani Baeyens <daniel.baeyens@hispalinux.es>
8 * Copyright (C) 2004 Julio M. Merino Vidal <jmmv@menta.net>
9 * Copyright (C) 2005 - 2006 Bas Driessen <bas.driessen@xobas.com>
10 * Copyright (C) 2005 - 2011 Vivien Malerba <malerba@gnome-db.org>
11 * Copyright (C) 2005 Álvaro Peña <alvaropg@telefonica.net>
12 * Copyright (C) 2007 Armin Burgmeier <armin@openismus.com>
13 * Copyright (C) 2008 Murray Cumming <murrayc@murrayc.com>
14 * Copyright (C) 2008 Przemysław Grzegorczyk <pgrzegorczyk@gmail.com>
15 * Copyright (C) 2010 David King <davidk@openismus.com>
16 * Copyright (C) 2010 Jonh Wendell <jwendell@gnome.org>
17 * Copyright (C) 2012 Daniel Espinosa <despinosa@src.gnome.org>
18 *
19 * This library is free software; you can redistribute it and/or
20 * modify it under the terms of the GNU Lesser General Public
21 * License as published by the Free Software Foundation; either
22 * version 2 of the License, or (at your option) any later version.
23 *
24 * This library is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * Lesser General Public License for more details.
28 *
29 * You should have received a copy of the GNU Lesser General Public
30 * License along with this library; if not, write to the
31 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
32 * Boston, MA 02110-1301, USA.
33 */
34
35 #include <glib.h>
36 #include <libgda/gda-server-provider.h>
37 #include <libgda/gda-server-provider-extra.h>
38 #include <libgda/gda-server-provider-private.h>
39 #include <libgda/gda-data-handler.h>
40 #include <libgda/gda-util.h>
41 #include <libgda/gda-set.h>
42 #include <sql-parser/gda-sql-parser.h>
43 #include <string.h>
44 #include <glib/gi18n-lib.h>
45 #include <libgda/gda-lockable.h>
46
47 #define CLASS(provider) (GDA_SERVER_PROVIDER_CLASS (G_OBJECT_GET_CLASS (provider)))
48
49 static void gda_server_provider_class_init (GdaServerProviderClass *klass);
50 static void gda_server_provider_init (GdaServerProvider *provider,
51 GdaServerProviderClass *klass);
52 static void gda_server_provider_finalize (GObject *object);
53
54 static void gda_server_provider_set_property (GObject *object,
55 guint param_id,
56 const GValue *value,
57 GParamSpec *pspec);
58 static void gda_server_provider_get_property (GObject *object,
59 guint param_id,
60 GValue *value,
61 GParamSpec *pspec);
62
63 static GObjectClass *parent_class = NULL;
64
65 /* properties */
66 enum {
67 PROP_0,
68 };
69
70 /* module error */
gda_server_provider_error_quark(void)71 GQuark gda_server_provider_error_quark (void)
72 {
73 static GQuark quark;
74 if (!quark)
75 quark = g_quark_from_static_string ("gda_server_provider_error");
76 return quark;
77 }
78
79 /*
80 * GdaServerProvider class implementation
81 */
82
83 static void
gda_server_provider_class_init(GdaServerProviderClass * klass)84 gda_server_provider_class_init (GdaServerProviderClass *klass)
85 {
86 GObjectClass *object_class = G_OBJECT_CLASS (klass);
87
88 parent_class = g_type_class_peek_parent (klass);
89
90 object_class->finalize = gda_server_provider_finalize;
91
92 klass->get_name = NULL;
93 klass->get_version = NULL;
94 klass->get_server_version = NULL;
95 klass->supports_feature = NULL;
96
97 klass->get_data_handler = NULL;
98 klass->get_def_dbms_type = NULL;
99 klass->escape_string = NULL;
100 klass->unescape_string = NULL;
101
102 klass->open_connection = NULL;
103 klass->close_connection = NULL;
104 klass->get_database = NULL;
105
106 klass->supports_operation = NULL;
107 klass->create_operation = NULL;
108 klass->render_operation = NULL;
109 klass->perform_operation = NULL;
110
111 klass->begin_transaction = NULL;
112 klass->commit_transaction = NULL;
113 klass->rollback_transaction = NULL;
114 klass->add_savepoint = NULL;
115 klass->rollback_savepoint = NULL;
116 klass->delete_savepoint = NULL;
117
118 klass->create_parser = NULL;
119 klass->statement_to_sql = NULL;
120 klass->statement_prepare = NULL;
121 klass->statement_execute = NULL;
122
123 klass->is_busy = NULL;
124 klass->cancel = NULL;
125 klass->handle_async = NULL;
126
127 klass->create_connection = NULL;
128 memset (&(klass->meta_funcs), 0, sizeof (GdaServerProviderMeta));
129 klass->xa_funcs = NULL;
130
131 klass->limiting_thread = GDA_SERVER_PROVIDER_UNDEFINED_LIMITING_THREAD;
132
133 /* Properties */
134 object_class->set_property = gda_server_provider_set_property;
135 object_class->get_property = gda_server_provider_get_property;
136 }
137
138 static guint
gda_server_provider_handler_info_hash_func(GdaServerProviderHandlerInfo * key)139 gda_server_provider_handler_info_hash_func (GdaServerProviderHandlerInfo *key)
140 {
141 guint hash;
142
143 hash = g_int_hash (&(key->g_type));
144 if (key->dbms_type)
145 hash += g_str_hash (key->dbms_type);
146 hash += GPOINTER_TO_UINT (key->cnc);
147
148 return hash;
149 }
150
151 static gboolean
gda_server_provider_handler_info_equal_func(GdaServerProviderHandlerInfo * a,GdaServerProviderHandlerInfo * b)152 gda_server_provider_handler_info_equal_func (GdaServerProviderHandlerInfo *a, GdaServerProviderHandlerInfo *b)
153 {
154 if ((a->g_type == b->g_type) &&
155 (a->cnc == b->cnc) &&
156 ((!a->dbms_type && !b->dbms_type) || !strcmp (a->dbms_type, b->dbms_type)))
157 return TRUE;
158 else
159 return FALSE;
160 }
161
162 static void
gda_server_provider_handler_info_free(GdaServerProviderHandlerInfo * info)163 gda_server_provider_handler_info_free (GdaServerProviderHandlerInfo *info)
164 {
165 g_free (info->dbms_type);
166 g_free (info);
167 }
168
169 static void
gda_server_provider_init(GdaServerProvider * provider,G_GNUC_UNUSED GdaServerProviderClass * klass)170 gda_server_provider_init (GdaServerProvider *provider,
171 G_GNUC_UNUSED GdaServerProviderClass *klass)
172 {
173 g_return_if_fail (GDA_IS_SERVER_PROVIDER (provider));
174
175 provider->priv = g_new0 (GdaServerProviderPrivate, 1);
176 provider->priv->data_handlers = g_hash_table_new_full ((GHashFunc) gda_server_provider_handler_info_hash_func,
177 (GEqualFunc) gda_server_provider_handler_info_equal_func,
178 (GDestroyNotify) gda_server_provider_handler_info_free,
179 (GDestroyNotify) g_object_unref);
180 }
181
182 static void
gda_server_provider_finalize(GObject * object)183 gda_server_provider_finalize (GObject *object)
184 {
185 GdaServerProvider *provider = (GdaServerProvider *) object;
186
187 g_return_if_fail (GDA_IS_SERVER_PROVIDER (provider));
188
189 /* free memory */
190 if (provider->priv) {
191 g_hash_table_destroy (provider->priv->data_handlers);
192 if (provider->priv->parser)
193 g_object_unref (provider->priv->parser);
194
195 g_free (provider->priv);
196 provider->priv = NULL;
197 }
198
199 /* chain to parent class */
200 parent_class->finalize (object);
201 }
202
203 GType
gda_server_provider_get_type(void)204 gda_server_provider_get_type (void)
205 {
206 static GType type = 0;
207
208 if (G_UNLIKELY (type == 0)) {
209 static GMutex registering;
210 static const GTypeInfo info = {
211 sizeof (GdaServerProviderClass),
212 (GBaseInitFunc) NULL,
213 (GBaseFinalizeFunc) NULL,
214 (GClassInitFunc) gda_server_provider_class_init,
215 NULL,
216 NULL,
217 sizeof (GdaServerProvider),
218 0,
219 (GInstanceInitFunc) gda_server_provider_init,
220 0
221 };
222 g_mutex_lock (®istering);
223 if (type == 0)
224 type = g_type_register_static (G_TYPE_OBJECT, "GdaServerProvider", &info, G_TYPE_FLAG_ABSTRACT);
225 g_mutex_unlock (®istering);
226 }
227
228 return type;
229 }
230
231 static void
gda_server_provider_set_property(GObject * object,guint param_id,G_GNUC_UNUSED const GValue * value,GParamSpec * pspec)232 gda_server_provider_set_property (GObject *object,
233 guint param_id,
234 G_GNUC_UNUSED const GValue *value,
235 GParamSpec *pspec) {
236 GdaServerProvider *prov;
237
238 prov = GDA_SERVER_PROVIDER (object);
239 if (prov->priv) {
240 switch (param_id) {
241 default:
242 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
243 break;
244 }
245 }
246 }
247
248 static void
gda_server_provider_get_property(GObject * object,guint param_id,G_GNUC_UNUSED GValue * value,GParamSpec * pspec)249 gda_server_provider_get_property (GObject *object,
250 guint param_id,
251 G_GNUC_UNUSED GValue *value,
252 GParamSpec *pspec) {
253 GdaServerProvider *prov;
254
255 prov = GDA_SERVER_PROVIDER (object);
256 if (prov->priv) {
257 switch (param_id) {
258 default:
259 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
260 break;
261 }
262 }
263 }
264
265 /**
266 * gda_server_provider_get_version:
267 * @provider: a #GdaServerProvider object.
268 *
269 * Get the version of the provider.
270 *
271 * Returns: (transfer none): a string containing the version identification.
272 */
273 const gchar *
gda_server_provider_get_version(GdaServerProvider * provider)274 gda_server_provider_get_version (GdaServerProvider *provider)
275 {
276 g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
277 g_return_val_if_fail (CLASS (provider)->get_version, NULL);
278
279 return CLASS (provider)->get_version (provider);
280 }
281
282 /**
283 * gda_server_provider_get_name:
284 * @provider: a #GdaServerProvider object.
285 *
286 * Get the name (identifier) of the provider
287 *
288 * Returns: (transfer none): a string containing the provider's name
289 */
290 const gchar *
gda_server_provider_get_name(GdaServerProvider * provider)291 gda_server_provider_get_name (GdaServerProvider *provider)
292 {
293 g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
294 g_return_val_if_fail (CLASS (provider)->get_name, NULL);
295
296 return CLASS (provider)->get_name (provider);
297 }
298
299 /**
300 * gda_server_provider_get_server_version:
301 * @provider: a #GdaServerProvider object.
302 * @cnc: a #GdaConnection object
303 *
304 * Get the version of the database to which the connection is opened.
305 *
306 * Returns: (transfer none): a (read only) string, or %NULL if an error occurred
307 */
308 const gchar *
gda_server_provider_get_server_version(GdaServerProvider * provider,GdaConnection * cnc)309 gda_server_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc)
310 {
311 const gchar *retval;
312 g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
313 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
314 g_return_val_if_fail (CLASS (provider)->get_server_version != NULL, NULL);
315
316 gda_lockable_lock ((GdaLockable*) cnc);
317 retval = CLASS (provider)->get_server_version (provider, cnc);
318 gda_lockable_unlock ((GdaLockable*) cnc);
319
320 return retval;
321 }
322
323 /**
324 * gda_server_provider_supports_operation:
325 * @provider: a #GdaServerProvider object
326 * @cnc: (allow-none): a #GdaConnection object which would be used to perform an action, or %NULL
327 * @type: the type of operation requested
328 * @options: (allow-none): a list of named parameters, or %NULL
329 *
330 * Tells if @provider supports the @type of operation on the @cnc connection, using the
331 * (optional) @options parameters.
332 *
333 * Returns: %TRUE if the operation is supported
334 */
335 gboolean
gda_server_provider_supports_operation(GdaServerProvider * provider,GdaConnection * cnc,GdaServerOperationType type,GdaSet * options)336 gda_server_provider_supports_operation (GdaServerProvider *provider, GdaConnection *cnc,
337 GdaServerOperationType type, GdaSet *options)
338 {
339 gboolean retval = FALSE;
340 g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
341 g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), FALSE);
342
343 if (cnc)
344 gda_lockable_lock ((GdaLockable*) cnc);
345 if (CLASS (provider)->supports_operation)
346 retval = CLASS (provider)->supports_operation (provider, cnc, type, options);
347 if (cnc)
348 gda_lockable_unlock ((GdaLockable*) cnc);
349 return retval;
350 }
351
352 typedef struct {
353 gchar *path;
354 GdaServerOperationNodeType node_type;
355 GType data_type;
356 } OpReq;
357
358 static OpReq op_req_CREATE_DB [] = {
359 {"/DB_DEF_P", GDA_SERVER_OPERATION_NODE_PARAMLIST, 0},
360 {"/DB_DEF_P/DB_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
361 {NULL, 0, 0}
362 };
363
364 static OpReq op_req_DROP_DB [] = {
365 {"/DB_DESC_P", GDA_SERVER_OPERATION_NODE_PARAMLIST, 0},
366 {"/DB_DESC_P/DB_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
367 {NULL, 0, 0}
368 };
369
370 static OpReq op_req_CREATE_TABLE [] = {
371 {"/TABLE_DEF_P", GDA_SERVER_OPERATION_NODE_PARAMLIST, 0},
372 {"/TABLE_DEF_P/TABLE_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
373 {"/FIELDS_A", GDA_SERVER_OPERATION_NODE_DATA_MODEL, 0},
374 {"/FIELDS_A/@COLUMN_NAME", GDA_SERVER_OPERATION_NODE_DATA_MODEL_COLUMN, G_TYPE_STRING},
375 {"/FIELDS_A/@COLUMN_TYPE", GDA_SERVER_OPERATION_NODE_DATA_MODEL_COLUMN, G_TYPE_STRING},
376 {NULL, 0, 0}
377 };
378
379 static OpReq op_req_DROP_TABLE [] = {
380 {"/TABLE_DESC_P/TABLE_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
381 {NULL, 0, 0}
382 };
383
384 static OpReq op_req_RENAME_TABLE [] = {
385 {"/TABLE_DESC_P", GDA_SERVER_OPERATION_NODE_PARAMLIST, 0},
386 {"/TABLE_DESC_P/TABLE_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
387 {"/TABLE_DESC_P/TABLE_NEW_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
388 {NULL, 0, 0}
389 };
390
391 static OpReq op_req_COMMENT_TABLE [] = {
392 {"/TABLE_DESC_P", GDA_SERVER_OPERATION_NODE_PARAMLIST, 0},
393 {"/TABLE_DESC_P/TABLE_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
394 {"/TABLE_DESC_P/TABLE_COMMENT", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
395 {NULL, 0, 0}
396 };
397
398 static OpReq op_req_ADD_COLUMN [] = {
399 {"/COLUMN_DEF_P", GDA_SERVER_OPERATION_NODE_PARAMLIST, 0},
400 {"/COLUMN_DEF_P/TABLE_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
401 {"/COLUMN_DEF_P/COLUMN_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
402 {"/COLUMN_DEF_P/COLUMN_TYPE", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
403 {NULL, 0, 0}
404 };
405
406 static OpReq op_req_DROP_COLUMN [] = {
407 {"/COLUMN_DESC_P", GDA_SERVER_OPERATION_NODE_PARAMLIST, 0},
408 {"/COLUMN_DESC_P/TABLE_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
409 {"/COLUMN_DESC_P/COLUMN_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
410 {NULL, 0, 0}
411 };
412
413 static OpReq op_req_COMMENT_COLUMN [] = {
414 {"/COLUMN_DESC_P", GDA_SERVER_OPERATION_NODE_PARAMLIST, 0},
415 {"/COLUMN_DESC_P/TABLE_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
416 {"/COLUMN_DESC_P/COLUMN_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
417 {"/COLUMN_DESC_P/COLUMN_COMMENT", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
418 {NULL, 0, 0}
419 };
420
421 static OpReq op_req_CREATE_INDEX [] = {
422 {"/INDEX_DEF_P/INDEX_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
423 {"/INDEX_DEF_P/INDEX_ON_TABLE", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
424 {"/INDEX_FIELDS_S", GDA_SERVER_OPERATION_NODE_SEQUENCE, 0},
425 {NULL, 0, 0}
426 };
427
428 static OpReq op_req_DROP_INDEX [] = {
429 {"/INDEX_DESC_P/INDEX_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
430 {NULL, 0, 0}
431 };
432
433 static OpReq op_req_CREATE_VIEW [] = {
434 {"/VIEW_DEF_P", GDA_SERVER_OPERATION_NODE_PARAMLIST, 0},
435 {"/VIEW_DEF_P/VIEW_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
436 {"/VIEW_DEF_P/VIEW_DEF", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
437 {NULL, 0, 0}
438 };
439
440 static OpReq op_req_DROP_VIEW [] = {
441 {"/VIEW_DESC_P/VIEW_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
442 {NULL, 0, 0}
443 };
444
445 static OpReq op_req_CREATE_USER [] = {
446 {"/USER_DEF_P", GDA_SERVER_OPERATION_NODE_PARAMLIST, 0},
447 {"/USER_DEF_P/USER_NAME", GDA_SERVER_OPERATION_NODE_PARAM, G_TYPE_STRING},
448 {NULL, 0, 0}
449 };
450
451
452 /**
453 * gda_server_provider_create_operation:
454 * @provider: a #GdaServerProvider object
455 * @cnc: (allow-none): a #GdaConnection object which will be used to perform an action, or %NULL
456 * @type: the type of operation requested
457 * @options: (allow-none): a list of parameters or %NULL
458 * @error: (allow-none): a place to store an error, or %NULL
459 *
460 * Creates a new #GdaServerOperation object which can be modified in order to perform the @type type of
461 * action. The @options can contain:
462 * <itemizedlist>
463 * <listitem>named values which ID is a path in the resulting GdaServerOperation object, to initialize some value</listitem>
464 * <listitem>named values which may change the contents of the GdaServerOperation, see <link linkend="gda-server-op-information-std">this section</link> for more information</listitem>
465 * </itemizedlist>
466 *
467 * Returns: (transfer full) (allow-none): a new #GdaServerOperation object, or %NULL in the provider does not support the @type type of operation or if an error occurred
468 */
469 GdaServerOperation *
gda_server_provider_create_operation(GdaServerProvider * provider,GdaConnection * cnc,GdaServerOperationType type,GdaSet * options,GError ** error)470 gda_server_provider_create_operation (GdaServerProvider *provider, GdaConnection *cnc,
471 GdaServerOperationType type,
472 GdaSet *options, GError **error)
473 {
474 static GMutex init_mutex;
475 static OpReq **op_req_table = NULL;
476
477 g_mutex_lock (&init_mutex);
478 if (! op_req_table) {
479 op_req_table = g_new0 (OpReq *, GDA_SERVER_OPERATION_LAST);
480
481 op_req_table [GDA_SERVER_OPERATION_CREATE_DB] = op_req_CREATE_DB;
482 op_req_table [GDA_SERVER_OPERATION_DROP_DB] = op_req_DROP_DB;
483
484 op_req_table [GDA_SERVER_OPERATION_CREATE_TABLE] = op_req_CREATE_TABLE;
485 op_req_table [GDA_SERVER_OPERATION_DROP_TABLE] = op_req_DROP_TABLE;
486 op_req_table [GDA_SERVER_OPERATION_RENAME_TABLE] = op_req_RENAME_TABLE;
487
488 op_req_table [GDA_SERVER_OPERATION_ADD_COLUMN] = op_req_ADD_COLUMN;
489 op_req_table [GDA_SERVER_OPERATION_DROP_COLUMN] = op_req_DROP_COLUMN;
490
491 op_req_table [GDA_SERVER_OPERATION_CREATE_INDEX] = op_req_CREATE_INDEX;
492 op_req_table [GDA_SERVER_OPERATION_DROP_INDEX] = op_req_DROP_INDEX;
493
494 op_req_table [GDA_SERVER_OPERATION_CREATE_VIEW] = op_req_CREATE_VIEW;
495 op_req_table [GDA_SERVER_OPERATION_DROP_VIEW] = op_req_DROP_VIEW;
496
497 op_req_table [GDA_SERVER_OPERATION_COMMENT_TABLE] = op_req_COMMENT_TABLE;
498 op_req_table [GDA_SERVER_OPERATION_COMMENT_COLUMN] = op_req_COMMENT_COLUMN;
499
500 op_req_table [GDA_SERVER_OPERATION_CREATE_USER] = op_req_CREATE_USER;
501 }
502 g_mutex_unlock (&init_mutex);
503
504 g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
505 g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), FALSE);
506
507 if (CLASS (provider)->create_operation) {
508 GdaServerOperation *op;
509
510 if (cnc)
511 gda_lockable_lock ((GdaLockable*) cnc);
512 op = CLASS (provider)->create_operation (provider, cnc, type, options, error);
513 if (op) {
514 /* test op's conformance */
515 OpReq *opreq = op_req_table [type];
516 while (opreq && opreq->path) {
517 GdaServerOperationNodeType node_type;
518 node_type = gda_server_operation_get_node_type (op, opreq->path, NULL);
519 if (node_type == GDA_SERVER_OPERATION_NODE_UNKNOWN)
520 g_warning (_("Provider %s created a GdaServerOperation without node for '%s'"),
521 gda_server_provider_get_name (provider), opreq->path);
522 else
523 if (node_type != opreq->node_type)
524 g_warning (_("Provider %s created a GdaServerOperation with wrong node type for '%s'"),
525 gda_server_provider_get_name (provider), opreq->path);
526 opreq += 1;
527 }
528
529 if (options) {
530 /* pre-init parameters depending on the @options argument */
531 GSList *list;
532 xmlNodePtr top, node;
533
534 top = xmlNewNode (NULL, BAD_CAST "serv_op_data");
535 for (list = options->holders; list; list = list->next) {
536 const gchar *id;
537 gchar *str = NULL;
538 const GValue *value;
539
540 id = gda_holder_get_id (GDA_HOLDER (list->data));
541 value = gda_holder_get_value (GDA_HOLDER (list->data));
542 if (value)
543 str = gda_value_stringify (value);
544 node = xmlNewTextChild (top, NULL, BAD_CAST "op_data", BAD_CAST str);
545 g_free (str);
546 xmlSetProp (node, BAD_CAST "path", BAD_CAST id);
547 }
548
549 if (! gda_server_operation_load_data_from_xml (op, top, error))
550 g_warning ("Incorrect options");
551 xmlFreeNode (top);
552 }
553 }
554 if (cnc)
555 gda_lockable_unlock ((GdaLockable*) cnc);
556 return op;
557 }
558 else
559 return NULL;
560 }
561
562 /**
563 * gda_server_provider_render_operation:
564 * @provider: a #GdaServerProvider object
565 * @cnc: (allow-none): a #GdaConnection object which will be used to render the action, or %NULL
566 * @op: a #GdaServerOperation object
567 * @error: (allow-none): a place to store an error, or %NULL
568 *
569 * Creates an SQL statement (possibly using some specific extensions of the DBMS) corresponding to the
570 * @op operation. Note that the returned string may actually contain more than one SQL statement.
571 *
572 * This function's purpose is mainly informative to get the actual SQL code which would be executed to perform
573 * the operation; to actually perform the operation, use gda_server_provider_perform_operation().
574 *
575 * Returns: (transfer full) (allow-none): a new string, or %NULL if an error occurred or operation cannot be rendered as SQL.
576 */
577 gchar *
gda_server_provider_render_operation(GdaServerProvider * provider,GdaConnection * cnc,GdaServerOperation * op,GError ** error)578 gda_server_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc,
579 GdaServerOperation *op, GError **error)
580 {
581 g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
582 g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
583
584 if (CLASS (provider)->render_operation) {
585 gchar *retval;
586 if (cnc)
587 gda_lockable_lock ((GdaLockable*) cnc);
588 retval = CLASS (provider)->render_operation (provider, cnc, op, error);
589 if (cnc)
590 gda_lockable_unlock ((GdaLockable*) cnc);
591 return retval;
592 }
593 else
594 return NULL;
595 }
596
597 /**
598 * gda_server_provider_perform_operation:
599 * @provider: a #GdaServerProvider object
600 * @cnc: (allow-none): a #GdaConnection object which will be used to perform the action, or %NULL
601 * @op: a #GdaServerOperation object
602 * @error: (allow-none): a place to store an error, or %NULL
603 *
604 * Performs the operation described by @op. Note that @op is not destroyed by this method
605 * and can be reused.
606 *
607 * Returns: %TRUE if no error occurred
608 */
609 gboolean
gda_server_provider_perform_operation(GdaServerProvider * provider,GdaConnection * cnc,GdaServerOperation * op,GError ** error)610 gda_server_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
611 GdaServerOperation *op, GError **error)
612 {
613 gboolean retval;
614 g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
615 g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), FALSE);
616
617 #ifdef GDA_DEBUG_NO
618 {
619 g_print ("Perform GdaServerOperation:\n");
620 xmlNodePtr node;
621 node = gda_server_operation_save_data_to_xml (op, NULL);
622 xmlDocPtr doc;
623 doc = xmlNewDoc ("1.0");
624 xmlDocSetRootElement (doc, node);
625 xmlDocDump (stdout, doc);
626 xmlFreeDoc (doc);
627 }
628 #endif
629 if (cnc)
630 gda_lockable_lock ((GdaLockable*) cnc);
631 if (CLASS (provider)->perform_operation)
632 retval = CLASS (provider)->perform_operation (provider, cnc, op, NULL, NULL, NULL, error);
633 else
634 retval = gda_server_provider_perform_operation_default (provider, cnc, op, error);
635 if (cnc)
636 gda_lockable_unlock ((GdaLockable*) cnc);
637 return retval;
638 }
639
640 /**
641 * gda_server_provider_supports_feature:
642 * @provider: a #GdaServerProvider object
643 * @cnc: (allow-none): a #GdaConnection object, or %NULL
644 * @feature: #GdaConnectionFeature feature to test
645 *
646 * Tests if a feature is supported
647 *
648 * Returns: %TRUE if @feature is supported
649 */
650 gboolean
gda_server_provider_supports_feature(GdaServerProvider * provider,GdaConnection * cnc,GdaConnectionFeature feature)651 gda_server_provider_supports_feature (GdaServerProvider *provider, GdaConnection *cnc,
652 GdaConnectionFeature feature)
653 {
654 gboolean retval = FALSE;
655
656 g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
657 g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), FALSE);
658
659 if (feature == GDA_CONNECTION_FEATURE_ASYNC_EXEC)
660 return CLASS(provider)->handle_async ? TRUE : FALSE;;
661
662 if (cnc)
663 gda_lockable_lock ((GdaLockable*) cnc);
664 if (CLASS (provider)->supports_feature)
665 retval = CLASS (provider)->supports_feature (provider, cnc, feature);
666
667 if (retval) {
668 switch (feature) {
669 case GDA_CONNECTION_FEATURE_TRANSACTIONS:
670 if (!CLASS (provider)->begin_transaction ||
671 !CLASS (provider)->commit_transaction ||
672 !CLASS (provider)->rollback_transaction)
673 retval = FALSE;
674 break;
675 case GDA_CONNECTION_FEATURE_SAVEPOINTS:
676 if (!CLASS (provider)->add_savepoint ||
677 !CLASS (provider)->rollback_savepoint)
678 retval = FALSE;
679 break;
680 case GDA_CONNECTION_FEATURE_SAVEPOINTS_REMOVE:
681 if (!CLASS (provider)->delete_savepoint)
682 retval = FALSE;
683 break;
684 default:
685 break;
686 }
687 }
688 if (cnc)
689 gda_lockable_unlock ((GdaLockable*) cnc);
690 return retval;
691 }
692
693 /**
694 * gda_server_provider_get_data_handler_g_type:
695 * @provider: a server provider.
696 * @cnc: (allow-none): a #GdaConnection object, or %NULL
697 * @for_type: a #GType
698 *
699 * Find a #GdaDataHandler object to manipulate data of type @for_type. The returned object must not be modified.
700 *
701 * Returns: (transfer none): a #GdaDataHandler, or %NULL if the provider does not support the requested @for_type data type
702 */
703 GdaDataHandler *
gda_server_provider_get_data_handler_g_type(GdaServerProvider * provider,GdaConnection * cnc,GType for_type)704 gda_server_provider_get_data_handler_g_type (GdaServerProvider *provider, GdaConnection *cnc, GType for_type)
705 {
706 GdaDataHandler *retval = NULL;
707 g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
708 g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
709
710 if (cnc)
711 gda_lockable_lock ((GdaLockable*) cnc);
712 if (CLASS (provider)->get_data_handler)
713 retval = CLASS (provider)->get_data_handler (provider, cnc, for_type, NULL);
714 else
715 retval = gda_server_provider_handler_use_default (provider, for_type);
716 if (cnc)
717 gda_lockable_unlock ((GdaLockable*) cnc);
718 return retval;
719 }
720
721 /**
722 * gda_server_provider_get_data_handler_dbms:
723 * @provider: a server provider.
724 * @cnc: (allow-none): a #GdaConnection object, or %NULL
725 * @for_type: a DBMS type definition
726 *
727 * Find a #GdaDataHandler object to manipulate data of type @for_type.
728 *
729 * Note: this function is currently very poorly implemented by database providers.
730 *
731 * Returns: (transfer none): a #GdaDataHandler, or %NULL if the provider does not know about the @for_type type
732 */
733 GdaDataHandler *
gda_server_provider_get_data_handler_dbms(GdaServerProvider * provider,GdaConnection * cnc,const gchar * for_type)734 gda_server_provider_get_data_handler_dbms (GdaServerProvider *provider, GdaConnection *cnc, const gchar *for_type)
735 {
736 GdaDataHandler *retval = NULL;
737 g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
738 g_return_val_if_fail (for_type && *for_type, NULL);
739 g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
740
741 if (cnc)
742 gda_lockable_lock ((GdaLockable*) cnc);
743 if (CLASS (provider)->get_data_handler)
744 retval = CLASS (provider)->get_data_handler (provider, cnc, G_TYPE_INVALID, for_type);
745 if (cnc)
746 gda_lockable_unlock ((GdaLockable*) cnc);
747 return retval;
748 }
749
750 /**
751 * gda_server_provider_get_default_dbms_type:
752 * @provider: a server provider.
753 * @cnc: (allow-none): a #GdaConnection object or %NULL
754 * @type: a #GType value type
755 *
756 * Get the name of the most common data type which has @type type.
757 *
758 * The returned value may be %NULL either if the provider does not implement that method, or if
759 * there is no DBMS data type which could contain data of the @g_type type (for example %NULL may be
760 * returned if a DBMS has integers only up to 4 bytes and a #G_TYPE_INT64 is requested).
761 *
762 * Returns: (transfer none) (allow-none): the name of the DBMS type, or %NULL
763 */
764 const gchar *
gda_server_provider_get_default_dbms_type(GdaServerProvider * provider,GdaConnection * cnc,GType type)765 gda_server_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConnection *cnc, GType type)
766 {
767 const gchar *retval = NULL;
768 g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
769 g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
770
771 if (CLASS (provider)->get_def_dbms_type) {
772 if (cnc)
773 gda_lockable_lock ((GdaLockable*) cnc);
774 retval = (CLASS (provider)->get_def_dbms_type) (provider, cnc, type);
775 if (cnc)
776 gda_lockable_unlock ((GdaLockable*) cnc);
777 }
778
779 return retval;
780 }
781
782
783 /**
784 * gda_server_provider_string_to_value:
785 * @provider: a server provider.
786 * @cnc: (allow-none): a #GdaConnection object, or %NULL
787 * @string: the SQL string to convert to a value
788 * @preferred_type: a #GType, or #G_TYPE_INVALID
789 * @dbms_type: (allow-none): place to get the actual database type used if the conversion succeeded, or %NULL
790 *
791 * Use @provider to create a new #GValue from a single string representation.
792 *
793 * The @preferred_type can optionally ask @provider to return a #GValue of the requested type
794 * (but if such a value can't be created from @string, then %NULL is returned);
795 * pass #G_TYPE_INVALID if any returned type is acceptable.
796 *
797 * The returned value is either a new #GValue or %NULL in the following cases:
798 * - @string cannot be converted to @preferred_type type
799 * - the provider does not handle @preferred_type
800 * - the provider could not make a #GValue from @string
801 *
802 * If @dbms_type is not %NULL, then if will contain a constant string representing
803 * the database type used for the conversion if the conversion was successfull, or %NULL
804 * otherwise.
805 *
806 * Returns: (transfer full): a new #GValue, or %NULL
807 */
808 GValue *
gda_server_provider_string_to_value(GdaServerProvider * provider,GdaConnection * cnc,const gchar * string,GType preferred_type,gchar ** dbms_type)809 gda_server_provider_string_to_value (GdaServerProvider *provider, GdaConnection *cnc, const gchar *string,
810 GType preferred_type, gchar **dbms_type)
811 {
812 GValue *retval = NULL;
813 GdaDataHandler *dh;
814 gsize i;
815
816 g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
817 g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
818
819 if (dbms_type)
820 *dbms_type = NULL;
821
822 if (cnc)
823 gda_lockable_lock ((GdaLockable*) cnc);
824 if (preferred_type != G_TYPE_INVALID) {
825 dh = gda_server_provider_get_data_handler_g_type (provider, cnc, preferred_type);
826 if (dh) {
827 retval = gda_data_handler_get_value_from_sql (dh, string, preferred_type);
828 if (retval) {
829 gchar *tmp;
830
831 tmp = gda_data_handler_get_sql_from_value (dh, retval);
832 if (!tmp || strcmp (tmp, string)) {
833 gda_value_free (retval);
834 retval = NULL;
835 }
836 else {
837 if (dbms_type)
838 *dbms_type = (gchar *) gda_server_provider_get_default_dbms_type (provider,
839 cnc, preferred_type);
840 }
841
842 g_free (tmp);
843 }
844 }
845 }
846 else {
847 /* test all the possible data types and see if we have a match */
848 GType types[] = {G_TYPE_UCHAR,
849 GDA_TYPE_USHORT,
850 G_TYPE_UINT,
851 G_TYPE_UINT64,
852
853 G_TYPE_CHAR,
854 GDA_TYPE_SHORT,
855 G_TYPE_INT,
856 G_TYPE_INT64,
857
858 G_TYPE_FLOAT,
859 G_TYPE_DOUBLE,
860 GDA_TYPE_NUMERIC,
861
862 G_TYPE_BOOLEAN,
863 GDA_TYPE_TIME,
864 G_TYPE_DATE,
865 GDA_TYPE_TIMESTAMP,
866 GDA_TYPE_GEOMETRIC_POINT,
867 G_TYPE_STRING,
868 GDA_TYPE_BINARY};
869
870 for (i = 0; !retval && (i <= (sizeof(types)/sizeof (GType)) - 1); i++) {
871 dh = gda_server_provider_get_data_handler_g_type (provider, cnc, types [i]);
872 if (dh) {
873 retval = gda_data_handler_get_value_from_sql (dh, string, types [i]);
874 if (retval) {
875 gchar *tmp;
876
877 tmp = gda_data_handler_get_sql_from_value (dh, retval);
878 if (!tmp || strcmp (tmp, string)) {
879 gda_value_free (retval);
880 retval = NULL;
881 }
882 else {
883 if (dbms_type)
884 *dbms_type = (gchar *) gda_server_provider_get_default_dbms_type (provider,
885 cnc, types[i]);
886 }
887 g_free (tmp);
888 }
889 }
890 }
891 }
892 if (cnc)
893 gda_lockable_unlock ((GdaLockable*) cnc);
894
895 return retval;
896 }
897
898
899 /**
900 * gda_server_provider_value_to_sql_string:
901 * @provider: a server provider.
902 * @cnc: (allow-none): a #GdaConnection object, or %NULL
903 * @from: #GValue to convert from
904 *
905 * Produces a fully quoted and escaped string from a GValue
906 *
907 * Returns: (transfer full): escaped and quoted value or NULL if not supported.
908 */
909 gchar *
gda_server_provider_value_to_sql_string(GdaServerProvider * provider,GdaConnection * cnc,GValue * from)910 gda_server_provider_value_to_sql_string (GdaServerProvider *provider,
911 GdaConnection *cnc,
912 GValue *from)
913 {
914 gchar *retval = NULL;
915 GdaDataHandler *dh;
916
917 g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
918 g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
919 g_return_val_if_fail (from != NULL, NULL);
920
921 if (cnc)
922 gda_lockable_lock ((GdaLockable*) cnc);
923 dh = gda_server_provider_get_data_handler_g_type (provider, cnc, G_VALUE_TYPE (from));
924 if (dh)
925 retval = gda_data_handler_get_sql_from_value (dh, from);
926 if (cnc)
927 gda_lockable_unlock ((GdaLockable*) cnc);
928 return retval;
929 }
930
931 /**
932 * gda_server_provider_escape_string:
933 * @provider: a server provider.
934 * @cnc: (allow-none): a #GdaConnection object, or %NULL
935 * @str: a string to escape
936 *
937 * Escapes @str for use within an SQL command (to avoid SQL injection attacks). Note that the returned value still needs
938 * to be enclosed in single quotes before being used in an SQL statement.
939 *
940 * Returns: (transfer full): a new string suitable to use in SQL statements
941 */
942 gchar *
gda_server_provider_escape_string(GdaServerProvider * provider,GdaConnection * cnc,const gchar * str)943 gda_server_provider_escape_string (GdaServerProvider *provider, GdaConnection *cnc, const gchar *str)
944 {
945 g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
946 g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
947
948 if (CLASS (provider)->escape_string) {
949 gchar *retval;
950 if (! CLASS (provider)->unescape_string)
951 g_warning (_("GdaServerProvider object implements the %s virtual method but "
952 "does not implement the %s one, please report this bug to "
953 "http://bugzilla.gnome.org/ for the \"libgda\" product."),
954 "escape_string()", "unescape_string()");
955 if (cnc)
956 gda_lockable_lock ((GdaLockable*) cnc);
957 retval = (CLASS (provider)->escape_string) (provider, cnc, str);
958 if (cnc)
959 gda_lockable_unlock ((GdaLockable*) cnc);
960 return retval;
961 }
962 else
963 return gda_default_escape_string (str);
964 }
965
966 /**
967 * gda_server_provider_unescape_string:
968 * @provider: a server provider.
969 * @cnc: (allow-none): a #GdaConnection object, or %NULL
970 * @str: a string to escape
971 *
972 * Unescapes @str for use within an SQL command. This is the exact opposite of gda_server_provider_escape_string().
973 *
974 * Returns: (transfer full): a new string
975 */
976 gchar *
gda_server_provider_unescape_string(GdaServerProvider * provider,GdaConnection * cnc,const gchar * str)977 gda_server_provider_unescape_string (GdaServerProvider *provider, GdaConnection *cnc, const gchar *str)
978 {
979 g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
980 g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
981
982 if (CLASS (provider)->unescape_string) {
983 gchar *retval;
984 if (! CLASS (provider)->escape_string)
985 g_warning (_("GdaServerProvider object implements the %s virtual method but "
986 "does not implement the %s one, please report this bug to "
987 "http://bugzilla.gnome.org/ for the \"libgda\" product."),
988 "unescape_string()", "escape_string()");
989 if (cnc)
990 gda_lockable_lock ((GdaLockable*) cnc);
991 retval = (CLASS (provider)->unescape_string)(provider, cnc, str);
992 if (cnc)
993 gda_lockable_unlock ((GdaLockable*) cnc);
994 return retval;
995 }
996 else
997 return gda_default_unescape_string (str);
998 }
999
1000
1001 /**
1002 * gda_server_provider_create_parser:
1003 * @provider: a #GdaServerProvider provider object
1004 * @cnc: (allow-none): a #GdaConnection, or %NULL
1005 *
1006 * Creates a new #GdaSqlParser object which is adapted to @provider (and possibly depending on
1007 * @cnc for the actual database version).
1008 *
1009 * If @prov does not have its own parser, then %NULL is returned, and a general SQL parser can be obtained
1010 * using gda_sql_parser_new().
1011 *
1012 * Returns: (transfer full): a new #GdaSqlParser object, or %NULL.
1013 */
1014 GdaSqlParser *
gda_server_provider_create_parser(GdaServerProvider * provider,GdaConnection * cnc)1015 gda_server_provider_create_parser (GdaServerProvider *provider, GdaConnection *cnc)
1016 {
1017 GdaSqlParser *parser = NULL;
1018
1019 g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
1020 g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
1021
1022 if (CLASS (provider)->create_parser)
1023 parser = (CLASS (provider)->create_parser) (provider, cnc);
1024 return parser;
1025 }
1026
1027