1 /*
2 * Copyright (C) YEAR The GNOME Foundation.
3 *
4 * AUTHORS:
5 * TO_ADD: your name and email
6 * Vivien Malerba <malerba@gnome-db.org>
7 *
8 * This Library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This Library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this Library; see the file COPYING.LIB. If not,
20 * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <glib/gi18n-lib.h>
29 #include <glib/gstdio.h>
30 #include <libgda/libgda.h>
31 #include <libgda/gda-data-model-private.h>
32 #include <libgda/gda-server-provider-extra.h>
33 #include <libgda/binreloc/gda-binreloc.h>
34 #include <libgda/gda-statement-extra.h>
35 #include <sql-parser/gda-sql-parser.h>
36 #include "gda-capi.h"
37 #include "gda-capi-provider.h"
38 #include "gda-capi-recordset.h"
39 #include "gda-capi-ddl.h"
40 #include "gda-capi-meta.h"
41 #include <libgda/gda-debug-macros.h>
42 #define _GDA_PSTMT(x) ((GdaPStmt*)(x))
43
44 /*
45 * GObject methods
46 */
47 static void gda_capi_provider_class_init (GdaCapiProviderClass *klass);
48 static void gda_capi_provider_init (GdaCapiProvider *provider,
49 GdaCapiProviderClass *klass);
50 static GObjectClass *parent_class = NULL;
51
52 /*
53 * GdaServerProvider's virtual methods
54 */
55 /* connection management */
56 static gboolean gda_capi_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
57 GdaQuarkList *params, GdaQuarkList *auth,
58 guint *task_id, GdaServerProviderAsyncCallback async_cb, gpointer cb_data);
59 static gboolean gda_capi_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc);
60 static const gchar *gda_capi_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc);
61 static const gchar *gda_capi_provider_get_database (GdaServerProvider *provider, GdaConnection *cnc);
62
63 /* DDL operations */
64 static gboolean gda_capi_provider_supports_operation (GdaServerProvider *provider, GdaConnection *cnc,
65 GdaServerOperationType type, GdaSet *options);
66 static GdaServerOperation *gda_capi_provider_create_operation (GdaServerProvider *provider, GdaConnection *cnc,
67 GdaServerOperationType type,
68 GdaSet *options, GError **error);
69 static gchar *gda_capi_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc,
70 GdaServerOperation *op, GError **error);
71
72 static gboolean gda_capi_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
73 GdaServerOperation *op, guint *task_id,
74 GdaServerProviderAsyncCallback async_cb, gpointer cb_data,
75 GError **error);
76 /* transactions */
77 static gboolean gda_capi_provider_begin_transaction (GdaServerProvider *provider, GdaConnection *cnc,
78 const gchar *name, GdaTransactionIsolation level, GError **error);
79 static gboolean gda_capi_provider_commit_transaction (GdaServerProvider *provider, GdaConnection *cnc,
80 const gchar *name, GError **error);
81 static gboolean gda_capi_provider_rollback_transaction (GdaServerProvider *provider, GdaConnection * cnc,
82 const gchar *name, GError **error);
83 static gboolean gda_capi_provider_add_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
84 const gchar *name, GError **error);
85 static gboolean gda_capi_provider_rollback_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
86 const gchar *name, GError **error);
87 static gboolean gda_capi_provider_delete_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
88 const gchar *name, GError **error);
89
90 /* information retrieval */
91 static const gchar *gda_capi_provider_get_version (GdaServerProvider *provider);
92 static gboolean gda_capi_provider_supports_feature (GdaServerProvider *provider, GdaConnection *cnc,
93 GdaConnectionFeature feature);
94
95 static const gchar *gda_capi_provider_get_name (GdaServerProvider *provider);
96
97 static GdaDataHandler *gda_capi_provider_get_data_handler (GdaServerProvider *provider, GdaConnection *cnc,
98 GType g_type, const gchar *dbms_type);
99
100 static const gchar* gda_capi_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConnection *cnc,
101 GType type);
102 /* statements */
103 static GdaSqlParser *gda_capi_provider_create_parser (GdaServerProvider *provider, GdaConnection *cnc);
104 static gchar *gda_capi_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection *cnc,
105 GdaStatement *stmt, GdaSet *params,
106 GdaStatementSqlFlag flags,
107 GSList **params_used, GError **error);
108 static gboolean gda_capi_provider_statement_prepare (GdaServerProvider *provider, GdaConnection *cnc,
109 GdaStatement *stmt, GError **error);
110 static GObject *gda_capi_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
111 GdaStatement *stmt, GdaSet *params,
112 GdaStatementModelUsage model_usage,
113 GType *col_types, GdaSet **last_inserted_row,
114 guint *task_id, GdaServerProviderExecCallback async_cb,
115 gpointer cb_data, GError **error);
116 static GdaSqlStatement *gda_capi_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
117 GdaStatement *stmt, GdaSet *params, GError **error);
118
119
120 /* distributed transactions */
121 static gboolean gda_capi_provider_xa_start (GdaServerProvider *provider, GdaConnection *cnc,
122 const GdaXaTransactionId *xid, GError **error);
123
124 static gboolean gda_capi_provider_xa_end (GdaServerProvider *provider, GdaConnection *cnc,
125 const GdaXaTransactionId *xid, GError **error);
126 static gboolean gda_capi_provider_xa_prepare (GdaServerProvider *provider, GdaConnection *cnc,
127 const GdaXaTransactionId *xid, GError **error);
128
129 static gboolean gda_capi_provider_xa_commit (GdaServerProvider *provider, GdaConnection *cnc,
130 const GdaXaTransactionId *xid, GError **error);
131 static gboolean gda_capi_provider_xa_rollback (GdaServerProvider *provider, GdaConnection *cnc,
132 const GdaXaTransactionId *xid, GError **error);
133
134 static GList *gda_capi_provider_xa_recover (GdaServerProvider *provider, GdaConnection *cnc,
135 GError **error);
136
137 /*
138 * private connection data destroy
139 */
140 static void gda_capi_free_cnc_data (CapiConnectionData *cdata);
141
142
143 /*
144 * Prepared internal statements
145 * TO_ADD: any prepared statement to be used internally by the provider should be
146 * declared here, as constants and as SQL statements
147 */
148 static GMutex init_mutex;
149 static GdaStatement **internal_stmt = NULL;
150
151 typedef enum {
152 INTERNAL_STMT1
153 } InternalStatementItem;
154
155 static gchar *internal_sql[] = {
156 "SQL for INTERNAL_STMT1"
157 };
158
159 /*
160 * GdaCapiProvider class implementation
161 */
162 static void
gda_capi_provider_class_init(GdaCapiProviderClass * klass)163 gda_capi_provider_class_init (GdaCapiProviderClass *klass)
164 {
165 GdaServerProviderClass *provider_class = GDA_SERVER_PROVIDER_CLASS (klass);
166
167 parent_class = g_type_class_peek_parent (klass);
168
169 provider_class->get_version = gda_capi_provider_get_version;
170 provider_class->get_server_version = gda_capi_provider_get_server_version;
171 provider_class->get_name = gda_capi_provider_get_name;
172 provider_class->supports_feature = gda_capi_provider_supports_feature;
173
174 provider_class->get_data_handler = gda_capi_provider_get_data_handler;
175 provider_class->get_def_dbms_type = gda_capi_provider_get_default_dbms_type;
176
177 provider_class->open_connection = gda_capi_provider_open_connection;
178 provider_class->close_connection = gda_capi_provider_close_connection;
179 provider_class->get_database = gda_capi_provider_get_database;
180
181 provider_class->supports_operation = gda_capi_provider_supports_operation;
182 provider_class->create_operation = gda_capi_provider_create_operation;
183 provider_class->render_operation = gda_capi_provider_render_operation;
184 provider_class->perform_operation = gda_capi_provider_perform_operation;
185
186 provider_class->begin_transaction = gda_capi_provider_begin_transaction;
187 provider_class->commit_transaction = gda_capi_provider_commit_transaction;
188 provider_class->rollback_transaction = gda_capi_provider_rollback_transaction;
189 provider_class->add_savepoint = gda_capi_provider_add_savepoint;
190 provider_class->rollback_savepoint = gda_capi_provider_rollback_savepoint;
191 provider_class->delete_savepoint = gda_capi_provider_delete_savepoint;
192
193 provider_class->create_parser = gda_capi_provider_create_parser;
194 provider_class->statement_to_sql = NULL; /* don't use gda_capi_provider_statement_to_sql()
195 * because it only calls gda_statement_to_sql_extended().
196 * Set it to gda_capi_provider_statement_to_sql() if it does
197 * not call calls gda_statement_to_sql_extended() */
198 provider_class->statement_prepare = gda_capi_provider_statement_prepare;
199 provider_class->statement_execute = gda_capi_provider_statement_execute;
200 provider_class->statement_rewrite = gda_capi_statement_rewrite;
201
202 provider_class->is_busy = NULL;
203 provider_class->cancel = NULL;
204 provider_class->create_connection = NULL;
205
206 memset (&(provider_class->meta_funcs), 0, sizeof (GdaServerProviderMeta));
207 provider_class->meta_funcs._info = _gda_capi_meta__info;
208 provider_class->meta_funcs._btypes = _gda_capi_meta__btypes;
209 provider_class->meta_funcs._udt = _gda_capi_meta__udt;
210 provider_class->meta_funcs.udt = _gda_capi_meta_udt;
211 provider_class->meta_funcs._udt_cols = _gda_capi_meta__udt_cols;
212 provider_class->meta_funcs.udt_cols = _gda_capi_meta_udt_cols;
213 provider_class->meta_funcs._enums = _gda_capi_meta__enums;
214 provider_class->meta_funcs.enums = _gda_capi_meta_enums;
215 provider_class->meta_funcs._domains = _gda_capi_meta__domains;
216 provider_class->meta_funcs.domains = _gda_capi_meta_domains;
217 provider_class->meta_funcs._constraints_dom = _gda_capi_meta__constraints_dom;
218 provider_class->meta_funcs.constraints_dom = _gda_capi_meta_constraints_dom;
219 provider_class->meta_funcs._el_types = _gda_capi_meta__el_types;
220 provider_class->meta_funcs.el_types = _gda_capi_meta_el_types;
221 provider_class->meta_funcs._collations = _gda_capi_meta__collations;
222 provider_class->meta_funcs.collations = _gda_capi_meta_collations;
223 provider_class->meta_funcs._character_sets = _gda_capi_meta__character_sets;
224 provider_class->meta_funcs.character_sets = _gda_capi_meta_character_sets;
225 provider_class->meta_funcs._schemata = _gda_capi_meta__schemata;
226 provider_class->meta_funcs.schemata = _gda_capi_meta_schemata;
227 provider_class->meta_funcs._tables_views = _gda_capi_meta__tables_views;
228 provider_class->meta_funcs.tables_views = _gda_capi_meta_tables_views;
229 provider_class->meta_funcs._columns = _gda_capi_meta__columns;
230 provider_class->meta_funcs.columns = _gda_capi_meta_columns;
231 provider_class->meta_funcs._view_cols = _gda_capi_meta__view_cols;
232 provider_class->meta_funcs.view_cols = _gda_capi_meta_view_cols;
233 provider_class->meta_funcs._constraints_tab = _gda_capi_meta__constraints_tab;
234 provider_class->meta_funcs.constraints_tab = _gda_capi_meta_constraints_tab;
235 provider_class->meta_funcs._constraints_ref = _gda_capi_meta__constraints_ref;
236 provider_class->meta_funcs.constraints_ref = _gda_capi_meta_constraints_ref;
237 provider_class->meta_funcs._key_columns = _gda_capi_meta__key_columns;
238 provider_class->meta_funcs.key_columns = _gda_capi_meta_key_columns;
239 provider_class->meta_funcs._check_columns = _gda_capi_meta__check_columns;
240 provider_class->meta_funcs.check_columns = _gda_capi_meta_check_columns;
241 provider_class->meta_funcs._triggers = _gda_capi_meta__triggers;
242 provider_class->meta_funcs.triggers = _gda_capi_meta_triggers;
243 provider_class->meta_funcs._routines = _gda_capi_meta__routines;
244 provider_class->meta_funcs.routines = _gda_capi_meta_routines;
245 provider_class->meta_funcs._routine_col = _gda_capi_meta__routine_col;
246 provider_class->meta_funcs.routine_col = _gda_capi_meta_routine_col;
247 provider_class->meta_funcs._routine_par = _gda_capi_meta__routine_par;
248 provider_class->meta_funcs.routine_par = _gda_capi_meta_routine_par;
249 provider_class->meta_funcs._indexes_tab = _gda_capi_meta__indexes_tab;
250 provider_class->meta_funcs.indexes_tab = _gda_capi_meta_indexes_tab;
251 provider_class->meta_funcs._index_cols = _gda_capi_meta__index_cols;
252 provider_class->meta_funcs.index_cols = _gda_capi_meta_index_cols;
253
254 /* distributed transactions: if not supported, then provider_class->xa_funcs should be set to NULL */
255 provider_class->xa_funcs = g_new0 (GdaServerProviderXa, 1);
256 provider_class->xa_funcs->xa_start = gda_capi_provider_xa_start;
257 provider_class->xa_funcs->xa_end = gda_capi_provider_xa_end;
258 provider_class->xa_funcs->xa_prepare = gda_capi_provider_xa_prepare;
259 provider_class->xa_funcs->xa_commit = gda_capi_provider_xa_commit;
260 provider_class->xa_funcs->xa_rollback = gda_capi_provider_xa_rollback;
261 provider_class->xa_funcs->xa_recover = gda_capi_provider_xa_recover;
262 }
263
264 static void
gda_capi_provider_init(GdaCapiProvider * capi_prv,G_GNUC_UNUSED GdaCapiProviderClass * klass)265 gda_capi_provider_init (GdaCapiProvider *capi_prv, G_GNUC_UNUSED GdaCapiProviderClass *klass)
266 {
267 g_mutex_lock (&init_mutex);
268
269 if (!internal_stmt) {
270 InternalStatementItem i;
271 GdaSqlParser *parser;
272
273 parser = gda_server_provider_internal_get_parser ((GdaServerProvider*) capi_prv);
274 internal_stmt = g_new0 (GdaStatement *, sizeof (internal_sql) / sizeof (gchar*));
275 for (i = INTERNAL_STMT1; i < sizeof (internal_sql) / sizeof (gchar*); i++) {
276 internal_stmt[i] = gda_sql_parser_parse_string (parser, internal_sql[i], NULL, NULL);
277 if (!internal_stmt[i])
278 g_error ("Could not parse internal statement: %s\n", internal_sql[i]);
279 }
280 }
281
282 /* meta data init */
283 _gda_capi_provider_meta_init ((GdaServerProvider*) capi_prv);
284
285 /* TO_ADD: any other provider's init should be added here */
286
287 g_mutex_unlock (&init_mutex);
288 }
289
290 GType
gda_capi_provider_get_type(void)291 gda_capi_provider_get_type (void)
292 {
293 static GType type = 0;
294
295 if (G_UNLIKELY (type == 0)) {
296 static GMutex registering;
297 static GTypeInfo info = {
298 sizeof (GdaCapiProviderClass),
299 (GBaseInitFunc) NULL,
300 (GBaseFinalizeFunc) NULL,
301 (GClassInitFunc) gda_capi_provider_class_init,
302 NULL, NULL,
303 sizeof (GdaCapiProvider),
304 0,
305 (GInstanceInitFunc) gda_capi_provider_init,
306 0
307 };
308 g_mutex_lock (®istering);
309 if (type == 0)
310 type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, "GdaCapiProvider", &info, 0);
311 g_mutex_unlock (®istering);
312 }
313
314 return type;
315 }
316
317
318 /*
319 * Get provider name request
320 */
321 static const gchar *
gda_capi_provider_get_name(G_GNUC_UNUSED GdaServerProvider * provider)322 gda_capi_provider_get_name (G_GNUC_UNUSED GdaServerProvider *provider)
323 {
324 return CAPI_PROVIDER_NAME;
325 }
326
327 /*
328 * Get provider's version, no need to change this
329 */
330 static const gchar *
gda_capi_provider_get_version(G_GNUC_UNUSED GdaServerProvider * provider)331 gda_capi_provider_get_version (G_GNUC_UNUSED GdaServerProvider *provider)
332 {
333 return PACKAGE_VERSION;
334 }
335
336 /*
337 * Open connection request
338 *
339 * In this function, the following _must_ be done:
340 * - check for the presence and validify of the parameters required to actually open a connection,
341 * using @params
342 * - open the real connection to the database using the parameters previously checked
343 * - create a CapiConnectionData structure and associate it to @cnc
344 *
345 * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR connection event must be added to @cnc)
346 */
347 static gboolean
gda_capi_provider_open_connection(GdaServerProvider * provider,GdaConnection * cnc,GdaQuarkList * params,G_GNUC_UNUSED GdaQuarkList * auth,G_GNUC_UNUSED guint * task_id,GdaServerProviderAsyncCallback async_cb,G_GNUC_UNUSED gpointer cb_data)348 gda_capi_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
349 GdaQuarkList *params, G_GNUC_UNUSED GdaQuarkList *auth,
350 G_GNUC_UNUSED guint *task_id, GdaServerProviderAsyncCallback async_cb,
351 G_GNUC_UNUSED gpointer cb_data)
352 {
353 g_return_val_if_fail (GDA_IS_CAPI_PROVIDER (provider), FALSE);
354 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
355
356 /* If asynchronous connection opening is not supported, then exit now */
357 if (async_cb) {
358 gda_connection_add_event_string (cnc, _("Provider does not support asynchronous connection open"));
359 return FALSE;
360 }
361
362 /* Check for connection parameters */
363 /* TO_ADD: your own connection parameters */
364 const gchar *db_name;
365 db_name = gda_quark_list_find (params, "DB_NAME");
366 if (!db_name) {
367 gda_connection_add_event_string (cnc,
368 _("The connection string must contain the DB_NAME values"));
369 return FALSE;
370 }
371
372 /* open the real connection to the database */
373 /* TO_ADD: C API specific function calls;
374 * if it fails, add a connection event and return FALSE */
375 TO_IMPLEMENT;
376
377 /* Create a new instance of the provider specific data associated to a connection (CapiConnectionData),
378 * and set its contents */
379 CapiConnectionData *cdata;
380 cdata = g_new0 (CapiConnectionData, 1);
381 gda_connection_internal_set_provider_data (cnc, cdata, (GDestroyNotify) gda_capi_free_cnc_data);
382 TO_IMPLEMENT; /* cdata->... = ... */
383
384 /* Optionnally set some attributes for the newly opened connection (encoding to UTF-8 for example )*/
385 TO_IMPLEMENT;
386
387 return TRUE;
388 }
389
390 /*
391 * Close connection request
392 *
393 * In this function, the following _must_ be done:
394 * - Actually close the connection to the database using @cnc's associated CapiConnectionData structure
395 * - Free the CapiConnectionData structure and its contents
396 *
397 * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR connection event must be added to @cnc)
398 */
399 static gboolean
gda_capi_provider_close_connection(GdaServerProvider * provider,GdaConnection * cnc)400 gda_capi_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc)
401 {
402 CapiConnectionData *cdata;
403
404 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
405 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
406
407 /* Close the connection using the C API */
408 cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data (cnc);
409 if (!cdata)
410 return FALSE;
411 TO_IMPLEMENT;
412
413 /* Free the CapiConnectionData structure and its contents*/
414 gda_capi_free_cnc_data (cdata);
415 gda_connection_internal_set_provider_data (cnc, NULL, NULL);
416
417 return TRUE;
418 }
419
420 /*
421 * Server version request
422 *
423 * Returns the server version as a string, which should be stored in @cnc's associated CapiConnectionData structure
424 */
425 static const gchar *
gda_capi_provider_get_server_version(GdaServerProvider * provider,GdaConnection * cnc)426 gda_capi_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc)
427 {
428 CapiConnectionData *cdata;
429
430 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
431 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
432
433 cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data (cnc);
434 if (!cdata)
435 return NULL;
436 TO_IMPLEMENT;
437 return NULL;
438 }
439
440 /*
441 * Get database request
442 *
443 * Returns the database name as a string, which should be stored in @cnc's associated CapiConnectionData structure
444 */
445 static const gchar *
gda_capi_provider_get_database(GdaServerProvider * provider,GdaConnection * cnc)446 gda_capi_provider_get_database (GdaServerProvider *provider, GdaConnection *cnc)
447 {
448 CapiConnectionData *cdata;
449
450 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
451 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
452
453 cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data (cnc);
454 if (!cdata)
455 return NULL;
456 TO_IMPLEMENT;
457 return NULL;
458 }
459
460 /*
461 * Support operation request
462 *
463 * Tells what the implemented server operations are. To add support for an operation, the following steps are required:
464 * - create a capi_specs_....xml.in file describing the required and optional parameters for the operation
465 * - add it to the Makefile.am
466 * - make this method return TRUE for the operation type
467 * - implement the gda_capi_provider_render_operation() and gda_capi_provider_perform_operation() methods
468 *
469 * In this example, the GDA_SERVER_OPERATION_CREATE_TABLE is implemented
470 */
471 static gboolean
gda_capi_provider_supports_operation(GdaServerProvider * provider,GdaConnection * cnc,GdaServerOperationType type,G_GNUC_UNUSED GdaSet * options)472 gda_capi_provider_supports_operation (GdaServerProvider *provider, GdaConnection *cnc,
473 GdaServerOperationType type, G_GNUC_UNUSED GdaSet *options)
474 {
475 if (cnc) {
476 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
477 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
478 }
479
480 switch (type) {
481 case GDA_SERVER_OPERATION_CREATE_DB:
482 case GDA_SERVER_OPERATION_DROP_DB:
483 return FALSE;
484
485 case GDA_SERVER_OPERATION_CREATE_TABLE:
486 return TRUE;
487 case GDA_SERVER_OPERATION_DROP_TABLE:
488 case GDA_SERVER_OPERATION_RENAME_TABLE:
489
490 case GDA_SERVER_OPERATION_ADD_COLUMN:
491
492 case GDA_SERVER_OPERATION_CREATE_INDEX:
493 case GDA_SERVER_OPERATION_DROP_INDEX:
494
495 case GDA_SERVER_OPERATION_CREATE_VIEW:
496 case GDA_SERVER_OPERATION_DROP_VIEW:
497 default:
498 return FALSE;
499 }
500 }
501
502 /*
503 * Create operation request
504 *
505 * Creates a #GdaServerOperation. The following code is generic and should only be changed
506 * if some further initialization is required, or if operation's contents is dependent on @cnc
507 */
508 static GdaServerOperation *
gda_capi_provider_create_operation(GdaServerProvider * provider,GdaConnection * cnc,GdaServerOperationType type,G_GNUC_UNUSED GdaSet * options,GError ** error)509 gda_capi_provider_create_operation (GdaServerProvider *provider, GdaConnection *cnc,
510 GdaServerOperationType type, G_GNUC_UNUSED GdaSet *options,
511 GError **error)
512 {
513 gchar *file;
514 GdaServerOperation *op;
515 gchar *str;
516 gchar *dir;
517
518 if (cnc) {
519 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
520 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
521 }
522
523 file = g_utf8_strdown (gda_server_operation_op_type_to_string (type), -1);
524 str = g_strdup_printf ("capi_specs_%s.xml", file);
525 g_free (file);
526
527 dir = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, NULL);
528 file = gda_server_provider_find_file (provider, dir, str);
529 g_free (dir);
530
531 if (! file) {
532 g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_FILE_NOT_FOUND_ERROR,
533 _("Missing spec. file '%s'"), str);
534 g_free (str);
535 return NULL;
536 }
537 g_free (str);
538
539 op = gda_server_operation_new (type, file);
540 g_free (file);
541
542 return op;
543 }
544
545 /*
546 * Render operation request
547 */
548 static gchar *
gda_capi_provider_render_operation(GdaServerProvider * provider,GdaConnection * cnc,GdaServerOperation * op,GError ** error)549 gda_capi_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc,
550 GdaServerOperation *op, GError **error)
551 {
552 gchar *sql = NULL;
553 gchar *file;
554 gchar *str;
555 gchar *dir;
556
557 if (cnc) {
558 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
559 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
560 }
561
562 /* test @op's validity */
563 file = g_utf8_strdown (gda_server_operation_op_type_to_string (gda_server_operation_get_op_type (op)), -1);
564 str = g_strdup_printf ("capi_specs_%s.xml", file);
565 g_free (file);
566
567 dir = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, NULL);
568 file = gda_server_provider_find_file (provider, dir, str);
569 g_free (dir);
570
571 if (! file) {
572 g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_FILE_NOT_FOUND_ERROR,
573 _("Missing spec. file '%s'"), str);
574 g_free (str);
575 return NULL;
576 }
577 g_free (str);
578 if (!gda_server_operation_is_valid (op, file, error)) {
579 g_free (file);
580 return NULL;
581 }
582 g_free (file);
583
584 /* actual rendering */
585 switch (gda_server_operation_get_op_type (op)) {
586 case GDA_SERVER_OPERATION_CREATE_DB:
587 case GDA_SERVER_OPERATION_DROP_DB:
588 sql = NULL;
589 break;
590 case GDA_SERVER_OPERATION_CREATE_TABLE:
591 sql = gda_capi_render_CREATE_TABLE (provider, cnc, op, error);
592 break;
593 case GDA_SERVER_OPERATION_DROP_TABLE:
594 case GDA_SERVER_OPERATION_RENAME_TABLE:
595 case GDA_SERVER_OPERATION_ADD_COLUMN:
596 case GDA_SERVER_OPERATION_CREATE_INDEX:
597 case GDA_SERVER_OPERATION_DROP_INDEX:
598 case GDA_SERVER_OPERATION_CREATE_VIEW:
599 case GDA_SERVER_OPERATION_DROP_VIEW:
600 sql = NULL;
601 break;
602 default:
603 g_assert_not_reached ();
604 }
605 return sql;
606 }
607
608 /*
609 * Perform operation request
610 */
611 static gboolean
gda_capi_provider_perform_operation(GdaServerProvider * provider,GdaConnection * cnc,GdaServerOperation * op,G_GNUC_UNUSED guint * task_id,GdaServerProviderAsyncCallback async_cb,G_GNUC_UNUSED gpointer cb_data,GError ** error)612 gda_capi_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
613 GdaServerOperation *op, G_GNUC_UNUSED guint *task_id,
614 GdaServerProviderAsyncCallback async_cb, G_GNUC_UNUSED gpointer cb_data,
615 GError **error)
616 {
617 GdaServerOperationType optype;
618
619 /* If asynchronous connection opening is not supported, then exit now */
620 if (async_cb) {
621 g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
622 "%s", _("Provider does not support asynchronous server operation"));
623 return FALSE;
624 }
625
626 if (cnc) {
627 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
628 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
629 }
630 optype = gda_server_operation_get_op_type (op);
631 switch (optype) {
632 case GDA_SERVER_OPERATION_CREATE_DB:
633 case GDA_SERVER_OPERATION_DROP_DB:
634 default:
635 /* use the SQL from the provider to perform the action */
636 return gda_server_provider_perform_operation_default (provider, cnc, op, error);
637 }
638 }
639
640 /*
641 * Begin transaction request
642 */
643 static gboolean
gda_capi_provider_begin_transaction(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED const gchar * name,G_GNUC_UNUSED GdaTransactionIsolation level,G_GNUC_UNUSED GError ** error)644 gda_capi_provider_begin_transaction (GdaServerProvider *provider, GdaConnection *cnc,
645 G_GNUC_UNUSED const gchar *name,
646 G_GNUC_UNUSED GdaTransactionIsolation level,
647 G_GNUC_UNUSED GError **error)
648 {
649 CapiConnectionData *cdata;
650
651 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
652 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
653
654 cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
655 if (!cdata)
656 return FALSE;
657
658 TO_IMPLEMENT;
659
660 return FALSE;
661 }
662
663 /*
664 * Commit transaction request
665 */
666 static gboolean
gda_capi_provider_commit_transaction(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED const gchar * name,G_GNUC_UNUSED GError ** error)667 gda_capi_provider_commit_transaction (GdaServerProvider *provider, GdaConnection *cnc,
668 G_GNUC_UNUSED const gchar *name, G_GNUC_UNUSED GError **error)
669 {
670 CapiConnectionData *cdata;
671
672 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
673 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
674
675 cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
676 if (!cdata)
677 return FALSE;
678
679 TO_IMPLEMENT;
680
681 return FALSE;
682 }
683
684 /*
685 * Rollback transaction request
686 */
687 static gboolean
gda_capi_provider_rollback_transaction(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED const gchar * name,G_GNUC_UNUSED GError ** error)688 gda_capi_provider_rollback_transaction (GdaServerProvider *provider, GdaConnection *cnc,
689 G_GNUC_UNUSED const gchar *name, G_GNUC_UNUSED GError **error)
690 {
691 CapiConnectionData *cdata;
692
693 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
694 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
695
696 cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
697 if (!cdata)
698 return FALSE;
699
700 TO_IMPLEMENT;
701
702 return FALSE;
703 }
704
705 /*
706 * Add savepoint request
707 */
708 static gboolean
gda_capi_provider_add_savepoint(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED const gchar * name,G_GNUC_UNUSED GError ** error)709 gda_capi_provider_add_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
710 G_GNUC_UNUSED const gchar *name, G_GNUC_UNUSED GError **error)
711 {
712 CapiConnectionData *cdata;
713
714 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
715 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
716
717 cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
718 if (!cdata)
719 return FALSE;
720
721 TO_IMPLEMENT;
722
723 return FALSE;
724 }
725
726 /*
727 * Rollback savepoint request
728 */
729 static gboolean
gda_capi_provider_rollback_savepoint(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED const gchar * name,G_GNUC_UNUSED GError ** error)730 gda_capi_provider_rollback_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
731 G_GNUC_UNUSED const gchar *name, G_GNUC_UNUSED GError **error)
732 {
733 CapiConnectionData *cdata;
734
735 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
736 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
737
738 cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
739 if (!cdata)
740 return FALSE;
741
742 TO_IMPLEMENT;
743
744 return FALSE;
745 }
746
747 /*
748 * Delete savepoint request
749 */
750 static gboolean
gda_capi_provider_delete_savepoint(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED const gchar * name,G_GNUC_UNUSED GError ** error)751 gda_capi_provider_delete_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
752 G_GNUC_UNUSED const gchar *name, G_GNUC_UNUSED GError **error)
753 {
754 CapiConnectionData *cdata;
755
756 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
757 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
758
759 cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
760 if (!cdata)
761 return FALSE;
762
763 TO_IMPLEMENT;
764
765 return FALSE;
766 }
767
768 /*
769 * Feature support request
770 */
771 static gboolean
gda_capi_provider_supports_feature(GdaServerProvider * provider,GdaConnection * cnc,GdaConnectionFeature feature)772 gda_capi_provider_supports_feature (GdaServerProvider *provider, GdaConnection *cnc, GdaConnectionFeature feature)
773 {
774 if (cnc) {
775 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
776 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
777 }
778
779 switch (feature) {
780 case GDA_CONNECTION_FEATURE_SQL :
781 return TRUE;
782 default:
783 return FALSE;
784 }
785 }
786
787 /*
788 * Get data handler request
789 *
790 * This method allows one to obtain a pointer to a #GdaDataHandler object specific to @type or @dbms_type (@dbms_type
791 * must be considered only if @type is not a valid GType).
792 *
793 * A data handler allows one to convert a value between its different representations which are a human readable string,
794 * an SQL representation and a GValue.
795 *
796 * The recommended method is to create GdaDataHandler objects only when they are needed and to keep a reference to them
797 * for further usage, using the gda_server_provider_handler_declare() method.
798 *
799 * The implementation shown here does not define any specific data handler, but there should be some for at least
800 * binary and time related types.
801 */
802 static GdaDataHandler *
gda_capi_provider_get_data_handler(GdaServerProvider * provider,GdaConnection * cnc,GType type,const gchar * dbms_type)803 gda_capi_provider_get_data_handler (GdaServerProvider *provider, GdaConnection *cnc,
804 GType type, const gchar *dbms_type)
805 {
806 GdaDataHandler *dh;
807 if (cnc) {
808 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
809 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
810 }
811
812 if (type == G_TYPE_INVALID) {
813 TO_IMPLEMENT; /* use @dbms_type */
814 dh = NULL;
815 }
816 else if ((type == GDA_TYPE_BINARY) ||
817 (type == GDA_TYPE_BLOB)) {
818 TO_IMPLEMENT; /* define data handlers for these types */
819 dh = NULL;
820 }
821 else if ((type == GDA_TYPE_TIME) ||
822 (type == GDA_TYPE_TIMESTAMP) ||
823 (type == G_TYPE_DATE)) {
824 TO_IMPLEMENT; /* define data handlers for these types */
825 dh = NULL;
826 }
827 else
828 dh = gda_server_provider_handler_use_default (provider, type);
829
830 return dh;
831 }
832
833 /*
834 * Get default DBMS type request
835 *
836 * This method returns the "preferred" DBMS type for GType
837 */
838 static const gchar*
gda_capi_provider_get_default_dbms_type(GdaServerProvider * provider,GdaConnection * cnc,GType type)839 gda_capi_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConnection *cnc, GType type)
840 {
841 if (cnc) {
842 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
843 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
844 }
845
846 TO_IMPLEMENT;
847
848 if ((type == G_TYPE_INT64) ||
849 (type == G_TYPE_INT) ||
850 (type == GDA_TYPE_SHORT) ||
851 (type == GDA_TYPE_USHORT) ||
852 (type == G_TYPE_CHAR) ||
853 (type == G_TYPE_UCHAR) ||
854 (type == G_TYPE_ULONG) ||
855 (type == G_TYPE_UINT) ||
856 (type == G_TYPE_UINT64))
857 return "integer";
858
859 if ((type == GDA_TYPE_BINARY) ||
860 (type == GDA_TYPE_BLOB))
861 return "blob";
862
863 if (type == G_TYPE_BOOLEAN)
864 return "boolean";
865
866 if ((type == G_TYPE_DATE) ||
867 (type == GDA_TYPE_GEOMETRIC_POINT) ||
868 (type == G_TYPE_OBJECT) ||
869 (type == G_TYPE_STRING) ||
870 (type == GDA_TYPE_TIME) ||
871 (type == GDA_TYPE_TIMESTAMP) ||
872 (type == G_TYPE_GTYPE))
873 return "string";
874
875 if ((type == G_TYPE_DOUBLE) ||
876 (type == GDA_TYPE_NUMERIC) ||
877 (type == G_TYPE_FLOAT))
878 return "real";
879
880 if (type == GDA_TYPE_TIME)
881 return "time";
882 if (type == GDA_TYPE_TIMESTAMP)
883 return "timestamp";
884 if (type == G_TYPE_DATE)
885 return "date";
886
887 if ((type == GDA_TYPE_NULL) ||
888 (type == G_TYPE_GTYPE))
889 return NULL;
890
891 return "text";
892 }
893
894 /*
895 * Create parser request
896 *
897 * This method is responsible for creating a #GdaSqlParser object specific to the SQL dialect used
898 * by the database. See the PostgreSQL provider implementation for an example.
899 */
900 static GdaSqlParser *
gda_capi_provider_create_parser(G_GNUC_UNUSED GdaServerProvider * provider,G_GNUC_UNUSED GdaConnection * cnc)901 gda_capi_provider_create_parser (G_GNUC_UNUSED GdaServerProvider *provider, G_GNUC_UNUSED GdaConnection *cnc)
902 {
903 TO_IMPLEMENT;
904 return NULL;
905 }
906
907 /*
908 * GdaStatement to SQL request
909 *
910 * This method renders a #GdaStatement into its SQL representation.
911 *
912 * The implementation show here simply calls gda_statement_to_sql_extended() but the rendering
913 * can be specialized to the database's SQL dialect, see the implementation of gda_statement_to_sql_extended()
914 * and SQLite's specialized rendering for more details
915 *
916 * NOTE: This implementation MUST NOT call gda_statement_to_sql_extended() if it is
917 * the GdaServerProvider::statement_to_sql() virtual method's implementation
918 */
919 static gchar *
gda_capi_provider_statement_to_sql(GdaServerProvider * provider,GdaConnection * cnc,GdaStatement * stmt,GdaSet * params,GdaStatementSqlFlag flags,GSList ** params_used,GError ** error)920 gda_capi_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection *cnc,
921 GdaStatement *stmt, GdaSet *params, GdaStatementSqlFlag flags,
922 GSList **params_used, GError **error)
923 {
924 g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
925 if (cnc) {
926 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
927 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
928 }
929
930 return gda_statement_to_sql_extended (stmt, cnc, params, flags, params_used, error);
931 }
932
933 /*
934 * Statement prepare request
935 *
936 * This methods "converts" @stmt into a prepared statement. A prepared statement is a notion
937 * specific in its implementation details to the C API used here. If successfull, it must create
938 * a new #GdaCapiPStmt object and declare it to @cnc.
939 */
940 static gboolean
gda_capi_provider_statement_prepare(GdaServerProvider * provider,GdaConnection * cnc,GdaStatement * stmt,GError ** error)941 gda_capi_provider_statement_prepare (GdaServerProvider *provider, GdaConnection *cnc,
942 GdaStatement *stmt, GError **error)
943 {
944 GdaCapiPStmt *ps;
945 gboolean retval = FALSE;
946
947 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
948 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
949 g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE);
950
951 /* fetch prepares stmt if already done */
952 ps = (GdaCapiPStmt *) gda_connection_get_prepared_statement (cnc, stmt);
953 if (ps)
954 return TRUE;
955
956 /* render as SQL understood by the provider */
957 GdaSet *params = NULL;
958 gchar *sql;
959 GSList *used_params = NULL;
960 if (! gda_statement_get_parameters (stmt, ¶ms, error))
961 return FALSE;
962 sql = gda_capi_provider_statement_to_sql (provider, cnc, stmt, params, GDA_STATEMENT_SQL_PARAMS_AS_UQMARK,
963 &used_params, error);
964 if (!sql)
965 goto out;
966
967 /* prepare @stmt using the C API, creates @ps */
968 TO_IMPLEMENT;
969
970 /* make a list of the parameter names used in the statement */
971 GSList *param_ids = NULL;
972 if (used_params) {
973 GSList *list;
974 for (list = used_params; list; list = list->next) {
975 const gchar *cid;
976 cid = gda_holder_get_id (GDA_HOLDER (list->data));
977 if (cid) {
978 param_ids = g_slist_append (param_ids, g_strdup (cid));
979 /*g_print ("PREPARATION: param ID: %s\n", cid);*/
980 }
981 else {
982 g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_PREPARE_STMT_ERROR,
983 "%s", _("Unnamed parameter is not allowed in prepared statements"));
984 g_slist_foreach (param_ids, (GFunc) g_free, NULL);
985 g_slist_free (param_ids);
986 goto out;
987 }
988 }
989 }
990
991 /* create a prepared statement object */
992 /*ps = gda_capi_pstmt_new (...);*/
993 gda_pstmt_set_gda_statement (_GDA_PSTMT (ps), stmt);
994 _GDA_PSTMT (ps)->param_ids = param_ids;
995 _GDA_PSTMT (ps)->sql = sql;
996
997 gda_connection_add_prepared_statement (cnc, stmt, (GdaPStmt *) ps);
998 g_object_unref (ps);
999
1000 retval = TRUE;
1001
1002 out:
1003 if (used_params)
1004 g_slist_free (used_params);
1005 if (params)
1006 g_object_unref (params);
1007 return retval;
1008 }
1009
1010 /*
1011 * Execute statement request
1012 *
1013 * Executes a statement. This method should do the following:
1014 * - try to prepare the statement if not yet done
1015 * - optionnally reset the prepared statement
1016 * - bind the variables's values (which are in @params)
1017 * - add a connection event to log the execution
1018 * - execute the prepared statement
1019 *
1020 * If @stmt is an INSERT statement and @last_inserted_row is not NULL then additional actions must be taken to return the
1021 * actual inserted row
1022 */
1023 static GObject *
gda_capi_provider_statement_execute(GdaServerProvider * provider,GdaConnection * cnc,GdaStatement * stmt,GdaSet * params,GdaStatementModelUsage model_usage,GType * col_types,GdaSet ** last_inserted_row,guint * task_id,GdaServerProviderExecCallback async_cb,gpointer cb_data,GError ** error)1024 gda_capi_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
1025 GdaStatement *stmt, GdaSet *params,
1026 GdaStatementModelUsage model_usage,
1027 GType *col_types, GdaSet **last_inserted_row,
1028 guint *task_id,
1029 GdaServerProviderExecCallback async_cb, gpointer cb_data, GError **error)
1030 {
1031 GdaCapiPStmt *ps;
1032 CapiConnectionData *cdata;
1033 gboolean allow_noparam;
1034 gboolean empty_rs = FALSE; /* TRUE when @allow_noparam is TRUE and there is a problem with @params
1035 => resulting data model will be empty (0 row) */
1036
1037 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
1038 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
1039 g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
1040
1041 /* If asynchronous connection opening is not supported, then exit now */
1042 if (async_cb) {
1043 g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
1044 "%s", _("Provider does not support asynchronous statement execution"));
1045 return NULL;
1046 }
1047
1048 allow_noparam = (model_usage & GDA_STATEMENT_MODEL_ALLOW_NOPARAM) &&
1049 (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT);
1050
1051 if (last_inserted_row)
1052 *last_inserted_row = NULL;
1053
1054 /* Get private data */
1055 cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1056 if (!cdata)
1057 return FALSE;
1058
1059
1060 /* get/create new prepared statement */
1061 ps = (GdaCapiPStmt *) gda_connection_get_prepared_statement (cnc, stmt);
1062 if (!ps) {
1063 if (!gda_capi_provider_statement_prepare (provider, cnc, stmt, NULL)) {
1064 /* this case can appear for example if some variables are used in places
1065 * where the C API cannot allow them (for example if the variable is the table name
1066 * in a SELECT statement). The action here is to get the actual SQL code for @stmt,
1067 * and use that SQL instead of @stmt to create another GdaCapiPStmt object.
1068 *
1069 * Don't call gda_connection_add_prepared_statement() with this new prepared statement
1070 * as it will be destroyed once used.
1071 */
1072 TO_IMPLEMENT;
1073 return NULL;
1074 }
1075 else {
1076 ps = (GdaCapiPStmt *) gda_connection_get_prepared_statement (cnc, stmt);
1077 g_object_ref (ps);
1078 }
1079 }
1080 else
1081 g_object_ref (ps);
1082 g_assert (ps);
1083
1084 /* optionnally reset the prepared statement if required by the API */
1085 TO_IMPLEMENT;
1086
1087 /* bind statement's parameters */
1088 GSList *list;
1089 GdaConnectionEvent *event = NULL;
1090 int i;
1091 for (i = 1, list = _GDA_PSTMT (ps)->param_ids; list; list = list->next, i++) {
1092 const gchar *pname = (gchar *) list->data;
1093 GdaHolder *h;
1094
1095 /* find requested parameter */
1096 if (!params) {
1097 event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
1098 gda_connection_event_set_description (event, _("Missing parameter(s) to execute query"));
1099 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
1100 GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR,
1101 "%s", _("Missing parameter(s) to execute query"));
1102 break;
1103 }
1104
1105 h = gda_set_get_holder (params, pname);
1106 if (!h) {
1107 gchar *tmp = gda_alphanum_to_text (g_strdup (pname + 1));
1108 if (tmp) {
1109 h = gda_set_get_holder (params, tmp);
1110 g_free (tmp);
1111 }
1112 }
1113 if (!h) {
1114 if (allow_noparam) {
1115 /* bind param to NULL */
1116 TO_IMPLEMENT;
1117 empty_rs = TRUE;
1118 continue;
1119 }
1120 else {
1121 gchar *str;
1122 str = g_strdup_printf (_("Missing parameter '%s' to execute query"), pname);
1123 event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
1124 gda_connection_event_set_description (event, str);
1125 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
1126 GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, "%s", str);
1127 g_free (str);
1128 break;
1129 }
1130
1131 }
1132 if (!gda_holder_is_valid (h)) {
1133 if (allow_noparam) {
1134 /* bind param to NULL */
1135 TO_IMPLEMENT;
1136 empty_rs = TRUE;
1137 continue;
1138 }
1139 else {
1140 gchar *str;
1141 str = g_strdup_printf (_("Parameter '%s' is invalid"), pname);
1142 event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
1143 gda_connection_event_set_description (event, str);
1144 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
1145 GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, "%s", str);
1146 g_free (str);
1147 break;
1148 }
1149 }
1150 else if (gda_holder_value_is_default (h) && !gda_holder_get_value (h)) {
1151 /* create a new GdaStatement to handle all default values and execute it instead
1152 * needs to be adapted to take into account how the database server handles default
1153 * values (some accept the DEFAULT keyword), changing the 3rd argument of the
1154 * gda_statement_rewrite_for_default_values() call
1155 */
1156 GdaSqlStatement *sqlst;
1157 GError *lerror = NULL;
1158 sqlst = gda_statement_rewrite_for_default_values (stmt, params, TRUE, &lerror);
1159 if (!sqlst) {
1160 event = gda_connection_point_available_event (cnc,
1161 GDA_CONNECTION_EVENT_ERROR);
1162 gda_connection_event_set_description (event, lerror && lerror->message ?
1163 lerror->message :
1164 _("Can't rewrite statement handle default values"));
1165 g_propagate_error (error, lerror);
1166 break;
1167 }
1168
1169 GdaStatement *rstmt;
1170 GObject *res;
1171 rstmt = g_object_new (GDA_TYPE_STATEMENT, "structure", sqlst, NULL);
1172 gda_sql_statement_free (sqlst);
1173 res = gda_capi_provider_statement_execute (provider, cnc,
1174 rstmt, params,
1175 model_usage,
1176 col_types, last_inserted_row,
1177 task_id,
1178 async_cb, cb_data, error);
1179 g_object_unref (rstmt);
1180 return res;
1181 }
1182
1183
1184 /* actual binding using the C API, for parameter at position @i */
1185 const GValue *value = gda_holder_get_value (h);
1186 if (!value || gda_value_is_null (value)) {
1187 GdaStatement *rstmt;
1188 if (! gda_rewrite_statement_for_null_parameters (stmt, params, &rstmt, error)) {
1189 TO_IMPLEMENT; /* bind to NULL */
1190 }
1191 else if (!rstmt)
1192 return NULL;
1193 else {
1194 /* The strategy here is to execute @rstmt using its prepared
1195 * statement, but with common data from @ps. Beware that
1196 * the @param_ids attribute needs to be retained (i.e. it must not
1197 * be the one copied from @ps) */
1198 GObject *obj;
1199 GdaCapiPStmt *tps;
1200 GdaPStmt *gtps;
1201 GSList *prep_param_ids, *copied_param_ids;
1202 if (!gda_capi_provider_statement_prepare (provider, cnc,
1203 rstmt, error))
1204 return NULL;
1205 tps = (GdaCapiPStmt *)
1206 gda_connection_get_prepared_statement (cnc, rstmt);
1207 gtps = (GdaPStmt *) tps;
1208
1209 /* keep @param_ids to avoid being cleared by gda_pstmt_copy_contents() */
1210 prep_param_ids = gtps->param_ids;
1211 gtps->param_ids = NULL;
1212
1213 /* actual copy */
1214 gda_pstmt_copy_contents ((GdaPStmt *) ps, (GdaPStmt *) tps);
1215
1216 /* restore previous @param_ids */
1217 copied_param_ids = gtps->param_ids;
1218 gtps->param_ids = prep_param_ids;
1219
1220 /* execute */
1221 obj = gda_capi_provider_statement_execute (provider, cnc,
1222 rstmt, params,
1223 model_usage,
1224 col_types,
1225 last_inserted_row,
1226 task_id, async_cb,
1227 cb_data, error);
1228 /* clear original @param_ids and restore copied one */
1229 g_slist_foreach (prep_param_ids, (GFunc) g_free, NULL);
1230 g_slist_free (prep_param_ids);
1231
1232 gtps->param_ids = copied_param_ids;
1233
1234 /*if (GDA_IS_DATA_MODEL (obj))
1235 gda_data_model_dump ((GdaDataModel*) obj, NULL);*/
1236
1237 g_object_unref (rstmt);
1238 return obj;
1239 }
1240 }
1241 else {
1242 /* usually the way to bind parameters is different depending on the type of @value.
1243 * Also, if the database engine does not support storing timezone information for time and
1244 * timestamp values, then before binding, the value must be converted to GMT using
1245 * gda_time_change_timezone (xxx, 0) or gda_timestamp_change_timezone (xxx, 0)
1246 */
1247 TO_IMPLEMENT;
1248 }
1249 }
1250
1251 if (event) {
1252 gda_connection_add_event (cnc, event);
1253 g_object_unref (ps);
1254 return NULL;
1255 }
1256
1257 /* add a connection event for the execution */
1258 event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_COMMAND);
1259 gda_connection_event_set_description (event, _GDA_PSTMT (ps)->sql);
1260 gda_connection_add_event (cnc, event);
1261
1262 if (empty_rs) {
1263 /* There are some missing parameters, so the SQL can't be executed but we still want
1264 * to execute something to get the columns correctly. A possibility is to actually
1265 * execute another SQL which is the code shown here.
1266 *
1267 * To adapt depending on the C API and its features */
1268 GdaStatement *estmt;
1269 gchar *esql;
1270 estmt = gda_select_alter_select_for_empty (stmt, error);
1271 if (!estmt) {
1272 g_object_unref (ps);
1273 return NULL;
1274 }
1275 esql = gda_statement_to_sql (estmt, NULL, error);
1276 g_object_unref (estmt);
1277 if (!esql) {
1278 g_object_unref (ps);
1279 return NULL;
1280 }
1281
1282 /* Execute the 'esql' SQL code */
1283 g_free (esql);
1284
1285 TO_IMPLEMENT;
1286 }
1287 else {
1288 /* Execute the _GDA_PSTMT (ps)->sql SQL code */
1289 TO_IMPLEMENT;
1290 }
1291
1292 /* execute prepared statement using C API depending on its kind */
1293 if (! g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "SELECT", 6) ||
1294 ! g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "EXPLAIN", 7)) {
1295 GObject *data_model;
1296 GdaDataModelAccessFlags flags;
1297
1298 if (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS)
1299 flags = GDA_DATA_MODEL_ACCESS_RANDOM;
1300 else
1301 flags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD;
1302
1303 data_model = (GObject *) gda_capi_recordset_new (cnc, ps, params, flags, col_types);
1304 gda_connection_internal_statement_executed (cnc, stmt, params, NULL); /* required: help @cnc keep some stats */
1305 g_object_unref (ps);
1306 return data_model;
1307 }
1308 else {
1309 GdaSet *set = NULL;
1310
1311 TO_IMPLEMENT;
1312 /* Create a #GdaSet containing "IMPACTED_ROWS" */
1313 /* Create GdaConnectionEvent notice with the type of command and impacted rows */
1314
1315 gda_connection_internal_statement_executed (cnc, stmt, params, event); /* required: help @cnc keep some stats */
1316 g_object_unref (ps);
1317 return (GObject*) set;
1318 }
1319 }
1320
1321 /*
1322 * Rewrites a statement in case some parameters in @params are set to DEFAULT, for INSERT or UPDATE statements
1323 *
1324 * Usually it uses the DEFAULT keyword or removes any default value inserted or updated, see
1325 * gda_statement_rewrite_for_default_values()
1326 */
1327 static GdaSqlStatement *
gda_capi_statement_rewrite(GdaServerProvider * provider,GdaConnection * cnc,GdaStatement * stmt,GdaSet * params,GError ** error)1328 gda_capi_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
1329 GdaStatement *stmt, GdaSet *params, GError **error)
1330 {
1331 if (cnc) {
1332 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
1333 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
1334 }
1335 return gda_statement_rewrite_for_default_values (stmt, params, TRUE, error);
1336 }
1337
1338 /*
1339 * starts a distributed transaction: put the XA transaction in the ACTIVE state
1340 */
1341 static gboolean
gda_capi_provider_xa_start(GdaServerProvider * provider,GdaConnection * cnc,const GdaXaTransactionId * xid,G_GNUC_UNUSED GError ** error)1342 gda_capi_provider_xa_start (GdaServerProvider *provider, GdaConnection *cnc,
1343 const GdaXaTransactionId *xid, G_GNUC_UNUSED GError **error)
1344 {
1345 CapiConnectionData *cdata;
1346
1347 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1348 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1349 g_return_val_if_fail (xid, FALSE);
1350
1351 cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1352 if (!cdata)
1353 return FALSE;
1354
1355 TO_IMPLEMENT;
1356 return FALSE;
1357 }
1358
1359 /*
1360 * put the XA transaction in the IDLE state: the connection won't accept any more modifications.
1361 * This state is required by some database providers before actually going to the PREPARED state
1362 */
1363 static gboolean
gda_capi_provider_xa_end(GdaServerProvider * provider,GdaConnection * cnc,const GdaXaTransactionId * xid,G_GNUC_UNUSED GError ** error)1364 gda_capi_provider_xa_end (GdaServerProvider *provider, GdaConnection *cnc,
1365 const GdaXaTransactionId *xid, G_GNUC_UNUSED GError **error)
1366 {
1367 CapiConnectionData *cdata;
1368
1369 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1370 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1371 g_return_val_if_fail (xid, FALSE);
1372
1373 cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1374 if (!cdata)
1375 return FALSE;
1376
1377 TO_IMPLEMENT;
1378 return FALSE;
1379 }
1380
1381 /*
1382 * prepares the distributed transaction: put the XA transaction in the PREPARED state
1383 */
1384 static gboolean
gda_capi_provider_xa_prepare(GdaServerProvider * provider,GdaConnection * cnc,const GdaXaTransactionId * xid,G_GNUC_UNUSED GError ** error)1385 gda_capi_provider_xa_prepare (GdaServerProvider *provider, GdaConnection *cnc,
1386 const GdaXaTransactionId *xid, G_GNUC_UNUSED GError **error)
1387 {
1388 CapiConnectionData *cdata;
1389
1390 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1391 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1392 g_return_val_if_fail (xid, FALSE);
1393
1394 cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1395 if (!cdata)
1396 return FALSE;
1397
1398 TO_IMPLEMENT;
1399 return FALSE;
1400 }
1401
1402 /*
1403 * commits the distributed transaction: actually write the prepared data to the database and
1404 * terminates the XA transaction
1405 */
1406 static gboolean
gda_capi_provider_xa_commit(GdaServerProvider * provider,GdaConnection * cnc,const GdaXaTransactionId * xid,G_GNUC_UNUSED GError ** error)1407 gda_capi_provider_xa_commit (GdaServerProvider *provider, GdaConnection *cnc,
1408 const GdaXaTransactionId *xid, G_GNUC_UNUSED GError **error)
1409 {
1410 CapiConnectionData *cdata;
1411
1412 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1413 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1414 g_return_val_if_fail (xid, FALSE);
1415
1416 cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1417 if (!cdata)
1418 return FALSE;
1419
1420 TO_IMPLEMENT;
1421 return FALSE;
1422 }
1423
1424 /*
1425 * Rolls back an XA transaction, possible only if in the ACTIVE, IDLE or PREPARED state
1426 */
1427 static gboolean
gda_capi_provider_xa_rollback(GdaServerProvider * provider,GdaConnection * cnc,const GdaXaTransactionId * xid,G_GNUC_UNUSED GError ** error)1428 gda_capi_provider_xa_rollback (GdaServerProvider *provider, GdaConnection *cnc,
1429 const GdaXaTransactionId *xid, G_GNUC_UNUSED GError **error)
1430 {
1431 CapiConnectionData *cdata;
1432
1433 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1434 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1435 g_return_val_if_fail (xid, FALSE);
1436
1437 cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1438 if (!cdata)
1439 return FALSE;
1440
1441 TO_IMPLEMENT;
1442 return FALSE;
1443 }
1444
1445 /*
1446 * Lists all XA transactions that are in the PREPARED state
1447 *
1448 * Returns: a list of GdaXaTransactionId structures, which will be freed by the caller
1449 */
1450 static GList *
gda_capi_provider_xa_recover(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED GError ** error)1451 gda_capi_provider_xa_recover (GdaServerProvider *provider, GdaConnection *cnc,
1452 G_GNUC_UNUSED GError **error)
1453 {
1454 CapiConnectionData *cdata;
1455
1456 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
1457 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
1458
1459 cdata = (CapiConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1460 if (!cdata)
1461 return NULL;
1462
1463 TO_IMPLEMENT;
1464 return NULL;
1465 }
1466
1467 /*
1468 * Free connection's specific data
1469 */
1470 static void
gda_capi_free_cnc_data(CapiConnectionData * cdata)1471 gda_capi_free_cnc_data (CapiConnectionData *cdata)
1472 {
1473 if (!cdata)
1474 return;
1475
1476 TO_IMPLEMENT;
1477 g_free (cdata);
1478 }
1479