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