1 /*
2  * Copyright (C) 2006 - 2008 Murray Cumming <murrayc@murrayc.com>
3  * Copyright (C) 2006 Rodrigo Moya <rodrigo@gnome-db.org>
4  * Copyright (C) 2006 - 2013 Vivien Malerba <malerba@gnome-db.org>
5  * Copyright (C) 2007 Armin Burgmeier <armin@openismus.com>
6  * Copyright (C) 2007 Daniel Espinosa <esodan@gmail.com>
7  * Copyright (C) 2010 David King <davidk@openismus.com>
8  * Copyright (C) 2010 Jonh Wendell <jwendell@gnome.org>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the
22  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
23  * Boston, MA  02110-1301, USA.
24  */
25 
26 #include <string.h>
27 #include <libgda/gda-server-provider.h>
28 #include <libgda/gda-server-provider-extra.h>
29 #include <libgda/gda-server-provider-private.h>
30 #include <libgda/gda-data-handler.h>
31 #include <libgda/gda-util.h>
32 #include <glib/gi18n-lib.h>
33 #include <libgda/sql-parser/gda-sql-parser.h>
34 
35 #include <libgda/handlers/gda-handler-numerical.h>
36 #include <libgda/handlers/gda-handler-boolean.h>
37 #include <libgda/handlers/gda-handler-time.h>
38 #include <libgda/handlers/gda-handler-string.h>
39 #include <libgda/handlers/gda-handler-type.h>
40 
41 /**
42  * gda_server_provider_internal_get_parser:
43  * @prov: a #GdaServerProvider
44  *
45  * This is a factory method to get a unique instance of a #GdaSqlParser object
46  * for each #GdaServerProvider object
47  * Don't unref it.
48  *
49  * Returns: (transfer none): a #GdaSqlParser
50  */
51 GdaSqlParser *
gda_server_provider_internal_get_parser(GdaServerProvider * prov)52 gda_server_provider_internal_get_parser (GdaServerProvider *prov)
53 {
54 	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (prov), NULL);
55 	if (prov->priv->parser)
56 		return prov->priv->parser;
57 	prov->priv->parser = gda_server_provider_create_parser (prov, NULL);
58 	if (!prov->priv->parser)
59 		prov->priv->parser = gda_sql_parser_new ();
60 	return prov->priv->parser;
61 }
62 
63 /**
64  * gda_server_provider_perform_operation_default:
65  * @provider: a #GdaServerProvider object
66  * @cnc: (allow-none): a #GdaConnection object which will be used to perform an action, or %NULL
67  * @op: a #GdaServerOperation object
68  * @error: a place to store an error, or %NULL
69  *
70  * Performs the operation described by @op, using the SQL from the rendering of the operation
71  *
72  * Returns: %TRUE if no error occurred
73  */
74 gboolean
gda_server_provider_perform_operation_default(GdaServerProvider * provider,GdaConnection * cnc,GdaServerOperation * op,GError ** error)75 gda_server_provider_perform_operation_default (GdaServerProvider *provider, GdaConnection *cnc,
76 					       GdaServerOperation *op, GError **error)
77 {
78 	gchar *sql;
79 	GdaBatch *batch;
80 	const GSList *list;
81 	gboolean retval = TRUE;
82 
83 	sql = gda_server_provider_render_operation (provider, cnc, op, error);
84 	if (!sql)
85 		return FALSE;
86 
87 	GdaSqlParser *parser;
88 	parser = gda_server_provider_internal_get_parser (provider); /* no ref held! */
89 	batch = gda_sql_parser_parse_string_as_batch (parser, sql, NULL, error);
90 	g_free (sql);
91 	if (!batch)
92 		return FALSE;
93 
94 	for (list = gda_batch_get_statements (batch); list; list = list->next) {
95 		if (gda_connection_statement_execute_non_select (cnc, GDA_STATEMENT (list->data), NULL, NULL, error) == -1) {
96 			retval = FALSE;
97 			break;
98 		}
99 	}
100 	g_object_unref (batch);
101 
102 	return retval;
103 }
104 
105 /**
106  * gda_server_provider_handler_use_default: (skip)
107  * @provider: a server provider
108  * @type: a #GType
109  *
110  * Reserved to database provider's implementations. This method defines a default data handler for
111  * @provider, and returns that #GdaDataHandler.
112  *
113  * Returns: (transfer none): a #GdaDataHandler, or %NULL
114  *
115  * Since: 5.2
116  */
117 GdaDataHandler *
gda_server_provider_handler_use_default(GdaServerProvider * provider,GType type)118 gda_server_provider_handler_use_default (GdaServerProvider *provider, GType type)
119 {
120 	GdaDataHandler *dh = NULL;
121 	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
122 	if ((type == G_TYPE_INT64) ||
123 	    (type == G_TYPE_UINT64) ||
124 	    (type == G_TYPE_DOUBLE) ||
125 	    (type == G_TYPE_INT) ||
126 	    (type == GDA_TYPE_NUMERIC) ||
127 	    (type == G_TYPE_FLOAT) ||
128 	    (type == GDA_TYPE_SHORT) ||
129 	    (type == GDA_TYPE_USHORT) ||
130 	    (type == G_TYPE_CHAR) ||
131 	    (type == G_TYPE_UCHAR) ||
132 	    (type == G_TYPE_UINT) ||
133 	    (type == G_TYPE_LONG) ||
134 	    (type == G_TYPE_ULONG)) {
135 		dh = gda_server_provider_handler_find (provider, NULL, type, NULL);
136 		if (!dh) {
137 			dh = gda_handler_numerical_new ();
138 			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_INT64, NULL);
139 			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_UINT64, NULL);
140 			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_DOUBLE, NULL);
141 			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_INT, NULL);
142 			gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_NUMERIC, NULL);
143 			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_FLOAT, NULL);
144 			gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_SHORT, NULL);
145 			gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_USHORT, NULL);
146 			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_CHAR, NULL);
147 			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_UCHAR, NULL);
148 			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_UINT, NULL);
149 			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_ULONG, NULL);
150 			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_LONG, NULL);
151 			g_object_unref (dh);
152 		}
153 	}
154         else if ((type == GDA_TYPE_BINARY) ||
155 		 (type == GDA_TYPE_BLOB)) {
156 		/* no default binary data handler, it's too database specific */
157 		dh = NULL;
158 	}
159         else if (type == G_TYPE_BOOLEAN) {
160 		dh = gda_server_provider_handler_find (provider, NULL, type, NULL);
161 		if (!dh) {
162 			dh = gda_handler_boolean_new ();
163 			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_BOOLEAN, NULL);
164 			g_object_unref (dh);
165 		}
166 	}
167 	else if ((type == GDA_TYPE_TIME) ||
168 		 (type == GDA_TYPE_TIMESTAMP) ||
169 		 (type == G_TYPE_DATE)) {
170 		/* no default time related data handler, it's too database specific */
171 		dh = NULL;
172 	}
173 	else if (type == G_TYPE_STRING) {
174 		dh = gda_server_provider_handler_find (provider, NULL, type, NULL);
175 		if (!dh) {
176 			dh = gda_handler_string_new ();
177 			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_STRING, NULL);
178 			g_object_unref (dh);
179 		}
180 	}
181 	else if (type == G_TYPE_GTYPE) {
182 		dh = gda_server_provider_handler_find (provider, NULL, type, NULL);
183 		if (!dh) {
184 			dh = gda_handler_type_new ();
185 			gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_GTYPE, NULL);
186 			g_object_unref (dh);
187 		}
188 	}
189 
190 	return dh;
191 }
192 
193 /**
194  * gda_server_provider_get_data_handler_default:
195  * @provider: a server provider.
196  * @cnc: (allow-none): a #GdaConnection object, or %NULL
197  * @type: a #GType
198  * @dbms_type: a DBMS type definition
199  *
200  * Provides the implementation when the default Libgda's data handlers must be used
201  *
202  * Returns: (transfer none): a #GdaDataHandler, or %NULL
203  *
204  * Deprecated: 5.2: use gda_server_provider_handler_use_default() instead
205  */
206 GdaDataHandler *
gda_server_provider_get_data_handler_default(GdaServerProvider * provider,G_GNUC_UNUSED GdaConnection * cnc,GType type,G_GNUC_UNUSED const gchar * dbms_type)207 gda_server_provider_get_data_handler_default (GdaServerProvider *provider, G_GNUC_UNUSED GdaConnection *cnc,
208 					      GType type, G_GNUC_UNUSED const gchar *dbms_type)
209 {
210 	return gda_server_provider_handler_use_default (provider, type);
211 }
212 
213 static gboolean
param_to_null_foreach(GdaSqlAnyPart * part,G_GNUC_UNUSED gpointer data,G_GNUC_UNUSED GError ** error)214 param_to_null_foreach (GdaSqlAnyPart *part, G_GNUC_UNUSED gpointer data, G_GNUC_UNUSED GError **error)
215 {
216 	if (part->type == GDA_SQL_ANY_EXPR) {
217 		GdaSqlExpr *expr = (GdaSqlExpr*) part;
218 		if (expr->param_spec) {
219 			GType type = expr->param_spec->g_type;
220 			gda_sql_param_spec_free (expr->param_spec);
221 			expr->param_spec = NULL;
222 
223 			if (!expr->value) {
224 				if (type != GDA_TYPE_NULL)
225 					expr->value = gda_value_new_from_string ("0", type);
226 				else
227 					g_value_set_int ((expr->value = gda_value_new (G_TYPE_INT)), 0);
228 			}
229 		}
230 	}
231 	return TRUE;
232 }
233 
234 /**
235  * gda_select_alter_select_for_empty:
236  * @stmt: a SELECT #GdaStatement
237  * @error: (allow-none): a place to store errors, or %NULL
238  *
239  * Creates a new #GdaStatement, selecting the same data as @stmt, but which always returns an
240  * empty (no row) data model. This is use dy database providers' implementations.
241  *
242  * Returns: (transfer full): a new #GdaStatement
243  */
244 GdaStatement *
gda_select_alter_select_for_empty(GdaStatement * stmt,G_GNUC_UNUSED GError ** error)245 gda_select_alter_select_for_empty (GdaStatement *stmt, G_GNUC_UNUSED GError **error)
246 {
247 	GdaStatement *estmt;
248 	GdaSqlStatement *sqlst;
249 	GdaSqlStatementSelect *stsel;
250 
251 	g_assert (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT);
252 	g_object_get (G_OBJECT (stmt), "structure", &sqlst, NULL);
253 	g_assert (sqlst);
254 
255 	if (sqlst->sql) {
256 		g_free (sqlst->sql);
257 		sqlst->sql = NULL;
258 	}
259 	stsel = (GdaSqlStatementSelect*) sqlst->contents;
260 
261 	/* set the WHERE condition to "1 = 0" */
262 	GdaSqlExpr *expr, *cond = stsel->where_cond;
263 	GdaSqlOperation *op;
264 	if (cond)
265 		gda_sql_expr_free (cond);
266 	cond = gda_sql_expr_new (GDA_SQL_ANY_PART (stsel));
267 	stsel->where_cond = cond;
268 	op = gda_sql_operation_new (GDA_SQL_ANY_PART (cond));
269 	cond->cond = op;
270 	op->operator_type = GDA_SQL_OPERATOR_TYPE_EQ;
271 	expr = gda_sql_expr_new (GDA_SQL_ANY_PART (op));
272 	op->operands = g_slist_prepend (NULL, expr);
273 	g_value_set_int ((expr->value = gda_value_new (G_TYPE_INT)), 1);
274 	expr = gda_sql_expr_new (GDA_SQL_ANY_PART (op));
275 	op->operands = g_slist_prepend (op->operands, expr);
276 	g_value_set_int ((expr->value = gda_value_new (G_TYPE_INT)), 0);
277 
278 	/* replace any selected field which has a parameter with NULL */
279 	gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stsel), (GdaSqlForeachFunc) param_to_null_foreach,
280 				  NULL, NULL);
281 
282 	/* create new statement */
283 	estmt = g_object_new (GDA_TYPE_STATEMENT, "structure", sqlst, NULL);
284 	gda_sql_statement_free (sqlst);
285 	return estmt;
286 }
287 
288 /**
289  * gda_server_provider_handler_find:
290  * @prov: a #GdaServerProvider
291  * @cnc: (allow-none): a #GdaConnection
292  * @g_type: a #GType
293  * @dbms_type: (allow-none): a database type
294  *
295  * Reserved to database provider's implementations: get the #GdaDataHandler associated to @prov
296  * for connection @cnc. You probably want to use gda_server_provider_get_data_handler_g_type().
297  *
298  * Returns: (transfer none): the requested #GdaDataHandler, or %NULL if none found
299  */
300 GdaDataHandler *
gda_server_provider_handler_find(GdaServerProvider * prov,GdaConnection * cnc,GType g_type,const gchar * dbms_type)301 gda_server_provider_handler_find (GdaServerProvider *prov, GdaConnection *cnc,
302 				  GType g_type, const gchar *dbms_type)
303 {
304 	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (prov), NULL);
305 	if (cnc)
306 		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
307 
308 	GdaDataHandler *dh;
309 	GdaServerProviderHandlerInfo info;
310 
311 	info.cnc = cnc;
312 	info.g_type = g_type;
313 	info.dbms_type = (gchar *) dbms_type;
314 	dh = g_hash_table_lookup (prov->priv->data_handlers, &info);
315 	if (!dh) {
316 		/* try without the connection specification */
317 		info.cnc = NULL;
318 		dh = g_hash_table_lookup (prov->priv->data_handlers, &info);
319 	}
320 
321 	return dh;
322 }
323 
324 void
gda_server_provider_handler_declare(GdaServerProvider * prov,GdaDataHandler * dh,GdaConnection * cnc,GType g_type,const gchar * dbms_type)325 gda_server_provider_handler_declare (GdaServerProvider *prov, GdaDataHandler *dh,
326 				     GdaConnection *cnc,
327 				     GType g_type, const gchar *dbms_type)
328 {
329 	GdaServerProviderHandlerInfo *info;
330 	g_return_if_fail (GDA_IS_SERVER_PROVIDER (prov));
331 	g_return_if_fail (GDA_IS_DATA_HANDLER (dh));
332 
333 	info = g_new (GdaServerProviderHandlerInfo, 1);
334 	info->cnc = cnc;
335 	info->g_type = g_type;
336 	info->dbms_type = dbms_type ? g_strdup (dbms_type) : NULL;
337 
338 	g_hash_table_insert (prov->priv->data_handlers, info, dh);
339 	g_object_ref (dh);
340 }
341 
342 static gboolean
handlers_clear_for_cnc_fh(GdaServerProviderHandlerInfo * key,GdaDataHandler * value,GdaConnection * cnc)343 handlers_clear_for_cnc_fh (GdaServerProviderHandlerInfo *key, GdaDataHandler *value, GdaConnection *cnc)
344 {
345 	return (key->cnc == cnc) ? TRUE : FALSE;
346 }
347 
348 /*
349  * Removes any #GdaServerProviderHandlerInfo associated to @cnc */
350 void
_gda_server_provider_handlers_clear_for_cnc(GdaServerProvider * prov,GdaConnection * cnc)351 _gda_server_provider_handlers_clear_for_cnc (GdaServerProvider *prov, GdaConnection *cnc)
352 {
353 	g_return_if_fail (GDA_IS_SERVER_PROVIDER (prov));
354 	g_return_if_fail (GDA_IS_CONNECTION (cnc));
355 	g_hash_table_foreach_remove (prov->priv->data_handlers, (GHRFunc) handlers_clear_for_cnc_fh, cnc);
356 }
357 
358 /**
359  * gda_server_provider_find_file:
360  * @prov: a #GdaServerProvider
361  * @inst_dir: directory where @prov is installed
362  * @filename: name of the file to find
363  *
364  * Finds the location of a @filename. This function should only be used by database provider's
365  * implementations
366  *
367  * Returns: (transfer full): the complete path to @filename, or %NULL if not found
368  */
369 gchar *
gda_server_provider_find_file(GdaServerProvider * prov,const gchar * inst_dir,const gchar * filename)370 gda_server_provider_find_file (GdaServerProvider *prov, const gchar *inst_dir, const gchar *filename)
371 {
372 	gchar *file = NULL;
373 	const gchar *dirname;
374 
375 	g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (prov), NULL);
376 	dirname = g_object_get_data (G_OBJECT (prov), "GDA_PROVIDER_DIR");
377 	if (dirname)
378 		file = g_build_filename (dirname, filename, NULL);
379 
380 	if (!file ||
381 	    (file && !g_file_test (file, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))) {
382 		g_free (file);
383 		file = g_build_filename (inst_dir, filename, NULL);
384 		if (! g_file_test (file, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
385 			g_free (file);
386 			file = NULL;
387 			if (dirname) {
388 				/* look in the parent dir, to handle the case where the lib is in a .libs dir */
389 				file = g_build_filename (dirname, "..", filename, NULL);
390 				if (! g_file_test (file, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
391 					g_free (file);
392 					file = NULL;
393 				}
394 			}
395 		}
396 	}
397 
398 	return file;
399 }
400 
401 /**
402  * gda_server_provider_load_file_contents:
403  * @inst_dir: directory where the database provider has been installed
404  * @data_dir: DATA directory to look for ($prefix/share)
405  * @filename: name of the file to load
406  *
407  * Loads and returns the contents of @filename, which is searched in several places
408  * This function should only be used by database provider's
409  * implementations
410  *
411  * Returns: (transfer full): a new string containing @filename's contents, or %NULL if not found or if an error occurred
412  */
413 gchar *
gda_server_provider_load_file_contents(const gchar * inst_dir,const gchar * data_dir,const gchar * filename)414 gda_server_provider_load_file_contents (const gchar *inst_dir, const gchar *data_dir, const gchar *filename)
415 {
416 	gchar *contents, *file;
417 
418 	file = g_build_filename (inst_dir, filename, NULL);
419 
420 	if (g_file_get_contents (file, &contents, NULL, NULL))
421 		goto theend;
422 
423 	g_free (file);
424 	file = g_build_filename (inst_dir, "..", filename, NULL);
425 	if (g_file_get_contents (file, &contents, NULL, NULL))
426 		goto theend;
427 
428 	g_free (file);
429 	file = g_build_filename (data_dir, filename, NULL);
430 	if (g_file_get_contents (file, &contents, NULL, NULL))
431 		goto theend;
432 
433 	g_free (file);
434 	file = g_build_filename (inst_dir, "..", "..", "..", "share", "libgda-5.0", filename, NULL);
435 	if (g_file_get_contents (file, &contents, NULL, NULL))
436 		goto theend;
437 	contents = NULL;
438 
439  theend:
440 	g_free (file);
441 	return contents;
442 }
443