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