1 /*
2 * Copyright (C) 2002 Rodrigo Moya <rodrigo@gnome-db.org>
3 * Copyright (C) 2003 Gonzalo Paniagua Javier <gonzalo@gnome-db.org>
4 * Copyright (C) 2004 Jeronimo Albi <jeronimoalbi@yahoo.com.ar>
5 * Copyright (C) 2004 Julio M. Merino Vidal <jmmv@menta.net>
6 * Copyright (C) 2004 - 2012 Vivien Malerba <malerba@gnome-db.org>
7 * Copyright (C) 2008 Murray Cumming <murrayc@murrayc.com>
8 * Copyright (C) 2009 Bas Driessen <bas.driessen@xobas.com>
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 <stdio.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <glib/gi18n-lib.h>
31 #include <glib/gstdio.h>
32 #include <libgda/libgda.h>
33 #include <libgda/gda-data-model-private.h>
34 #include <libgda/gda-server-provider-extra.h>
35 #include <libgda/binreloc/gda-binreloc.h>
36 #include <libgda/gda-statement-extra.h>
37 #include <sql-parser/gda-sql-parser.h>
38 #include "gda-firebird.h"
39 #include "gda-firebird-provider.h"
40 #include "gda-firebird-recordset.h"
41 #include "gda-firebird-ddl.h"
42 #include "gda-firebird-meta.h"
43 #include "gda-firebird-parser.h"
44 #include "gda-firebird-util.h"
45 #include <libgda/gda-debug-macros.h>
46
47 #define _GDA_PSTMT(x) ((GdaPStmt*)(x))
48
49 #define FILE_EXTENSION ".fdb"
50
51 /*
52 * GObject methods
53 */
54 static void gda_firebird_provider_class_init (GdaFirebirdProviderClass *klass);
55 static void gda_firebird_provider_init (GdaFirebirdProvider *provider,
56 GdaFirebirdProviderClass *klass);
57 static GObjectClass *parent_class = NULL;
58
59 /*
60 * GdaServerProvider's virtual methods
61 */
62 /* connection management */
63 static gboolean gda_firebird_provider_open_connection (GdaServerProvider *provider,
64 GdaConnection *cnc,
65 GdaQuarkList *params,
66 GdaQuarkList *auth,
67 guint *task_id,
68 GdaServerProviderAsyncCallback async_cb,
69 gpointer cb_data);
70 static gboolean gda_firebird_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc);
71 static const gchar *gda_firebird_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc);
72 static const gchar *gda_firebird_provider_get_database (GdaServerProvider *provider, GdaConnection *cnc);
73
74 /* DDL operations */
75 static gboolean gda_firebird_provider_supports_operation (GdaServerProvider *provider, GdaConnection *cnc,
76 GdaServerOperationType type, GdaSet *options);
77 static GdaServerOperation *gda_firebird_provider_create_operation (GdaServerProvider *provider, GdaConnection *cnc,
78 GdaServerOperationType type,
79 GdaSet *options, GError **error);
80 static gchar *gda_firebird_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc,
81 GdaServerOperation *op, GError **error);
82
83 static gboolean gda_firebird_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
84 GdaServerOperation *op, guint *task_id,
85 GdaServerProviderAsyncCallback async_cb, gpointer cb_data,
86 GError **error);
87 /* transactions */
88 static gboolean gda_firebird_provider_begin_transaction (GdaServerProvider *provider, GdaConnection *cnc,
89 const gchar *name, GdaTransactionIsolation level, GError **error);
90 static gboolean gda_firebird_provider_commit_transaction (GdaServerProvider *provider, GdaConnection *cnc,
91 const gchar *name, GError **error);
92 static gboolean gda_firebird_provider_rollback_transaction (GdaServerProvider *provider, GdaConnection * cnc,
93 const gchar *name, GError **error);
94 static gboolean gda_firebird_provider_add_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
95 const gchar *name, GError **error);
96 static gboolean gda_firebird_provider_rollback_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
97 const gchar *name, GError **error);
98 static gboolean gda_firebird_provider_delete_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
99 const gchar *name, GError **error);
100
101 /* information retrieval */
102 static const gchar *gda_firebird_provider_get_version (GdaServerProvider *provider);
103 static gboolean gda_firebird_provider_supports_feature (GdaServerProvider *provider, GdaConnection *cnc,
104 GdaConnectionFeature feature);
105
106 static const gchar *gda_firebird_provider_get_name (GdaServerProvider *provider);
107
108 static GdaDataHandler *gda_firebird_provider_get_data_handler (GdaServerProvider *provider, GdaConnection *cnc,
109 GType g_type, const gchar *dbms_type);
110
111 static const gchar* gda_firebird_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConnection *cnc,
112 GType type);
113 /* statements */
114 static GdaSqlParser *gda_firebird_provider_create_parser (GdaServerProvider *provider,
115 GdaConnection *cnc);
116 static gchar *gda_firebird_provider_statement_to_sql (GdaServerProvider *provider,
117 GdaConnection *cnc,
118 GdaStatement *stmt,
119 GdaSet *params,
120 GdaStatementSqlFlag flags,
121 GSList **params_used,
122 GError **error);
123 static gboolean gda_firebird_provider_statement_prepare (GdaServerProvider *provider,
124 GdaConnection *cnc,
125 GdaStatement *stmt, GError **error);
126 static GObject *gda_firebird_provider_statement_execute (GdaServerProvider *provider,
127 GdaConnection *cnc,
128 GdaStatement *stmt,
129 GdaSet *params,
130 GdaStatementModelUsage model_usage,
131 GType *col_types,
132 GdaSet **last_inserted_row,
133 guint *task_id,
134 GdaServerProviderExecCallback async_cb,
135 gpointer cb_data, GError **error);
136
137 /* distributed transactions */
138 static gboolean gda_firebird_provider_xa_start (GdaServerProvider *provider,
139 GdaConnection *cnc,
140 const GdaXaTransactionId *xid,
141 GError **error);
142
143 static gboolean gda_firebird_provider_xa_end (GdaServerProvider *provider,
144 GdaConnection *cnc,
145 const GdaXaTransactionId *xid,
146 GError **error);
147
148 static gboolean gda_firebird_provider_xa_prepare (GdaServerProvider *provider,
149 GdaConnection *cnc,
150 const GdaXaTransactionId *xid,
151 GError **error);
152
153 static gboolean gda_firebird_provider_xa_commit (GdaServerProvider *provider, GdaConnection *cnc,
154 const GdaXaTransactionId *xid, GError **error);
155 static gboolean gda_firebird_provider_xa_rollback (GdaServerProvider *provider, GdaConnection *cnc,
156 const GdaXaTransactionId *xid, GError **error);
157
158 static GList *gda_firebird_provider_xa_recover (GdaServerProvider *provider, GdaConnection *cnc,
159 GError **error);
160
161 /*
162 * private connection data destroy
163 */
164 static void gda_firebird_free_cnc_data (FirebirdConnectionData *cdata);
165
166
167 static gchar *fb_server_get_version (FirebirdConnectionData *fcnc);
168
169
170 static gchar * firebird_render_operation (GdaSqlOperation *op, GdaSqlRenderingContext *context, GError **error);
171
172 static gchar * firebird_render_compound (GdaSqlStatementCompound *stmt, GdaSqlRenderingContext *context, GError **error);
173
174 static gchar * firebird_render_expr (GdaSqlExpr *expr, GdaSqlRenderingContext *context, gboolean *is_default, gboolean *is_null, GError **error);
175
176
177
178
179 /*
180 * Prepared internal statements
181 * TO_ADD: any prepared statement to be used internally by the provider should be
182 * declared here, as constants and as SQL statements
183 */
184 static GMutex init_mutex;
185 static GdaStatement **internal_stmt = NULL;
186
187 typedef enum {
188 INTERNAL_STMT1
189 } InternalStatementItem;
190
191 gchar *internal_sql[] = {
192 "SQL 'firebird' FROM RDB$DATABASE"
193 };
194
195 /*
196 * GdaFirebirdProvider class implementation
197 */
198 static void
gda_firebird_provider_class_init(GdaFirebirdProviderClass * klass)199 gda_firebird_provider_class_init (GdaFirebirdProviderClass *klass)
200 {
201 GdaServerProviderClass *provider_class = GDA_SERVER_PROVIDER_CLASS (klass);
202
203 parent_class = g_type_class_peek_parent (klass);
204
205 provider_class->get_version = gda_firebird_provider_get_version;
206 provider_class->get_server_version = gda_firebird_provider_get_server_version;
207 provider_class->get_name = gda_firebird_provider_get_name;
208 provider_class->supports_feature = gda_firebird_provider_supports_feature;
209
210 provider_class->get_data_handler = gda_firebird_provider_get_data_handler;
211 provider_class->get_def_dbms_type = gda_firebird_provider_get_default_dbms_type;
212
213 provider_class->open_connection = gda_firebird_provider_open_connection;
214 provider_class->close_connection = gda_firebird_provider_close_connection;
215 provider_class->get_database = gda_firebird_provider_get_database;
216
217 provider_class->supports_operation = gda_firebird_provider_supports_operation;
218 provider_class->create_operation = gda_firebird_provider_create_operation;
219 provider_class->render_operation = gda_firebird_provider_render_operation;
220 provider_class->perform_operation = gda_firebird_provider_perform_operation;
221
222 provider_class->begin_transaction = gda_firebird_provider_begin_transaction;
223 provider_class->commit_transaction = gda_firebird_provider_commit_transaction;
224 provider_class->rollback_transaction = gda_firebird_provider_rollback_transaction;
225 provider_class->add_savepoint = NULL /*gda_firebird_provider_add_savepoint*/;
226 provider_class->rollback_savepoint = NULL /*gda_firebird_provider_rollback_savepoint*/;
227 provider_class->delete_savepoint = NULL /*gda_firebird_provider_delete_savepoint*/;
228
229 provider_class->create_parser = gda_firebird_provider_create_parser;
230 provider_class->statement_to_sql = gda_firebird_provider_statement_to_sql;
231 provider_class->statement_prepare = gda_firebird_provider_statement_prepare;
232 provider_class->statement_execute = gda_firebird_provider_statement_execute;
233
234 provider_class->is_busy = NULL;
235 provider_class->cancel = NULL;
236 provider_class->create_connection = NULL;
237
238 memset (&(provider_class->meta_funcs), 0, sizeof (GdaServerProviderMeta));
239 provider_class->meta_funcs._info = _gda_firebird_meta__info;
240 provider_class->meta_funcs._btypes = _gda_firebird_meta__btypes;
241 provider_class->meta_funcs._udt = _gda_firebird_meta__udt;
242 provider_class->meta_funcs.udt = _gda_firebird_meta_udt;
243 provider_class->meta_funcs._udt_cols = _gda_firebird_meta__udt_cols;
244 provider_class->meta_funcs.udt_cols = _gda_firebird_meta_udt_cols;
245 provider_class->meta_funcs._enums = _gda_firebird_meta__enums;
246 provider_class->meta_funcs.enums = _gda_firebird_meta_enums;
247 provider_class->meta_funcs._domains = _gda_firebird_meta__domains;
248 provider_class->meta_funcs.domains = _gda_firebird_meta_domains;
249 provider_class->meta_funcs._constraints_dom = _gda_firebird_meta__constraints_dom;
250 provider_class->meta_funcs.constraints_dom = _gda_firebird_meta_constraints_dom;
251 provider_class->meta_funcs._el_types = _gda_firebird_meta__el_types;
252 provider_class->meta_funcs.el_types = _gda_firebird_meta_el_types;
253 provider_class->meta_funcs._collations = _gda_firebird_meta__collations;
254 provider_class->meta_funcs.collations = _gda_firebird_meta_collations;
255 provider_class->meta_funcs._character_sets = _gda_firebird_meta__character_sets;
256 provider_class->meta_funcs.character_sets = _gda_firebird_meta_character_sets;
257 provider_class->meta_funcs._schemata = _gda_firebird_meta__schemata;
258 provider_class->meta_funcs.schemata = _gda_firebird_meta_schemata;
259 provider_class->meta_funcs._tables_views = _gda_firebird_meta__tables_views;
260 provider_class->meta_funcs.tables_views = _gda_firebird_meta_tables_views;
261 provider_class->meta_funcs._columns = _gda_firebird_meta__columns;
262 provider_class->meta_funcs.columns = _gda_firebird_meta_columns;
263 provider_class->meta_funcs._view_cols = _gda_firebird_meta__view_cols;
264 provider_class->meta_funcs.view_cols = _gda_firebird_meta_view_cols;
265 provider_class->meta_funcs._constraints_tab = _gda_firebird_meta__constraints_tab;
266 provider_class->meta_funcs.constraints_tab = _gda_firebird_meta_constraints_tab;
267 provider_class->meta_funcs._constraints_ref = _gda_firebird_meta__constraints_ref;
268 provider_class->meta_funcs.constraints_ref = _gda_firebird_meta_constraints_ref;
269 provider_class->meta_funcs._key_columns = _gda_firebird_meta__key_columns;
270 provider_class->meta_funcs.key_columns = _gda_firebird_meta_key_columns;
271 provider_class->meta_funcs._check_columns = _gda_firebird_meta__check_columns;
272 provider_class->meta_funcs.check_columns = _gda_firebird_meta_check_columns;
273 provider_class->meta_funcs._triggers = _gda_firebird_meta__triggers;
274 provider_class->meta_funcs.triggers = _gda_firebird_meta_triggers;
275 provider_class->meta_funcs._routines = _gda_firebird_meta__routines;
276 provider_class->meta_funcs.routines = _gda_firebird_meta_routines;
277 provider_class->meta_funcs._routine_col = _gda_firebird_meta__routine_col;
278 provider_class->meta_funcs.routine_col = _gda_firebird_meta_routine_col;
279 provider_class->meta_funcs._routine_par = _gda_firebird_meta__routine_par;
280 provider_class->meta_funcs.routine_par = _gda_firebird_meta_routine_par;
281 provider_class->meta_funcs._indexes_tab = _gda_firebird_meta__indexes_tab;
282 provider_class->meta_funcs.indexes_tab = _gda_firebird_meta_indexes_tab;
283 provider_class->meta_funcs._index_cols = _gda_firebird_meta__index_cols;
284 provider_class->meta_funcs.index_cols = _gda_firebird_meta_index_cols;
285
286 /* distributed transactions: if not supported, then provider_class->xa_funcs should be set to NULL */
287 provider_class->xa_funcs = NULL;
288 /*
289 provider_class->xa_funcs = g_new0 (GdaServerProviderXa, 1);
290 provider_class->xa_funcs->xa_start = gda_firebird_provider_xa_start;
291 provider_class->xa_funcs->xa_end = gda_firebird_provider_xa_end;
292 provider_class->xa_funcs->xa_prepare = gda_firebird_provider_xa_prepare;
293 provider_class->xa_funcs->xa_commit = gda_firebird_provider_xa_commit;
294 provider_class->xa_funcs->xa_rollback = gda_firebird_provider_xa_rollback;
295 provider_class->xa_funcs->xa_recover = gda_firebird_provider_xa_recover;
296 */
297 }
298
299 static void
gda_firebird_provider_init(GdaFirebirdProvider * firebird_prv,GdaFirebirdProviderClass * klass)300 gda_firebird_provider_init (GdaFirebirdProvider *firebird_prv, GdaFirebirdProviderClass *klass)
301 {
302 g_mutex_lock (&init_mutex);
303 if (!internal_stmt) {
304 InternalStatementItem i;
305 GdaSqlParser *parser;
306
307 parser = gda_server_provider_internal_get_parser ((GdaServerProvider*) firebird_prv);
308 internal_stmt = g_new0 (GdaStatement *, sizeof (internal_sql) / sizeof (gchar*));
309 for (i = INTERNAL_STMT1; i < sizeof (internal_sql) / sizeof (gchar*); i++) {
310 internal_stmt[i] = gda_sql_parser_parse_string (parser, internal_sql[i], NULL, NULL);
311 if (!internal_stmt[i])
312 g_error ("Could not parse internal statement: %s\n", internal_sql[i]);
313 }
314 }
315
316 /* meta data init */
317 _gda_firebird_provider_meta_init ((GdaServerProvider*) firebird_prv);
318
319 g_mutex_unlock (&init_mutex);
320 }
321
322 GType
gda_firebird_provider_get_type(void)323 gda_firebird_provider_get_type (void)
324 {
325 static GType type = 0;
326
327 if (G_UNLIKELY (type == 0)) {
328 static GMutex registering;
329 static GTypeInfo info = {
330 sizeof (GdaFirebirdProviderClass),
331 (GBaseInitFunc) NULL,
332 (GBaseFinalizeFunc) NULL,
333 (GClassInitFunc) gda_firebird_provider_class_init,
334 NULL, NULL,
335 sizeof (GdaFirebirdProvider),
336 0,
337 (GInstanceInitFunc) gda_firebird_provider_init
338 };
339 g_mutex_lock (®istering);
340 if (type == 0) {
341 #ifdef FIREBIRD_EMBED
342 type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, "GdaFirebirdProviderEmbed", &info, 0);
343 #else
344 type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, "GdaFirebirdProvider", &info, 0);
345 #endif
346 }
347 g_mutex_unlock (®istering);
348 }
349
350 return type;
351 }
352
353
354 /*
355 * Get provider name request
356 */
357 static const gchar *
gda_firebird_provider_get_name(GdaServerProvider * provider)358 gda_firebird_provider_get_name (GdaServerProvider *provider)
359 {
360 return FIREBIRD_PROVIDER_NAME;
361 }
362
363 /*
364 * Get provider's version, no need to change this
365 */
366 static const gchar *
gda_firebird_provider_get_version(GdaServerProvider * provider)367 gda_firebird_provider_get_version (GdaServerProvider *provider)
368 {
369 return PACKAGE_VERSION;
370 }
371
372 /*
373 * Open connection request
374 *
375 * In this function, the following _must_ be done:
376 * - check for the presence and validify of the parameters required to actually open a connection,
377 * using @params
378 * - open the real connection to the database using the parameters previously checked
379 * - create a FirebirdConnectionData structure and associate it to @cnc
380 *
381 * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR gonnection event must be added to @cnc)
382 */
383 static gboolean
gda_firebird_provider_open_connection(GdaServerProvider * provider,GdaConnection * cnc,GdaQuarkList * params,GdaQuarkList * auth,guint * task_id,GdaServerProviderAsyncCallback async_cb,gpointer cb_data)384 gda_firebird_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
385 GdaQuarkList *params, GdaQuarkList *auth,
386 guint *task_id, GdaServerProviderAsyncCallback async_cb, gpointer cb_data)
387 {
388 g_return_val_if_fail (GDA_IS_FIREBIRD_PROVIDER (provider), FALSE);
389 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
390
391 /* If asynchronous connection opening is not supported, then exit now */
392 if (async_cb) {
393 gda_connection_add_event_string (cnc, _("Provider does not support asynchronous connection open"));
394 return FALSE;
395 }
396
397 /* Check for connection parameters */
398 const gchar *fb_db, *fb_dir, *fb_user, *fb_password, *fb_host;
399 gchar *fb_conn;
400
401 fb_db = (gchar *) gda_quark_list_find (params, "DB_NAME");
402 fb_dir = (gchar *) gda_quark_list_find (params, "DB_DIR");
403 fb_host = (gchar *) gda_quark_list_find (params, "HOST");
404 fb_user = (gchar *) gda_quark_list_find (auth, "USERNAME");
405 fb_password = (gchar *) gda_quark_list_find (auth, "PASSWORD");
406
407 if (!fb_db) {
408 gda_connection_add_event_string (cnc, "%s", _("The connection string must contain the DB_NAME values"));
409 return FALSE;
410 }
411 if (!fb_dir)
412 fb_dir = ".";
413
414 /* prepare DPB */
415 GString *dpb_string;
416 dpb_string = g_string_new ("");
417 g_string_append_c (dpb_string, isc_dpb_version1);
418
419 /* Set user name */
420 if (fb_user) {
421 size_t len;
422 len = strlen (fb_user);
423 if (len > 256) {
424 gda_connection_add_event_string (cnc, _("The parameter '%s' is too long"), "USERNAME");
425 g_string_free (dpb_string, TRUE);
426 return FALSE;
427 }
428 g_string_append_c (dpb_string, isc_dpb_user_name);
429 g_string_append_c (dpb_string, len);
430 g_string_append (dpb_string, fb_user);
431 }
432
433 /* Set password */
434 if (fb_password) {
435 size_t len;
436 len = strlen (fb_password);
437 if (len > 256) {
438 gda_connection_add_event_string (cnc, _("The parameter '%s' is too long"), "PASSWORD");
439 g_string_free (dpb_string, TRUE);
440 return FALSE;
441 }
442 g_string_append_c (dpb_string, isc_dpb_password);
443 g_string_append_c (dpb_string, len);
444 g_string_append (dpb_string, fb_password);
445
446 }
447
448 /* Set character set */
449 g_string_append_c (dpb_string, isc_dpb_lc_ctype);
450 g_string_append_c (dpb_string, strlen ("UTF8"));
451 g_string_append (dpb_string, "UTF8");
452
453 if (fb_host)
454 fb_conn = g_strconcat (fb_host, ":", fb_db, NULL);
455 else {
456 gchar *tmp;
457 tmp = g_strdup_printf ("%s%s", fb_db, FILE_EXTENSION);
458 fb_conn = g_build_filename (fb_dir, tmp, NULL);
459 g_free (tmp);
460
461 if (! g_file_test (fb_conn, G_FILE_TEST_EXISTS)) {
462 g_free (fb_conn);
463 fb_conn = g_build_filename (fb_dir, fb_db, NULL);
464 }
465 }
466
467 ISC_STATUS_ARRAY status_vector;
468 isc_db_handle handle = 0L;
469 if (isc_attach_database (status_vector, strlen (fb_conn), fb_conn, &handle,
470 dpb_string->len, dpb_string->str)) {
471 ISC_SCHAR *msg;
472 const ISC_STATUS *p = status_vector;
473 GdaConnectionEvent *ev;
474
475 msg = g_new0 (ISC_SCHAR, 512);
476 fb_interpret (msg, 511, &p);
477 ev = gda_connection_add_event_string (cnc, "%s", msg);
478 g_free (msg);
479 gda_connection_event_set_code (ev, isc_sqlcode (status_vector));
480
481 g_free (fb_conn);
482 g_string_free (dpb_string, TRUE);
483 return FALSE;
484 }
485
486 /* connection is now opened:
487 * Create a new instance of the provider specific data associated to a connection (FirebirdConnectionData),
488 * and set its contents, and open the real connection to the database */
489 FirebirdConnectionData *cdata;
490 cdata = g_new0 (FirebirdConnectionData, 1);
491 cdata->handle = handle;
492 cdata->dpb = g_string_free (dpb_string, FALSE);
493 cdata->dbname = fb_conn;
494 cdata->server_version = fb_server_get_version (cdata);
495
496 gda_connection_internal_set_provider_data (cnc, cdata, (GDestroyNotify) gda_firebird_free_cnc_data);
497
498 return TRUE;
499 }
500
501 /*
502 * Close connection request
503 *
504 * In this function, the following _must_ be done:
505 * - Actually close the connection to the database using @cnc's associated FirebirdConnectionData structure
506 * - Free the FirebirdConnectionData structure and its contents
507 *
508 * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR gonnection event must be added to @cnc)
509 */
510 static gboolean
gda_firebird_provider_close_connection(GdaServerProvider * provider,GdaConnection * cnc)511 gda_firebird_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc)
512 {
513 FirebirdConnectionData *cdata;
514
515 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
516 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
517
518 /* Close the connection using the C API */
519 cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data (cnc);
520 if (!cdata)
521 return FALSE;
522
523 /* detach from database */
524 isc_detach_database (cdata->status, &(cdata->handle));
525 cdata->handle = 0L;
526
527 /* Free the FirebirdConnectionData structure and its contents*/
528 gda_firebird_free_cnc_data (cdata);
529 gda_connection_internal_set_provider_data (cnc, NULL, NULL);
530
531 return TRUE;
532 }
533
534 /*
535 * Server version request
536 *
537 * Returns the server version as a string, which should be stored in @cnc's associated FirebirdConnectionData structure
538 */
539 static const gchar *
gda_firebird_provider_get_server_version(GdaServerProvider * provider,GdaConnection * cnc)540 gda_firebird_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc)
541 {
542 FirebirdConnectionData *cdata;
543
544 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
545 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
546
547 cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data (cnc);
548 if (!cdata)
549 return FALSE;
550
551 return ((const gchar *) cdata->server_version);
552 }
553
554 /*
555 * Get database request
556 *
557 * Returns the server version as a string, which should be stored in @cnc's associated FirebirdConnectionData structure
558 */
559 static const gchar *
gda_firebird_provider_get_database(GdaServerProvider * provider,GdaConnection * cnc)560 gda_firebird_provider_get_database (GdaServerProvider *provider, GdaConnection *cnc)
561 {
562 FirebirdConnectionData *cdata;
563
564 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
565 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
566
567 cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data (cnc);
568 if (!cdata)
569 return NULL;
570
571 return (const gchar *) cdata->dbname;
572 }
573
574 /*
575 * Support operation request
576 *
577 * Tells what the implemented server operations are. To add support for an operation, the following steps are required:
578 * - create a firebird_specs_....xml.in file describing the required and optional parameters for the operation
579 * - add it to the Makefile.am
580 * - make this method return TRUE for the operation type
581 * - implement the gda_firebird_provider_render_operation() and gda_firebird_provider_perform_operation() methods
582 *
583 */
584 static gboolean
gda_firebird_provider_supports_operation(GdaServerProvider * provider,GdaConnection * cnc,GdaServerOperationType type,GdaSet * options)585 gda_firebird_provider_supports_operation (GdaServerProvider *provider, GdaConnection *cnc,
586 GdaServerOperationType type, GdaSet *options)
587 {
588 if (cnc) {
589 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
590 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
591 }
592
593 return FALSE;
594
595 switch (type) {
596 case GDA_SERVER_OPERATION_CREATE_DB:
597 case GDA_SERVER_OPERATION_DROP_DB:
598 return FALSE;
599
600 case GDA_SERVER_OPERATION_CREATE_TABLE:
601 return TRUE;
602 case GDA_SERVER_OPERATION_DROP_TABLE:
603 case GDA_SERVER_OPERATION_RENAME_TABLE:
604
605 case GDA_SERVER_OPERATION_ADD_COLUMN:
606
607 case GDA_SERVER_OPERATION_CREATE_INDEX:
608 case GDA_SERVER_OPERATION_DROP_INDEX:
609
610 case GDA_SERVER_OPERATION_CREATE_VIEW:
611 case GDA_SERVER_OPERATION_DROP_VIEW:
612 default:
613 return FALSE;
614 }
615 }
616
617 /*
618 * Create operation request
619 *
620 * Creates a #GdaServerOperation. The following code is generic and should only be changed
621 * if some further initialization is required, or if operation's contents is dependent on @cnc
622 */
623 static GdaServerOperation *
gda_firebird_provider_create_operation(GdaServerProvider * provider,GdaConnection * cnc,GdaServerOperationType type,GdaSet * options,GError ** error)624 gda_firebird_provider_create_operation (GdaServerProvider *provider, GdaConnection *cnc,
625 GdaServerOperationType type, GdaSet *options, GError **error)
626 {
627 gchar *file;
628 GdaServerOperation *op;
629 gchar *str;
630 gchar *dir;
631
632 if (cnc) {
633 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
634 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
635 }
636
637 file = g_utf8_strdown (gda_server_operation_op_type_to_string (type), -1);
638 str = g_strdup_printf ("firebird_specs_%s.xml", file);
639 g_free (file);
640
641 dir = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, NULL);
642 file = gda_server_provider_find_file (provider, dir, str);
643 g_free (dir);
644 g_free (str);
645
646 if (! file) {
647 g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_FILE_NOT_FOUND_ERROR,
648 _("Missing spec. file '%s'"), file);
649 return NULL;
650 }
651
652 op = gda_server_operation_new (type, file);
653 g_free (file);
654
655 return op;
656 }
657
658 /*
659 * Render operation request
660 */
661 static gchar *
gda_firebird_provider_render_operation(GdaServerProvider * provider,GdaConnection * cnc,GdaServerOperation * op,GError ** error)662 gda_firebird_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc,
663 GdaServerOperation *op, GError **error)
664 {
665 gchar *sql = NULL;
666 gchar *file;
667 gchar *str;
668 gchar *dir;
669
670 if (cnc) {
671 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
672 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
673 }
674
675 /* test @op's validity */
676 file = g_utf8_strdown (gda_server_operation_op_type_to_string (gda_server_operation_get_op_type (op)), -1);
677 str = g_strdup_printf ("firebird_specs_%s.xml", file);
678 g_free (file);
679
680 dir = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, NULL);
681 file = gda_server_provider_find_file (provider, dir, str);
682 g_free (dir);
683 g_free (str);
684
685 if (! file) {
686 g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_FILE_NOT_FOUND_ERROR,
687 _("Missing spec. file '%s'"), file);
688 return NULL;
689 }
690 if (!gda_server_operation_is_valid (op, file, error)) {
691 g_free (file);
692 return NULL;
693 }
694 g_free (file);
695
696 /* actual rendering */
697 switch (gda_server_operation_get_op_type (op)) {
698 case GDA_SERVER_OPERATION_CREATE_DB:
699 case GDA_SERVER_OPERATION_DROP_DB:
700 sql = NULL;
701 break;
702 case GDA_SERVER_OPERATION_CREATE_TABLE:
703 sql = gda_firebird_render_CREATE_TABLE (provider, cnc, op, error);
704 break;
705 case GDA_SERVER_OPERATION_DROP_TABLE:
706 case GDA_SERVER_OPERATION_RENAME_TABLE:
707 case GDA_SERVER_OPERATION_ADD_COLUMN:
708 case GDA_SERVER_OPERATION_CREATE_INDEX:
709 case GDA_SERVER_OPERATION_DROP_INDEX:
710 case GDA_SERVER_OPERATION_CREATE_VIEW:
711 case GDA_SERVER_OPERATION_DROP_VIEW:
712 sql = NULL;
713 break;
714 default:
715 g_assert_not_reached ();
716 }
717 return sql;
718 }
719
720 /*
721 * Perform operation request
722 */
723 static gboolean
gda_firebird_provider_perform_operation(GdaServerProvider * provider,GdaConnection * cnc,GdaServerOperation * op,guint * task_id,GdaServerProviderAsyncCallback async_cb,gpointer cb_data,GError ** error)724 gda_firebird_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
725 GdaServerOperation *op, guint *task_id,
726 GdaServerProviderAsyncCallback async_cb, gpointer cb_data, GError **error)
727 {
728 GdaServerOperationType optype;
729
730 /* If asynchronous connection opening is not supported, then exit now */
731 if (async_cb) {
732 g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
733 "%s", _("Provider does not support asynchronous server operation"));
734 return FALSE;
735 }
736
737 if (cnc) {
738 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
739 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
740 }
741 optype = gda_server_operation_get_op_type (op);
742 switch (optype) {
743 case GDA_SERVER_OPERATION_CREATE_DB:
744 case GDA_SERVER_OPERATION_DROP_DB:
745 default:
746 /* use the SQL from the provider to perform the action */
747 return gda_server_provider_perform_operation_default (provider, cnc, op, error);
748 }
749 }
750
751 /*
752 * Begin transaction request
753 */
754 static gboolean
gda_firebird_provider_begin_transaction(GdaServerProvider * provider,GdaConnection * cnc,const gchar * name,GdaTransactionIsolation level,GError ** error)755 gda_firebird_provider_begin_transaction (GdaServerProvider *provider,
756 GdaConnection *cnc,
757 const gchar *name,
758 GdaTransactionIsolation level,
759 GError **error)
760 {
761 FirebirdConnectionData *cdata;
762 static char tpb[] = {
763 isc_tpb_version3,
764 isc_tpb_write,
765 isc_tpb_read_committed,
766 isc_tpb_rec_version,
767 isc_tpb_wait
768 };
769
770 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
771 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
772 if (level != GDA_TRANSACTION_ISOLATION_UNKNOWN) {
773 gda_connection_add_event_string (cnc, "Provider does not handle that kind of transaction");
774 return FALSE;
775 }
776
777 cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
778 if (!cdata)
779 return FALSE;
780
781 if (cdata->ftr) {
782 gda_connection_add_event_string (cnc, _("Transaction already started"));
783 return FALSE;
784 }
785
786 /* start the transaction */
787 cdata->ftr = g_new0 (isc_tr_handle, 1);
788 if (isc_start_transaction (cdata->status, (cdata->ftr), 1, &(cdata->handle),
789 (unsigned short) sizeof (tpb), &tpb)) {
790 _gda_firebird_make_error (cnc, 0);
791 g_free (cdata->ftr);
792 cdata->ftr = NULL;
793
794 return FALSE;
795 }
796
797 gda_connection_internal_transaction_started (cnc, NULL, name, level);
798
799 return TRUE;
800 }
801
802 /*
803 * Commit transaction request
804 */
805 static gboolean
gda_firebird_provider_commit_transaction(GdaServerProvider * provider,GdaConnection * cnc,const gchar * name,GError ** error)806 gda_firebird_provider_commit_transaction (GdaServerProvider *provider, GdaConnection *cnc,
807 const gchar *name, GError **error)
808 {
809 FirebirdConnectionData *cdata;
810 gboolean result;
811
812 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
813 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
814
815 cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
816 if (!cdata)
817 return FALSE;
818
819 if (!cdata->ftr) {
820 gda_connection_add_event_string (cnc, _("Invalid transaction handle"));
821 return FALSE;
822 }
823
824 if (isc_commit_transaction (cdata->status, cdata->ftr)) {
825 _gda_firebird_make_error (cnc, 0);
826 result = FALSE;
827 }
828 else {
829 gda_connection_internal_transaction_committed (cnc, name);
830 result = TRUE;
831 }
832
833 g_free (cdata->ftr);
834 cdata->ftr = NULL;
835
836 return result;
837 }
838
839 /*
840 * Rollback transaction request
841 */
842 static gboolean
gda_firebird_provider_rollback_transaction(GdaServerProvider * provider,GdaConnection * cnc,const gchar * name,GError ** error)843 gda_firebird_provider_rollback_transaction (GdaServerProvider *provider, GdaConnection *cnc,
844 const gchar *name, GError **error)
845 {
846 FirebirdConnectionData *cdata;
847 gboolean result = FALSE;
848 //WHERE_AM_I;
849 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
850 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
851
852 cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
853 if (!cdata)
854 return FALSE;
855
856 if (!cdata->ftr) {
857 gda_connection_add_event_string (cnc, _("Invalid transaction handle"));
858 return FALSE;
859 }
860
861 if (isc_rollback_transaction (cdata->status, cdata->ftr)) {
862 _gda_firebird_make_error (cnc, 0);
863 result = FALSE;
864 }
865 else {
866 gda_connection_internal_transaction_committed (cnc, name);
867 result = TRUE;
868 }
869
870 g_free (cdata->ftr);
871 cdata->ftr = NULL;
872
873 return result;
874 }
875
876 /*
877 * Add savepoint request
878 */
879 static gboolean
gda_firebird_provider_add_savepoint(GdaServerProvider * provider,GdaConnection * cnc,const gchar * name,GError ** error)880 gda_firebird_provider_add_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
881 const gchar *name, GError **error)
882 {
883 FirebirdConnectionData *cdata;
884
885 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
886 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
887
888 cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
889 if (!cdata)
890 return FALSE;
891
892 TO_IMPLEMENT;
893
894 return FALSE;
895 }
896
897 /*
898 * Rollback savepoint request
899 */
900 static gboolean
gda_firebird_provider_rollback_savepoint(GdaServerProvider * provider,GdaConnection * cnc,const gchar * name,GError ** error)901 gda_firebird_provider_rollback_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
902 const gchar *name, GError **error)
903 {
904 FirebirdConnectionData *cdata;
905
906 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
907 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
908
909 cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
910 if (!cdata)
911 return FALSE;
912
913 TO_IMPLEMENT;
914
915 return FALSE;
916 }
917
918 /*
919 * Delete savepoint request
920 */
921 static gboolean
gda_firebird_provider_delete_savepoint(GdaServerProvider * provider,GdaConnection * cnc,const gchar * name,GError ** error)922 gda_firebird_provider_delete_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
923 const gchar *name, GError **error)
924 {
925 FirebirdConnectionData *cdata;
926
927 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
928 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
929
930 cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
931 if (!cdata)
932 return FALSE;
933
934 TO_IMPLEMENT;
935
936 return FALSE;
937 }
938
939 /*
940 * Feature support request
941 */
942 static gboolean
gda_firebird_provider_supports_feature(GdaServerProvider * provider,GdaConnection * cnc,GdaConnectionFeature feature)943 gda_firebird_provider_supports_feature (GdaServerProvider *provider, GdaConnection *cnc, GdaConnectionFeature feature)
944 {
945 if (cnc) {
946 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
947 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
948 }
949
950 switch (feature) {
951 case GDA_CONNECTION_FEATURE_SQL :
952 return TRUE;
953 default:
954 return FALSE;
955 }
956 }
957
958 /*
959 * Get data handler request
960 *
961 * This method allows one to obtain a pointer to a #GdaDataHandler object specific to @type or @dbms_type (@dbms_type
962 * must be considered only if @type is not a valid GType).
963 *
964 * A data handler allows one to convert a value between its different representations which are a human readable string,
965 * an SQL representation and a GValue.
966 *
967 * The recommended method is to create GdaDataHandler objects only when they are needed and to keep a reference to them
968 * for further usage, using the gda_server_provider_handler_declare() method.
969 *
970 * The implementation shown here does not define any specific data handler, but there should be some for at least
971 * binary and time related types.
972 */
973 static GdaDataHandler *
gda_firebird_provider_get_data_handler(GdaServerProvider * provider,GdaConnection * cnc,GType type,const gchar * dbms_type)974 gda_firebird_provider_get_data_handler (GdaServerProvider *provider, GdaConnection *cnc,
975 GType type, const gchar *dbms_type)
976 {
977 GdaDataHandler *dh;
978 if (cnc) {
979 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
980 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
981 }
982
983 if (type == G_TYPE_INVALID) {
984 TO_IMPLEMENT; /* use @dbms_type */
985 dh = NULL;
986 }
987 else if ((type == GDA_TYPE_BINARY) ||
988 (type == GDA_TYPE_BLOB)) {
989 TO_IMPLEMENT; /* define data handlers for these types */
990 dh = NULL;
991 }
992 else if ((type == GDA_TYPE_TIME) ||
993 (type == GDA_TYPE_TIMESTAMP) ||
994 (type == G_TYPE_DATE)) {
995 TO_IMPLEMENT; /* define data handlers for these types */
996 dh = NULL;
997 }
998 else
999 dh = gda_server_provider_handler_use_default (provider, type);
1000
1001 return dh;
1002 }
1003
1004 /*
1005 * Get default DBMS type request
1006 *
1007 * This method returns the "preferred" DBMS type for GType
1008 */
1009 static const gchar*
gda_firebird_provider_get_default_dbms_type(GdaServerProvider * provider,GdaConnection * cnc,GType type)1010 gda_firebird_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConnection *cnc, GType type)
1011 {
1012 if (cnc) {
1013 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
1014 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
1015 }
1016
1017 TO_IMPLEMENT;
1018
1019 if ((type == G_TYPE_INT64) ||
1020 (type == G_TYPE_INT) ||
1021 (type == GDA_TYPE_SHORT) ||
1022 (type == GDA_TYPE_USHORT) ||
1023 (type == G_TYPE_CHAR) ||
1024 (type == G_TYPE_UCHAR) ||
1025 (type == G_TYPE_ULONG) ||
1026 (type == G_TYPE_UINT) ||
1027 (type == G_TYPE_UINT64))
1028 return "integer";
1029
1030 if ((type == GDA_TYPE_BINARY) ||
1031 (type == GDA_TYPE_BLOB))
1032 return "blob";
1033
1034 if (type == G_TYPE_BOOLEAN)
1035 return "smallint";
1036
1037 if ((type == G_TYPE_DATE) ||
1038 (type == GDA_TYPE_GEOMETRIC_POINT) ||
1039 (type == G_TYPE_OBJECT) ||
1040 (type == G_TYPE_STRING) ||
1041 (type == GDA_TYPE_TIME) ||
1042 (type == GDA_TYPE_TIMESTAMP))
1043 return "string";
1044
1045 if ((type == G_TYPE_DOUBLE) ||
1046 (type == GDA_TYPE_NUMERIC) ||
1047 (type == G_TYPE_FLOAT))
1048 return "double";
1049
1050 if (type == GDA_TYPE_TIME)
1051 return "time";
1052 if (type == GDA_TYPE_TIMESTAMP)
1053 return "timestamp";
1054 if (type == G_TYPE_DATE)
1055 return "date";
1056
1057 if ((type == GDA_TYPE_NULL) ||
1058 (type == G_TYPE_GTYPE))
1059 return NULL;
1060
1061 return "text";
1062 }
1063
1064 /*
1065 * Create parser request
1066 *
1067 * This method is responsible for creating a #GdaSqlParser object specific to the SQL dialect used
1068 * by the database. See the PostgreSQL provider implementation for an example.
1069 */
1070 static GdaSqlParser *
gda_firebird_provider_create_parser(GdaServerProvider * provider,GdaConnection * cnc)1071 gda_firebird_provider_create_parser (GdaServerProvider *provider, GdaConnection *cnc)
1072 {
1073 return (GdaSqlParser*) g_object_new (GDA_TYPE_FIREBIRD_PARSER, "tokenizer-flavour",
1074 GDA_SQL_PARSER_FLAVOUR_STANDARD, NULL);
1075 }
1076
1077 /*
1078 * GdaStatement to SQL request
1079 *
1080 * This method renders a #GdaStatement into its SQL representation.
1081 *
1082 * The implementation show here simply calls gda_statement_to_sql_extended() but the rendering
1083 * can be specialized to the database's SQL dialect, see the implementation of gda_statement_to_sql_extended()
1084 * and SQLite's specialized rendering for more details
1085 */
1086 static gchar *
gda_firebird_provider_statement_to_sql(GdaServerProvider * provider,GdaConnection * cnc,GdaStatement * stmt,GdaSet * params,GdaStatementSqlFlag flags,GSList ** params_used,GError ** error)1087 gda_firebird_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection *cnc,
1088 GdaStatement *stmt, GdaSet *params, GdaStatementSqlFlag flags,
1089 GSList **params_used, GError **error)
1090 {
1091 //gchar *str;
1092 //GdaSqlRenderingContext context;
1093
1094 g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
1095 if (cnc) {
1096 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
1097 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
1098 }
1099
1100 return gda_statement_to_sql_extended (stmt, cnc, params, flags, params_used, error);
1101 }
1102
1103
1104 /*
1105 * Statement prepare request
1106 */
1107 static GdaFirebirdPStmt *real_prepare (GdaServerProvider *provider, GdaConnection *cnc, GdaStatement *stmt, GError **error);
1108
1109
1110 /*
1111 * Statement prepare request
1112 *
1113 * This methods "converts" @stmt into a prepared statement. A prepared statement is a notion
1114 * specific in its implementation details to the C API used here. If successfull, it must create
1115 * a new #GdaFirebirdPStmt object and declare it to @cnc.
1116 */
1117 static gboolean
gda_firebird_provider_statement_prepare(GdaServerProvider * provider,GdaConnection * cnc,GdaStatement * stmt,GError ** error)1118 gda_firebird_provider_statement_prepare (GdaServerProvider *provider, GdaConnection *cnc,
1119 GdaStatement *stmt, GError **error)
1120 {
1121 GdaFirebirdPStmt *ps;
1122 FirebirdConnectionData *cdata;
1123 gboolean result = FALSE;
1124
1125 int buffer[2048];
1126
1127 XSQLVAR *var;
1128 short num_cols, i;
1129 short length, alignment, type, offset;
1130 int fetch_stat;
1131 static char stmt_info[] = { isc_info_sql_stmt_type };
1132 char info_buffer[20];
1133 short l;
1134
1135 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1136 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1137 g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE);
1138
1139 /* fetch prepares stmt if already done */
1140 ps = (GdaFirebirdPStmt *) gda_connection_get_prepared_statement (cnc, stmt);
1141 if (ps)
1142 return TRUE;
1143
1144 /* render as SQL understood by Firebird */
1145 GdaSet *params = NULL;
1146 gchar *sql = NULL;
1147 GSList *used_params = NULL;
1148 gboolean trans_started = FALSE;
1149
1150 if (!gda_statement_get_parameters (stmt, ¶ms, error))
1151 goto out_err;
1152
1153 sql = gda_firebird_provider_statement_to_sql (provider, NULL, stmt, params, GDA_STATEMENT_SQL_PARAMS_AS_UQMARK,
1154 &used_params, error);
1155 if (!sql)
1156 goto out_err;
1157
1158 /* get private connection data */
1159 cdata = (FirebirdConnectionData *) gda_connection_internal_get_provider_data (cnc);
1160 if (!cdata)
1161 goto out_err;
1162
1163 /* create the stmt object */
1164 ps = (GdaFirebirdPStmt *) g_object_new (GDA_TYPE_FIREBIRD_PSTMT, NULL);
1165 ps->stmt_h = 0L;
1166
1167 /* actually prepare statement */
1168 if (isc_dsql_allocate_statement (cdata->status, &(cdata->handle), &(ps->stmt_h)))
1169 goto out_err;
1170
1171 if (! cdata->ftr) {
1172 if (!gda_firebird_provider_begin_transaction (provider, cnc, "prepare_tr",
1173 GDA_TRANSACTION_ISOLATION_UNKNOWN, error))
1174 goto out_err;
1175 trans_started = TRUE;
1176 }
1177
1178 if (! ps->sqlda){
1179 /*
1180 * Allocate enough space for 20 fields.
1181 * If more fields get selected, re-allocate SQLDA later.
1182 */
1183 ps->sqlda = (XSQLDA *) g_malloc (XSQLDA_LENGTH(20)); //g_new0(XSQLDA, 20);
1184 ps->sqlda->sqln = 20;
1185 ps->sqlda->version = SQLDA_VERSION1;
1186 }
1187
1188 /* now prepare the fb statement */
1189 if (isc_dsql_prepare (cdata->status, cdata->ftr, &(ps->stmt_h), 0, sql, SQL_DIALECT_CURRENT, ps->sqlda)) {
1190 _gda_firebird_make_error (cnc, 0);
1191 goto out_err;
1192 }
1193
1194 /* What is the statement type of this statement?
1195 *
1196 * stmt_info is a 1 byte info request. info_buffer is a buffer
1197 * large enough to hold the returned info packet
1198 * The info_buffer returned contains a isc_info_sql_stmt_type in the first byte,
1199 * two bytes of length, and a statement_type token.
1200 */
1201
1202 if (!isc_dsql_sql_info (cdata->status, &(ps->stmt_h), sizeof (stmt_info), stmt_info,
1203 sizeof (info_buffer), info_buffer)) {
1204 l = (short) isc_vax_integer ((char *) info_buffer + 1, 2);
1205 ps->statement_type = isc_vax_integer ((char *) info_buffer + 3, l);
1206 }
1207
1208 ps->is_non_select = !ps->sqlda->sqld;
1209
1210 if (!ps->is_non_select){
1211 /*
1212 * Process select statements.
1213 */
1214
1215 num_cols = ps->sqlda->sqld;
1216
1217 /* Need more room. */
1218 if (ps->sqlda->sqln < num_cols) {
1219 //g_print("Only have space for %d columns, need to re-allocate more space for %d columns\n", ps->sqlda->sqln, ps->sqlda->sqld );
1220 g_free (ps->sqlda);
1221 ps->sqlda = (XSQLDA *) g_malloc(XSQLDA_LENGTH(num_cols)); //g_new0(XSQLDA, num_cols);
1222 ps->sqlda->sqln = num_cols;
1223 ps->sqlda->version = SQLDA_VERSION1;
1224
1225 if (isc_dsql_describe (cdata->status, &(ps->stmt_h), SQL_DIALECT_V6, ps->sqlda))
1226 goto out_err;
1227 num_cols = ps->sqlda->sqld;
1228 }
1229
1230 /*
1231 * Set up SQLDA.
1232 */
1233 //g_print("set up SQLDA\n");
1234 for (var = ps->sqlda->sqlvar, offset = 0, i = 0; i < num_cols; var++, i++) {
1235 length = alignment = var->sqllen;
1236 type = var->sqltype & ~1;
1237 var->sqlname[var->sqlname_length + 1] = '\0';
1238 var->relname[var->relname_length + 1] = '\0';
1239 var->ownname[var->ownname_length + 1] = '\0';
1240 var->aliasname[var->aliasname_length + 1] = '\0';
1241
1242 if (type == SQL_TEXT)
1243 alignment = 1;
1244 else if (type == SQL_VARYING) {
1245 length += sizeof (short) + 1;
1246 alignment = sizeof (short);
1247 }
1248
1249 /* RISC machines are finicky about word alignment
1250 * So the output buffer values must be placed on
1251 * word boundaries where appropriate
1252 */
1253 gchar *buff = g_new0(gchar, 2048);
1254
1255 offset = FB_ALIGN(offset, alignment);
1256 var->sqldata = (char *) buff + offset;
1257 offset += length;
1258 offset = FB_ALIGN(offset, sizeof (short));
1259 var->sqlind = (short*) ((char *) buff + offset);
1260 offset += sizeof (short);
1261 }
1262 }
1263
1264 //SETUP INPUT-SQLDA
1265 //NOW ALLOCATE SPACE FOR THE INPUT PARAMETERS
1266 if (ps->input_sqlda)
1267 g_free(ps->input_sqlda);
1268
1269 ps->input_sqlda = (XSQLDA *) g_new0(XSQLDA, 1);
1270 ps->input_sqlda->version = SQLDA_VERSION1;
1271 ps->input_sqlda->sqln = 1;
1272
1273 isc_dsql_describe_bind(cdata->status, &(ps->stmt_h), 1, ps->input_sqlda);
1274
1275 if ((cdata->status[0] == 1) && cdata->status[1]){
1276 // Process error
1277 isc_print_status (cdata->status);
1278 goto out_err;
1279 }
1280
1281 if (ps->input_sqlda->sqld > ps->input_sqlda->sqln){
1282 gint n = ps->input_sqlda->sqld;
1283 g_free(ps->input_sqlda);
1284 ps->input_sqlda = (XSQLDA *) g_new0(XSQLDA, n);
1285 ps->input_sqlda->sqln= n;
1286 ps->input_sqlda->version = SQLDA_VERSION1;
1287
1288 isc_dsql_describe_bind(cdata->status, &(ps->stmt_h), n, ps->input_sqlda);
1289
1290 if ((cdata->status[0] == 1) && cdata->status[1]){
1291 // Process error
1292 isc_print_status(cdata->status);
1293 goto out_err;
1294 }
1295 }
1296
1297 if (!params){
1298 /* no input paramaters so clear the input_sqlda */
1299 g_free (ps->input_sqlda);
1300 ps->input_sqlda = NULL;
1301 }
1302
1303 /* make a list of the parameter names used in the statement */
1304 GSList *param_ids = NULL;
1305 if (used_params) {
1306 GSList *list;
1307 for (list = used_params; list; list = list->next) {
1308 const gchar *cid;
1309 cid = gda_holder_get_id (GDA_HOLDER (list->data));
1310 if (cid) {
1311 param_ids = g_slist_append (param_ids, g_strdup (cid));
1312 }
1313 else {
1314 g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_PREPARE_STMT_ERROR,
1315 "%s", _("Unnamed parameter is not allowed in prepared statements"));
1316 g_slist_foreach (param_ids, (GFunc) g_free, NULL);
1317 g_slist_free (param_ids);
1318 goto out_err;
1319 }
1320 }
1321
1322 g_slist_free (used_params);
1323 }
1324
1325
1326 /* create a prepared statement */
1327 //g_print("Adding the prepared statement to GDA.\n");
1328 //ps = (GdaFirebirdPStmt *) g_object_new (GDA_TYPE_FIREBIRD_PSTMT, NULL);
1329 gda_pstmt_set_gda_statement (_GDA_PSTMT (ps), stmt);
1330 _GDA_PSTMT (ps)->param_ids = param_ids;
1331 _GDA_PSTMT (ps)->sql = sql;
1332
1333 gda_connection_add_prepared_statement (cnc, stmt, (GdaPStmt *) ps);
1334 //g_object_unref (ps);
1335
1336 result = TRUE;
1337
1338 out_err:
1339 if (!result){
1340 if (trans_started)
1341 gda_firebird_provider_rollback_transaction (provider, cnc, "prepare_tr", NULL);
1342 g_free (sql);
1343 }
1344
1345 if (params)
1346 g_object_unref (params);
1347
1348 return result;
1349 }
1350
1351 /*
1352 * Execute statement request
1353 *
1354 * Executes a statement. This method should do the following:
1355 * - try to prepare the statement if not yet done
1356 * - optionnally reset the prepared statement
1357 * - bind the variables's values (which are in @params)
1358 * - add a connection event to log the execution
1359 * - execute the prepared statement
1360 *
1361 * If @stmt is an INSERT statement and @last_inserted_row is not NULL then additional actions must be taken to return the
1362 * actual inserted row
1363 */
1364 static GObject *
gda_firebird_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)1365 gda_firebird_provider_statement_execute (GdaServerProvider *provider,
1366 GdaConnection *cnc,
1367 GdaStatement *stmt,
1368 GdaSet *params,
1369 GdaStatementModelUsage model_usage,
1370 GType *col_types,
1371 GdaSet **last_inserted_row,
1372 guint *task_id,
1373 GdaServerProviderExecCallback async_cb,
1374 gpointer cb_data,
1375 GError **error)
1376 {
1377 GdaFirebirdPStmt *ps;
1378 FirebirdConnectionData *cdata;
1379 GSList *mem_to_free = NULL;
1380 XSQLVAR *fbvar;
1381
1382 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
1383 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
1384 g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
1385
1386 /* If asynchronous connection opening is not supported, then exit now */
1387 if (async_cb) {
1388 g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
1389 "%s", _("Provider does not support asynchronous statement execution"));
1390 return FALSE;
1391 }
1392
1393 cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1394 if (!cdata)
1395 return FALSE;
1396
1397 /* get/create new prepared statement */
1398 ps = (GdaFirebirdPStmt *)gda_connection_get_prepared_statement (cnc, stmt);
1399 if (!ps) {
1400 g_print("prepare statement in execute stage\n");
1401 if (!gda_firebird_provider_statement_prepare (provider, cnc, stmt, NULL)) {
1402 /* this case can appear for example if some variables are used in places
1403 * where the C API cannot allow them (for example if the variable is the table name
1404 * in a SELECT statement). The action here is to get the actual SQL code for @stmt,
1405 * and use that SQL instead of @stmt to create another GdaFirebirdPStmt object.
1406 */
1407 g_print("Could not prepare the statement :-(.\n");
1408 //TO_IMPLEMENT;
1409 return NULL;
1410 }
1411
1412 ps = (GdaFirebirdPStmt *)gda_connection_get_prepared_statement (cnc, stmt);
1413 }
1414 g_object_ref(ps);
1415 g_assert (ps);
1416
1417 /* optionnally reset the prepared statement if required by the API */
1418
1419 /* bind statement's parameters */
1420 GSList *list;
1421 GdaConnectionEvent *event = NULL;
1422 int i;
1423
1424 for (i = 1, list = _GDA_PSTMT (ps)->param_ids; list; list = list->next, i++) {
1425 const gchar *pname = (gchar *) list->data;
1426 GdaHolder *h;
1427 g_print("binding paramater %s\n", pname);
1428 /* find requested parameter */
1429 if (!params) {
1430 event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
1431 gda_connection_event_set_description (event, _("Missing parameter(s) to execute query"));
1432 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
1433 GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR,
1434 "%s", _("Missing parameter(s) to execute query"));
1435 break;
1436 }
1437
1438 h = gda_set_get_holder (params, pname);
1439 if (!h) {
1440 gchar *tmp = gda_alphanum_to_text (g_strdup (pname + 1));
1441 if (tmp) {
1442 h = gda_set_get_holder (params, tmp);
1443 g_free (tmp);
1444 }
1445 }
1446 if (!h) {
1447 gchar *str;
1448 str = g_strdup_printf (_("Missing parameter '%s' to execute query"), pname);
1449 event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
1450 gda_connection_event_set_description (event, str);
1451 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
1452 GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, "%s", str);
1453 g_free (str);
1454 break;
1455 }
1456
1457 /* actual binding using the C API, for parameter at position @i */
1458 if (ps->input_sqlda == NULL) continue;
1459
1460 g_print("bind the value to SQLDA\n");
1461 const GValue* value = gda_holder_get_value (h);
1462
1463 fbvar = &(ps->input_sqlda->sqlvar[i-1]);
1464 if (!value || gda_value_is_null (value)) {
1465 short *flag0 = g_new0 (short, 1);
1466 mem_to_free = g_slist_prepend (mem_to_free, flag0);
1467
1468 fbvar->sqlind = flag0; //TELLS FIREBIRD THAT THE COLUMN IS NULL
1469 *flag0 = -1; //TELLS FIREBIRD THAT THE COLUMN IS NULL
1470 }
1471 else if (G_VALUE_TYPE (value) == GDA_TYPE_TIMESTAMP) {
1472 /*
1473 const GdaTimestamp *ts;
1474
1475 ts = gda_value_get_timestamp (value);
1476 if (!ts) {
1477 fbvar->sqldata_type = MYSQL_TYPE_NULL;
1478 fbvar.is_null = (my_bool*)1;
1479 }
1480 else {
1481 MYSQL_TIME *mtime;
1482 mtime = g_new0 (MYSQL_TIME, 1);
1483 mem_to_free = g_slist_prepend (mem_to_free, mtime);
1484 mtime->year = ts->year;
1485 mtime->month = ts->month;
1486 mtime->day = ts->day;
1487 mtime->hour = ts->hour;
1488 mtime->minute = ts->minute;
1489 mtime->second = ts->second;
1490 mtime->second_part = ts->fraction;
1491
1492 fbvar->sqldata_type= MYSQL_TYPE_TIMESTAMP;
1493 fbvar->sqldata= (char *)mtime;
1494 fbvar->sqllen = sizeof (MYSQL_TIME);
1495 }
1496 */
1497 }
1498 else if (G_VALUE_TYPE (value) == GDA_TYPE_TIME) {
1499 /*
1500 const GdaTime *ts;
1501
1502 ts = gda_value_get_time (value);
1503 if (!ts) {
1504 fbvar->sqldata_type = MYSQL_TYPE_NULL;
1505 fbvar.is_null = (my_bool*)1;
1506 }
1507 else {
1508 MYSQL_TIME *mtime;
1509 mtime = g_new0 (MYSQL_TIME, 1);
1510 mem_to_free = g_slist_prepend (mem_to_free, mtime);
1511 mtime->hour = ts->hour;
1512 mtime->minute = ts->minute;
1513 mtime->second = ts->second;
1514 mtime->second_part = ts->fraction;
1515
1516 fbvar->sqldata_type= MYSQL_TYPE_TIME;
1517 fbvar->sqldata= (char *)mtime;
1518 fbvar->sqllen = sizeof (MYSQL_TIME);
1519 }
1520 */
1521 }
1522 else if (G_VALUE_TYPE (value) == G_TYPE_DATE) {
1523 /*
1524 const GDate *ts;
1525
1526 ts = (GDate*) g_value_get_boxed (value);
1527 if (!ts) {
1528 fbvar->sqldata_type = MYSQL_TYPE_NULL;
1529 fbvar.is_null = (my_bool*)1;
1530 }
1531 else {
1532 MYSQL_TIME *mtime;
1533 mtime = g_new0 (MYSQL_TIME, 1);
1534 mem_to_free = g_slist_prepend (mem_to_free, mtime);
1535 mtime->year = g_date_get_year (ts);
1536 mtime->month = g_date_get_month (ts);
1537 mtime->day = g_date_get_day (ts);
1538
1539 fbvar->sqldata_type= MYSQL_TYPE_DATE;
1540 fbvar->sqldata= (char *)mtime;
1541 fbvar->sqllen = sizeof (MYSQL_TIME);
1542 }
1543 */
1544 }
1545 else if (G_VALUE_TYPE (value) == G_TYPE_STRING) {
1546
1547 const gchar *str;// = "CLIENTS";
1548 short *flag0 = g_new0 (short, 1);
1549 mem_to_free = g_slist_prepend (mem_to_free, flag0);
1550
1551 str = g_value_get_string (value);
1552
1553 if (!str) {
1554 fbvar->sqlind = flag0;
1555 *flag0 = -1;
1556 }
1557 else {
1558 fbvar->sqldata = g_value_dup_string(value); //str;
1559 //g_print("string-len: %d\n", fbvar->sqllen);
1560 fbvar->sqllen = strlen (fbvar->sqldata);
1561 fbvar->sqlind = flag0;
1562 *flag0 = 0;
1563 }
1564
1565 }
1566 else if (G_VALUE_TYPE (value) == G_TYPE_DOUBLE) {
1567 gdouble *pv;
1568 short *flag0 = g_new0 (short, 1);
1569 mem_to_free = g_slist_prepend (mem_to_free, flag0);
1570
1571 pv = g_new (gdouble, 1);
1572 mem_to_free = g_slist_prepend (mem_to_free, pv);
1573 *pv = g_value_get_double (value);
1574 fbvar->sqldata = pv;
1575 fbvar->sqllen = sizeof (gdouble);
1576 fbvar->sqlind = flag0;
1577 *flag0 = 0;
1578 }
1579 else if (G_VALUE_TYPE (value) == G_TYPE_FLOAT) {
1580 gfloat *pv;
1581 short *flag0 = g_new0 (short, 1);
1582 mem_to_free = g_slist_prepend (mem_to_free, flag0);
1583
1584 pv = g_new (gfloat, 1);
1585 mem_to_free = g_slist_prepend (mem_to_free, pv);
1586 *pv = g_value_get_float (value);
1587 fbvar->sqldata = pv;
1588 fbvar->sqllen = sizeof (gfloat);
1589 fbvar->sqlind = flag0;
1590 *flag0 = 0;
1591 }
1592 else if (G_VALUE_TYPE (value) == G_TYPE_CHAR) {
1593 gchar *pv;
1594 short *flag0 = g_new0 (short, 1);
1595 mem_to_free = g_slist_prepend (mem_to_free, flag0);
1596
1597 pv = g_new (gchar, 1);
1598 mem_to_free = g_slist_prepend (mem_to_free, pv);
1599 *pv = g_value_get_schar (value);
1600 fbvar->sqldata = pv;
1601 fbvar->sqllen = sizeof (gchar);
1602 fbvar->sqlind = flag0;
1603 *flag0 = 0;
1604 }
1605 else if (G_VALUE_TYPE (value) == GDA_TYPE_SHORT) {
1606 gshort *pv;
1607 short *flag0 = g_new0 (short, 1);
1608 mem_to_free = g_slist_prepend (mem_to_free, flag0);
1609
1610 pv = g_new (gshort, 1);
1611 mem_to_free = g_slist_prepend (mem_to_free, pv);
1612 *pv = gda_value_get_short (value);
1613 fbvar->sqldata = pv;
1614 fbvar->sqllen = sizeof (gshort);
1615 fbvar->sqlind = flag0;
1616 *flag0 = 0;
1617 }
1618 else if (G_VALUE_TYPE (value) == G_TYPE_LONG) {
1619 glong *pv;
1620 short *flag0 = g_new0 (short, 1);
1621 mem_to_free = g_slist_prepend (mem_to_free, flag0);
1622
1623 pv = g_new (glong, 1);
1624 mem_to_free = g_slist_prepend (mem_to_free, pv);
1625 *pv = g_value_get_long (value);
1626 fbvar->sqldata = pv;
1627 fbvar->sqllen = sizeof (glong);
1628 fbvar->sqlind = flag0;
1629 *flag0 = 0;
1630 }
1631 else if (G_VALUE_TYPE (value) == G_TYPE_INT64) {
1632 gint64 *pv;
1633 short *flag0 = g_new0 (short, 1);
1634 mem_to_free = g_slist_prepend (mem_to_free, flag0);
1635
1636 pv = g_new (gint64, 1);
1637 mem_to_free = g_slist_prepend (mem_to_free, pv);
1638 *pv = g_value_get_long (value);
1639 fbvar->sqldata = pv;
1640 fbvar->sqllen = sizeof (gint64);
1641 fbvar->sqlind = flag0;
1642 *flag0 = 0;
1643 }
1644 else if (G_VALUE_TYPE (value) == GDA_TYPE_BLOB) {
1645 /*
1646 const GdaBinary *bin = NULL;
1647 GdaBlob *blob = (GdaBlob*) gda_value_get_blob (value);
1648
1649 bin = ((GdaBinary*) blob);
1650 if (!bin) {
1651 fbvar->sqldata_type = MYSQL_TYPE_NULL;
1652 fbvar.is_null = (my_bool*)1;
1653 }
1654 else {
1655 gchar *str = NULL;
1656 glong blob_len;
1657 if (blob->op) {
1658 blob_len = gda_blob_op_get_length (blob->op);
1659 if ((blob_len != bin->binary_length) &&
1660 ! gda_blob_op_read_all (blob->op, blob)) {
1661 // force reading the complete BLOB into memory
1662 str = _("Can't read whole BLOB into memory");
1663 }
1664 }
1665 else
1666 blob_len = bin->binary_length;
1667 if (blob_len < 0)
1668 str = _("Can't get BLOB's length");
1669 else if (blob_len >= G_MAXINT)
1670 str = _("BLOB is too big");
1671
1672 if (str) {
1673 event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
1674 gda_connection_event_set_description (event, str);
1675 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
1676 GDA_SERVER_PROVIDER_DATA_ERROR, "%s", str);
1677 break;
1678 }
1679
1680 else {
1681 fbvar->sqldata_type= MYSQL_TYPE_BLOB;
1682 fbvar->sqldata= (char *) bin->data;
1683 fbvar->sqllen = bin->binary_length;
1684 fbvar.length = NULL;
1685 }
1686 }
1687 */
1688 }
1689 else if (G_VALUE_TYPE (value) == GDA_TYPE_BINARY) {
1690 /*
1691 const GdaBinary *bin;
1692 bin = gda_value_get_binary (value);
1693 if (!bin) {
1694 fbvar->sqldata_type = MYSQL_TYPE_NULL;
1695 fbvar.is_null = (my_bool*)1;
1696 }
1697 else {
1698 fbvar->sqldata_type= MYSQL_TYPE_BLOB;
1699 fbvar->sqldata= (char *) bin->data;
1700 fbvar->sqllen = bin->binary_length;
1701 fbvar.length = NULL;
1702 }
1703 */
1704 }
1705 else {
1706 GdaDataHandler *data_handler =
1707 gda_server_provider_get_data_handler_g_type (provider, cnc,
1708 G_VALUE_TYPE (value));
1709 if (data_handler == NULL) {
1710 /* there is an error here */
1711 gchar *str;
1712 event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
1713 str = g_strdup_printf (_("Unhandled data type '%s'"),
1714 gda_g_type_to_string (G_VALUE_TYPE (value)));
1715 gda_connection_event_set_description (event, str);
1716 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
1717 GDA_SERVER_PROVIDER_DATA_ERROR, "%s", str);
1718 g_free (str);
1719 break;
1720 }
1721 else {
1722 gchar *str;
1723 short *flag0 = g_new0 (short, 1);
1724 mem_to_free = g_slist_prepend (mem_to_free, flag0);
1725
1726 str = gda_data_handler_get_str_from_value (data_handler, value);
1727 mem_to_free = g_slist_prepend (mem_to_free, str);
1728 fbvar->sqldata = str;
1729 fbvar->sqllen = strlen (str);
1730 fbvar->sqlind = flag0;
1731 *flag0 = 0;
1732 }
1733 }
1734 }
1735
1736 if (event) {
1737 gda_connection_add_event (cnc, event);
1738 return NULL;
1739 }
1740
1741 /* add a connection event for the execution */
1742 event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_COMMAND);
1743 gda_connection_event_set_description (event, _GDA_PSTMT (ps)->sql);
1744 gda_connection_add_event (cnc, event);
1745
1746 /* execute prepared statement using C API depending on its kind */
1747 if (! g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "SELECT", 6) ||
1748 ! g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "EXPLAIN", 7)) {
1749 GObject *data_model;
1750 GdaDataModelAccessFlags flags;
1751
1752 if (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS)
1753 flags = GDA_DATA_MODEL_ACCESS_RANDOM;
1754 else
1755 flags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD;
1756
1757 g_print("get the data model\n");
1758
1759 data_model = (GObject *) gda_firebird_recordset_new (cnc, ps, params, flags, col_types);
1760
1761 g_print("assign the data model\n");
1762 gda_connection_internal_statement_executed (cnc, stmt, params, NULL); /* required: help @cnc keep some stats */
1763
1764
1765 if (mem_to_free){
1766 g_print("free the memory for the input variables\n");
1767 g_slist_foreach (mem_to_free, (GFunc) g_free, NULL);
1768 g_slist_free (mem_to_free);
1769 }
1770 g_object_unref(ps);
1771 return data_model;
1772 }
1773 else {
1774 GdaSet *set = NULL;
1775 //TODO: What the hell must I do here?
1776 //TO_IMPLEMENT;
1777 g_print("SQL: %s\n\n", _GDA_PSTMT (ps)->sql);
1778 if (isc_dsql_execute(cdata->status, cdata->ftr, &(ps->stmt_h), SQL_DIALECT_V6, NULL)) {
1779 isc_print_status(cdata->status);
1780 g_print("\n");
1781 }
1782 /*
1783 gchar count_item[] = { isc_info_sql_records };
1784 char res_buffer[64];
1785 gint affected = 0;
1786 gint length = 0;
1787
1788 isc_dsql_sql_info (cdata->status
1789 , &(ps->stmt_h)
1790 , sizeof (count_item)
1791 , count_item
1792 , sizeof (res_buffer)
1793 , res_buffer);
1794 if (res_buffer[0] == isc_info_sql_records){
1795 unsigned i = 3, result_size = isc_vax_integer(&res_buffer[1],2);
1796
1797 while (res_buffer[i] != isc_info_end && i < result_size) {
1798 short len = (short)isc_vax_integer(&res_buffer[i+1],2);
1799 if (res_buffer[i] != isc_info_req_select_count) {
1800 affected += isc_vax_integer(&res_buffer[i+3],len);
1801 }
1802 i += len+3;
1803 }
1804 }
1805 */
1806
1807 /* Create a #GdaSet containing "IMPACTED_ROWS" */
1808 /* Create GdaConnectionEvent notice with the type of command and impacted rows */
1809
1810 if (mem_to_free){
1811 g_slist_foreach (mem_to_free, (GFunc) g_free, NULL);
1812 g_slist_free (mem_to_free);
1813 }
1814
1815 gda_connection_internal_statement_executed (cnc, stmt, params, event); /* required: help @cnc keep some stats */
1816 return (GObject*) set;
1817 }
1818 }
1819
1820 /*
1821 * starts a distributed transaction: put the XA transaction in the ACTIVE state
1822 */
1823 static gboolean
gda_firebird_provider_xa_start(GdaServerProvider * provider,GdaConnection * cnc,const GdaXaTransactionId * xid,GError ** error)1824 gda_firebird_provider_xa_start (GdaServerProvider *provider, GdaConnection *cnc,
1825 const GdaXaTransactionId *xid, GError **error)
1826 {
1827 FirebirdConnectionData *cdata;
1828
1829 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1830 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1831 g_return_val_if_fail (xid, FALSE);
1832
1833 cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1834 if (!cdata)
1835 return FALSE;
1836
1837 TO_IMPLEMENT;
1838 return FALSE;
1839 }
1840
1841 /*
1842 * put the XA transaction in the IDLE state: the connection won't accept any more modifications.
1843 * This state is required by some database providers before actually going to the PREPARED state
1844 */
1845 static gboolean
gda_firebird_provider_xa_end(GdaServerProvider * provider,GdaConnection * cnc,const GdaXaTransactionId * xid,GError ** error)1846 gda_firebird_provider_xa_end (GdaServerProvider *provider, GdaConnection *cnc,
1847 const GdaXaTransactionId *xid, GError **error)
1848 {
1849 FirebirdConnectionData *cdata;
1850
1851 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1852 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1853 g_return_val_if_fail (xid, FALSE);
1854
1855 cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1856 if (!cdata)
1857 return FALSE;
1858
1859 TO_IMPLEMENT;
1860 return FALSE;
1861 }
1862
1863 /*
1864 * prepares the distributed transaction: put the XA transaction in the PREPARED state
1865 */
1866 static gboolean
gda_firebird_provider_xa_prepare(GdaServerProvider * provider,GdaConnection * cnc,const GdaXaTransactionId * xid,GError ** error)1867 gda_firebird_provider_xa_prepare (GdaServerProvider *provider, GdaConnection *cnc,
1868 const GdaXaTransactionId *xid, GError **error)
1869 {
1870 FirebirdConnectionData *cdata;
1871
1872 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1873 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1874 g_return_val_if_fail (xid, FALSE);
1875
1876 cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1877 if (!cdata)
1878 return FALSE;
1879
1880 TO_IMPLEMENT;
1881 return FALSE;
1882 }
1883
1884 /*
1885 * commits the distributed transaction: actually write the prepared data to the database and
1886 * terminates the XA transaction
1887 */
1888 static gboolean
gda_firebird_provider_xa_commit(GdaServerProvider * provider,GdaConnection * cnc,const GdaXaTransactionId * xid,GError ** error)1889 gda_firebird_provider_xa_commit (GdaServerProvider *provider, GdaConnection *cnc,
1890 const GdaXaTransactionId *xid, GError **error)
1891 {
1892 FirebirdConnectionData *cdata;
1893
1894 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1895 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1896 g_return_val_if_fail (xid, FALSE);
1897
1898 cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1899 if (!cdata)
1900 return FALSE;
1901
1902 TO_IMPLEMENT;
1903 return FALSE;
1904 }
1905
1906 /*
1907 * Rolls back an XA transaction, possible only if in the ACTIVE, IDLE or PREPARED state
1908 */
1909 static gboolean
gda_firebird_provider_xa_rollback(GdaServerProvider * provider,GdaConnection * cnc,const GdaXaTransactionId * xid,GError ** error)1910 gda_firebird_provider_xa_rollback (GdaServerProvider *provider, GdaConnection *cnc,
1911 const GdaXaTransactionId *xid, GError **error)
1912 {
1913 FirebirdConnectionData *cdata;
1914
1915 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1916 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1917 g_return_val_if_fail (xid, FALSE);
1918
1919 cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1920 if (!cdata)
1921 return FALSE;
1922
1923 TO_IMPLEMENT;
1924 return FALSE;
1925 }
1926
1927 /*
1928 * Lists all XA transactions that are in the PREPARED state
1929 *
1930 * Returns: a list of GdaXaTransactionId structures, which will be freed by the caller
1931 */
1932 static GList *
gda_firebird_provider_xa_recover(GdaServerProvider * provider,GdaConnection * cnc,GError ** error)1933 gda_firebird_provider_xa_recover (GdaServerProvider *provider, GdaConnection *cnc,
1934 GError **error)
1935 {
1936 FirebirdConnectionData *cdata;
1937
1938 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
1939 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
1940
1941 cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1942 if (!cdata)
1943 return NULL;
1944
1945 TO_IMPLEMENT;
1946 return NULL;
1947 }
1948
1949 /*
1950 * Free connection's specific data
1951 */
1952 static void
gda_firebird_free_cnc_data(FirebirdConnectionData * cdata)1953 gda_firebird_free_cnc_data (FirebirdConnectionData *cdata)
1954 {
1955 if (!cdata)
1956 return;
1957
1958 if (cdata->handle)
1959 isc_detach_database (cdata->status, &(cdata->handle));
1960 g_free (cdata->dpb);
1961 g_free (cdata->dbname);
1962 g_free (cdata->server_version);
1963
1964 g_free (cdata);
1965 }
1966
1967 /*
1968 * fb_server_get_version
1969 *
1970 * Gets Firebird connection's server version number
1971 *
1972 * Returns: A string containing server version, or NULL if error
1973 * String must be released after use
1974 */
1975 static gchar *
fb_server_get_version(FirebirdConnectionData * fcnc)1976 fb_server_get_version (FirebirdConnectionData *fcnc)
1977 {
1978 gchar buffer[254], item, *p_buffer;
1979 gint length;
1980 gchar fdb_info[] = {
1981 isc_info_isc_version,
1982 isc_info_end
1983 };
1984
1985 /* Try to get database version */
1986 if (! isc_database_info (fcnc->status, &(fcnc->handle), sizeof (fdb_info), fdb_info,
1987 sizeof (buffer), buffer)) {
1988 p_buffer = buffer;
1989 if (*p_buffer != isc_info_end) {
1990 item = *p_buffer++;
1991 length = isc_vax_integer (p_buffer, 2);
1992 p_buffer += 2;
1993 if (item == isc_info_isc_version)
1994 return g_strndup ((const gchar *) &p_buffer[2], length-2);
1995 }
1996 }
1997
1998 return NULL;
1999 }
2000