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 (&registering);
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 (&registering);
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, &params, 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