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 (&registering);
223 		if (type == 0)
224 			type = g_type_register_static (G_TYPE_OBJECT, "GdaServerProvider", &info, G_TYPE_FLAG_ABSTRACT);
225 		g_mutex_unlock (&registering);
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