1 /*
2  * Copyright (C) 2001 - 2004 Rodrigo Moya <rodrigo@gnome-db.org>
3  * Copyright (C) 2002 - 2003 Gonzalo Paniagua Javier <gonzalo@ximian.com>
4  * Copyright (C) 2002 Holger Thon <holger.thon@gnome-db.org>
5  * Copyright (C) 2002 Zbigniew Chyla <cyba@gnome.pl>
6  * Copyright (C) 2002 Cleber Rodrigues <cleber@gnome-db.org>
7  * Copyright (C) 2003 Akira TAGOH <tagoh@gnome-db.org>
8  * Copyright (C) 2003 Paisa Seeluangsawat <paisa@users.sf.net>
9  * Copyright (C) 2004 - 2005 Alan Knowles <alan@akbkhome.com>
10  * Copyright (C) 2004 Caolan McNamara <caolanm@redhat.com>
11  * Copyright (C) 2004 Julio M. Merino Vidal <jmmv@menta.net>
12  * Copyright (C) 2004 Jürg Billeter <j@bitron.ch>
13  * Copyright (C) 2004 Szalai Ferenc <szferi@einstein.ki.iif.hu>
14  * Copyright (C) 2005 - 2009 Bas Driessen <bas.driessen@xobas.com>
15  * Copyright (C) 2005 - 2013 Vivien Malerba <malerba@gnome-db.org>
16  * Copyright (C) 2005 Álvaro Peña <alvaropg@telefonica.net>
17  * Copyright (C) 2007 Armin Burgmeier <armin@openismus.com>
18  * Copyright (C) 2007 - 2011 Murray Cumming <murrayc@murrayc.com>
19  *
20  * This library is free software; you can redistribute it and/or
21  * modify it under the terms of the GNU Lesser General Public
22  * License as published by the Free Software Foundation; either
23  * version 2 of the License, or (at your option) any later version.
24  *
25  * This library is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
28  * Lesser General Public License for more details.
29  *
30  * You should have received a copy of the GNU Lesser General Public
31  * License along with this library; if not, write to the
32  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
33  * Boston, MA  02110-1301, USA.
34  */
35 
36 #undef GDA_DISABLE_DEPRECATED
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <errno.h>
40 #include <string.h>
41 #include <glib/gi18n-lib.h>
42 #include <glib/gstdio.h>
43 #include <libgda/libgda.h>
44 #include <libgda/gda-data-model-private.h>
45 #include <libgda/gda-server-provider-extra.h>
46 #include <libgda/binreloc/gda-binreloc.h>
47 #include <libgda/gda-statement-extra.h>
48 #include <sql-parser/gda-sql-parser.h>
49 #include <libgda/gda-blob-op.h>
50 #include "gda-mysql.h"
51 #include "gda-mysql-provider.h"
52 #include "gda-mysql-recordset.h"
53 #include "gda-mysql-ddl.h"
54 #include "gda-mysql-meta.h"
55 
56 #include "gda-mysql-util.h"
57 #include "gda-mysql-parser.h"
58 #include "gda-mysql-handler-boolean.h"
59 #include "gda-mysql-handler-bin.h"
60 #include <libgda/gda-debug-macros.h>
61 
62 #define _GDA_PSTMT(x) ((GdaPStmt*)(x))
63 
64 #ifdef MYSQL8
65 typedef bool my_bool;
66 #endif
67 /*
68  * GObject methods
69  */
70 static void gda_mysql_provider_class_init (GdaMysqlProviderClass  *klass);
71 static void gda_mysql_provider_init       (GdaMysqlProvider       *provider,
72 					   GdaMysqlProviderClass  *klass);
73 static void gda_mysql_provider_set_property (GObject *object,
74 					     guint param_id,
75 					     const GValue *value,
76 					     GParamSpec *pspec);
77 static void gda_mysql_provider_get_property (GObject *object,
78 					     guint param_id,
79 					     GValue *value,
80 					     GParamSpec *pspec);
81 static GObjectClass *parent_class = NULL;
82 
83 /* properties */
84 enum
85 {
86         PROP_0,
87         PROP_IDENT_CASE_SENSITIVE, /* used for tests */
88 };
89 
90 /*
91  * GdaServerProvider's virtual methods
92  */
93 /* connection management */
94 static gboolean            gda_mysql_provider_open_connection (GdaServerProvider               *provider,
95 							       GdaConnection                   *cnc,
96 							       GdaQuarkList                    *params,
97 							       GdaQuarkList                    *auth,
98 							       guint                           *task_id,
99 							       GdaServerProviderAsyncCallback   async_cb,
100 							       gpointer                         cb_data);
101 static gboolean            gda_mysql_provider_close_connection (GdaServerProvider  *provider,
102 								GdaConnection      *cnc);
103 static const gchar        *gda_mysql_provider_get_server_version (GdaServerProvider  *provider,
104 								  GdaConnection      *cnc);
105 static const gchar        *gda_mysql_provider_get_database (GdaServerProvider  *provider,
106 							    GdaConnection      *cnc);
107 
108 /* DDL operations */
109 static gboolean            gda_mysql_provider_supports_operation (GdaServerProvider       *provider,
110 								  GdaConnection           *cnc,
111 								  GdaServerOperationType   type,
112 								  GdaSet                  *options);
113 static GdaServerOperation *gda_mysql_provider_create_operation (GdaServerProvider       *provider,
114 								GdaConnection           *cnc,
115 								GdaServerOperationType   type,
116 								G_GNUC_UNUSED GdaSet                  *options,
117 								GError                **error);
118 static gchar              *gda_mysql_provider_render_operation (GdaServerProvider   *provider,
119 								GdaConnection       *cnc,
120 								GdaServerOperation  *op,
121 								GError             **error);
122 
123 static gboolean            gda_mysql_provider_perform_operation (GdaServerProvider               *provider,
124 								 GdaConnection                   *cnc,
125 								 GdaServerOperation              *op,
126 								 guint                           *task_id,
127 								 GdaServerProviderAsyncCallback   async_cb,
128 								 gpointer                         cb_data,
129 								 GError                         **error);
130 /* transactions */
131 static gboolean            gda_mysql_provider_begin_transaction (GdaServerProvider        *provider,
132 								 GdaConnection            *cnc,
133 								 const gchar              *name,
134 								 GdaTransactionIsolation   level,
135 								 GError                  **error);
136 static gboolean            gda_mysql_provider_commit_transaction (GdaServerProvider  *provider,
137 								  GdaConnection *cnc,
138 								  const gchar *name, GError **error);
139 static gboolean            gda_mysql_provider_rollback_transaction (GdaServerProvider *provider,
140 								    GdaConnection     *cnc,
141 								    const gchar       *name,
142 								    GError           **error);
143 static gboolean            gda_mysql_provider_add_savepoint (GdaServerProvider  *provider,
144 							     GdaConnection      *cnc,
145 							     const gchar        *name,
146 							     GError            **error);
147 static gboolean            gda_mysql_provider_rollback_savepoint (GdaServerProvider  *provider,
148 								  GdaConnection      *cnc,
149 								  const gchar        *name,
150 								  GError            **error);
151 static gboolean            gda_mysql_provider_delete_savepoint (GdaServerProvider  *provider,
152 								GdaConnection      *cnc,
153 								const gchar        *name,
154 								GError            **error);
155 
156 /* information retrieval */
157 static const gchar        *gda_mysql_provider_get_version (GdaServerProvider  *provider);
158 static gboolean            gda_mysql_provider_supports_feature (GdaServerProvider     *provider,
159 								GdaConnection         *cnc,
160 								GdaConnectionFeature   feature);
161 
162 static const gchar        *gda_mysql_provider_get_name (GdaServerProvider  *provider);
163 
164 static GdaDataHandler     *gda_mysql_provider_get_data_handler (GdaServerProvider  *provider,
165 								GdaConnection      *cnc,
166 								GType               g_type,
167 								const gchar        *dbms_type);
168 
169 static const gchar*        gda_mysql_provider_get_default_dbms_type (GdaServerProvider  *provider,
170 								     GdaConnection      *cnc,
171 								     GType               type);
172 /* statements */
173 static GdaSqlParser        *gda_mysql_provider_create_parser (GdaServerProvider  *provider,
174 							      GdaConnection      *cnc);
175 static gchar               *gda_mysql_provider_statement_to_sql  (GdaServerProvider    *provider,
176 								  GdaConnection        *cnc,
177 								  GdaStatement         *stmt,
178 								  GdaSet               *params,
179 								  GdaStatementSqlFlag   flags,
180 								  GSList              **params_used,
181 								  GError              **error);
182 static gboolean             gda_mysql_provider_statement_prepare (GdaServerProvider  *provider,
183 								  GdaConnection      *cnc,
184 								  GdaStatement       *stmt,
185 								  GError            **error);
186 static GObject             *gda_mysql_provider_statement_execute (GdaServerProvider               *provider,
187 								  GdaConnection                   *cnc,
188 								  GdaStatement                    *stmt,
189 								  GdaSet                          *params,
190 								  GdaStatementModelUsage           model_usage,
191 								  GType                           *col_types,
192 								  GdaSet                         **last_inserted_row,
193 								  guint                           *task_id,
194 								  GdaServerProviderExecCallback    async_cb,
195 								  gpointer                         cb_data,
196 								  GError                         **error);
197 static GdaSqlStatement     *gda_mysql_statement_rewrite          (GdaServerProvider *provider, GdaConnection *cnc,
198 								  GdaStatement *stmt, GdaSet *params, GError **error);
199 
200 
201 /* Quoting */
202 static gchar               *gda_mysql_identifier_quote    (GdaServerProvider *provider, GdaConnection *cnc,
203 							   const gchar *id,
204 							   gboolean meta_store_convention, gboolean force_quotes);
205 
206 /* distributed transactions */
207 static gboolean gda_mysql_provider_xa_start    (GdaServerProvider         *provider,
208 						GdaConnection             *cnc,
209 						const GdaXaTransactionId  *xid,
210 						GError                   **error);
211 
212 static gboolean gda_mysql_provider_xa_end      (GdaServerProvider         *provider,
213 						GdaConnection             *cnc,
214 						const GdaXaTransactionId  *xid,
215 						GError                   **error);
216 static gboolean gda_mysql_provider_xa_prepare  (GdaServerProvider         *provider,
217 						GdaConnection             *cnc,
218 						const GdaXaTransactionId  *xid,
219 						GError                   **error);
220 
221 static gboolean gda_mysql_provider_xa_commit   (GdaServerProvider        *provider,
222 						GdaConnection            *cnc,
223 						const GdaXaTransactionId  *xid,
224 						GError                   **error);
225 static gboolean gda_mysql_provider_xa_rollback (GdaServerProvider         *provider,
226 						GdaConnection             *cnc,
227 						const GdaXaTransactionId  *xid,
228 						GError                   **error);
229 
230 static GList   *gda_mysql_provider_xa_recover  (GdaServerProvider  *provider,
231 						GdaConnection      *cnc,
232 						GError            **error);
233 
234 
235 /*
236  * private connection data destroy
237  */
238 static void gda_mysql_free_cnc_data (MysqlConnectionData  *cdata);
239 
240 
241 /*
242  * Prepared internal statements
243  * TO_ADD: any prepared statement to be used internally by the provider should be
244  *         declared here, as constants and as SQL statements
245  */
246 static GMutex init_mutex;
247 static GdaStatement **internal_stmt = NULL;
248 
249 typedef enum {
250 	INTERNAL_STMT1
251 } InternalStatementItem;
252 
253 gchar *internal_sql[] = {
254 	"SQL for INTERNAL_STMT1"
255 };
256 
257 /*
258  * GdaMysqlProvider class implementation
259  */
260 static void
gda_mysql_provider_class_init(GdaMysqlProviderClass * klass)261 gda_mysql_provider_class_init (GdaMysqlProviderClass  *klass)
262 {
263 	GdaServerProviderClass *provider_class = GDA_SERVER_PROVIDER_CLASS (klass);
264 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
265 
266 	parent_class = g_type_class_peek_parent (klass);
267 
268 	/* Properties */
269         object_class->set_property = gda_mysql_provider_set_property;
270         object_class->get_property = gda_mysql_provider_get_property;
271 
272 	g_object_class_install_property (object_class, PROP_IDENT_CASE_SENSITIVE,
273                                          g_param_spec_boolean ("identifiers-case-sensitive", NULL, NULL, TRUE,
274 							       G_PARAM_READABLE | G_PARAM_WRITABLE));
275 
276 
277 	/* virtual methods */
278 	provider_class->get_version = gda_mysql_provider_get_version;
279 	provider_class->get_server_version = gda_mysql_provider_get_server_version;
280 	provider_class->get_name = gda_mysql_provider_get_name;
281 	provider_class->supports_feature = gda_mysql_provider_supports_feature;
282 
283 	provider_class->get_data_handler = gda_mysql_provider_get_data_handler;
284 	provider_class->get_def_dbms_type = gda_mysql_provider_get_default_dbms_type;
285 
286 	provider_class->open_connection = gda_mysql_provider_open_connection;
287 	provider_class->close_connection = gda_mysql_provider_close_connection;
288 	provider_class->get_database = gda_mysql_provider_get_database;
289 
290 	provider_class->supports_operation = gda_mysql_provider_supports_operation;
291         provider_class->create_operation = gda_mysql_provider_create_operation;
292         provider_class->render_operation = gda_mysql_provider_render_operation;
293         provider_class->perform_operation = gda_mysql_provider_perform_operation;
294 
295 	provider_class->begin_transaction = gda_mysql_provider_begin_transaction;
296 	provider_class->commit_transaction = gda_mysql_provider_commit_transaction;
297 	provider_class->rollback_transaction = gda_mysql_provider_rollback_transaction;
298 	provider_class->add_savepoint = gda_mysql_provider_add_savepoint;
299         provider_class->rollback_savepoint = gda_mysql_provider_rollback_savepoint;
300         provider_class->delete_savepoint = gda_mysql_provider_delete_savepoint;
301 
302 	provider_class->create_parser = gda_mysql_provider_create_parser;
303 	provider_class->statement_to_sql = gda_mysql_provider_statement_to_sql;
304 	provider_class->statement_prepare = gda_mysql_provider_statement_prepare;
305 	provider_class->statement_execute = gda_mysql_provider_statement_execute;
306 	provider_class->statement_rewrite = gda_mysql_statement_rewrite;
307 
308 	provider_class->is_busy = NULL;
309 	provider_class->cancel = NULL;
310 	provider_class->create_connection = NULL;
311 
312 	provider_class->identifier_quote = gda_mysql_identifier_quote;
313 
314 	memset (&(provider_class->meta_funcs), 0, sizeof (GdaServerProviderMeta));
315 	provider_class->meta_funcs._info = _gda_mysql_meta__info;
316         provider_class->meta_funcs._btypes = _gda_mysql_meta__btypes;
317         provider_class->meta_funcs._udt = _gda_mysql_meta__udt;
318         provider_class->meta_funcs.udt = _gda_mysql_meta_udt;
319         provider_class->meta_funcs._udt_cols = _gda_mysql_meta__udt_cols;
320         provider_class->meta_funcs.udt_cols = _gda_mysql_meta_udt_cols;
321         provider_class->meta_funcs._enums = _gda_mysql_meta__enums;
322         provider_class->meta_funcs.enums = _gda_mysql_meta_enums;
323         provider_class->meta_funcs._domains = _gda_mysql_meta__domains;
324         provider_class->meta_funcs.domains = _gda_mysql_meta_domains;
325         provider_class->meta_funcs._constraints_dom = _gda_mysql_meta__constraints_dom;
326         provider_class->meta_funcs.constraints_dom = _gda_mysql_meta_constraints_dom;
327         provider_class->meta_funcs._el_types = _gda_mysql_meta__el_types;
328         provider_class->meta_funcs._collations = _gda_mysql_meta__collations;
329         provider_class->meta_funcs.collations = _gda_mysql_meta_collations;
330         provider_class->meta_funcs._character_sets = _gda_mysql_meta__character_sets;
331         provider_class->meta_funcs.character_sets = _gda_mysql_meta_character_sets;
332         provider_class->meta_funcs._schemata = _gda_mysql_meta__schemata;
333         provider_class->meta_funcs.schemata = _gda_mysql_meta_schemata;
334         provider_class->meta_funcs._tables_views = _gda_mysql_meta__tables_views;
335         provider_class->meta_funcs.tables_views = _gda_mysql_meta_tables_views;
336         provider_class->meta_funcs._columns = _gda_mysql_meta__columns;
337         provider_class->meta_funcs.columns = _gda_mysql_meta_columns;
338         provider_class->meta_funcs._view_cols = _gda_mysql_meta__view_cols;
339         provider_class->meta_funcs.view_cols = _gda_mysql_meta_view_cols;
340         provider_class->meta_funcs._constraints_tab = _gda_mysql_meta__constraints_tab;
341         provider_class->meta_funcs.constraints_tab = _gda_mysql_meta_constraints_tab;
342         provider_class->meta_funcs._constraints_ref = _gda_mysql_meta__constraints_ref;
343         provider_class->meta_funcs.constraints_ref = _gda_mysql_meta_constraints_ref;
344         provider_class->meta_funcs._key_columns = _gda_mysql_meta__key_columns;
345         provider_class->meta_funcs.key_columns = _gda_mysql_meta_key_columns;
346         provider_class->meta_funcs._check_columns = _gda_mysql_meta__check_columns;
347         provider_class->meta_funcs.check_columns = _gda_mysql_meta_check_columns;
348         provider_class->meta_funcs._triggers = _gda_mysql_meta__triggers;
349         provider_class->meta_funcs.triggers = _gda_mysql_meta_triggers;
350         provider_class->meta_funcs._routines = _gda_mysql_meta__routines;
351         provider_class->meta_funcs.routines = _gda_mysql_meta_routines;
352         provider_class->meta_funcs._routine_col = _gda_mysql_meta__routine_col;
353         provider_class->meta_funcs.routine_col = _gda_mysql_meta_routine_col;
354         provider_class->meta_funcs._routine_par = _gda_mysql_meta__routine_par;
355         provider_class->meta_funcs.routine_par = _gda_mysql_meta_routine_par;
356 	provider_class->meta_funcs._indexes_tab = _gda_mysql_meta__indexes_tab;
357         provider_class->meta_funcs.indexes_tab = _gda_mysql_meta_indexes_tab;
358         provider_class->meta_funcs._index_cols = _gda_mysql_meta__index_cols;
359         provider_class->meta_funcs.index_cols = _gda_mysql_meta_index_cols;
360 
361 	/* distributed transactions: if not supported, then provider_class->xa_funcs should be set to NULL */
362 	provider_class->xa_funcs = g_new0 (GdaServerProviderXa, 1);
363 	provider_class->xa_funcs->xa_start = gda_mysql_provider_xa_start;
364 	provider_class->xa_funcs->xa_end = gda_mysql_provider_xa_end;
365 	provider_class->xa_funcs->xa_prepare = gda_mysql_provider_xa_prepare;
366 	provider_class->xa_funcs->xa_commit = gda_mysql_provider_xa_commit;
367 	provider_class->xa_funcs->xa_rollback = gda_mysql_provider_xa_rollback;
368 	provider_class->xa_funcs->xa_recover = gda_mysql_provider_xa_recover;
369 
370 	if (!mysql_thread_safe ()) {
371 		gda_log_message ("MySQL was not compiled with the --enable-thread-safe-client flag, "
372 				 "only one thread can access the provider");
373 		provider_class->limiting_thread = GDA_SERVER_PROVIDER_UNDEFINED_LIMITING_THREAD;
374 	}
375 	else
376 		provider_class->limiting_thread = NULL;
377 
378 }
379 
380 static void
gda_mysql_provider_init(GdaMysqlProvider * mysql_prv,G_GNUC_UNUSED GdaMysqlProviderClass * klass)381 gda_mysql_provider_init (GdaMysqlProvider       *mysql_prv,
382 			 G_GNUC_UNUSED GdaMysqlProviderClass  *klass)
383 {
384 	g_mutex_lock (&init_mutex);
385 
386 	if (!internal_stmt) {
387 		InternalStatementItem i;
388 		GdaSqlParser *parser;
389 
390 		parser = gda_server_provider_internal_get_parser ((GdaServerProvider*) mysql_prv);
391 		internal_stmt = g_new0 (GdaStatement *, sizeof (internal_sql) / sizeof (gchar*));
392 		for (i = INTERNAL_STMT1; i < sizeof (internal_sql) / sizeof (gchar*); i++) {
393 			internal_stmt[i] = gda_sql_parser_parse_string (parser, internal_sql[i], NULL, NULL);
394 			if (!internal_stmt[i])
395 				g_error ("Could not parse internal statement: %s\n", internal_sql[i]);
396 		}
397 	}
398 
399 	/* meta data init */
400 	_gda_mysql_provider_meta_init ((GdaServerProvider*) mysql_prv);
401 
402 	/* for tests */
403 	mysql_prv->test_mode = FALSE;
404 	mysql_prv->test_identifiers_case_sensitive = TRUE;
405 
406 	g_mutex_unlock (&init_mutex);
407 }
408 
409 GType
gda_mysql_provider_get_type(void)410 gda_mysql_provider_get_type (void)
411 {
412 	static GType type = 0;
413 
414 	if (G_UNLIKELY (type == 0)) {
415 		static GMutex registering;
416 		static GTypeInfo info = {
417 			sizeof (GdaMysqlProviderClass),
418 			(GBaseInitFunc) NULL,
419 			(GBaseFinalizeFunc) NULL,
420 			(GClassInitFunc) gda_mysql_provider_class_init,
421 			NULL, NULL,
422 			sizeof (GdaMysqlProvider),
423 			0,
424 			(GInstanceInitFunc) gda_mysql_provider_init,
425 			NULL
426 		};
427 		g_mutex_lock (&registering);
428 		if (type == 0)
429 			type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, "GdaMysqlProvider", &info, 0);
430 		g_mutex_unlock (&registering);
431 	}
432 
433 	return type;
434 }
435 
436 static void
gda_mysql_provider_set_property(GObject * object,guint param_id,const GValue * value,G_GNUC_UNUSED GParamSpec * pspec)437 gda_mysql_provider_set_property (GObject *object,
438 				 guint param_id,
439 				 const GValue *value,
440 				 G_GNUC_UNUSED GParamSpec *pspec)
441 {
442 	GdaMysqlProvider *mysql_prv;
443 	mysql_prv = GDA_MYSQL_PROVIDER (object);
444 	switch (param_id) {
445 	case PROP_IDENT_CASE_SENSITIVE:
446 		mysql_prv->test_identifiers_case_sensitive = g_value_get_boolean (value);
447 		mysql_prv->test_mode = TRUE;
448 		break;
449 	}
450 }
451 
452 static void
gda_mysql_provider_get_property(GObject * object,guint param_id,GValue * value,G_GNUC_UNUSED GParamSpec * pspec)453 gda_mysql_provider_get_property (GObject *object,
454 				 guint param_id,
455 				 GValue *value,
456 				 G_GNUC_UNUSED GParamSpec *pspec)
457 {
458 	GdaMysqlProvider *mysql_prv;
459 	mysql_prv = GDA_MYSQL_PROVIDER (object);
460 	switch (param_id) {
461 	case PROP_IDENT_CASE_SENSITIVE:
462 		g_value_set_boolean (value, mysql_prv->test_identifiers_case_sensitive);
463 		break;
464 	}
465 }
466 
467 /*
468  * Get provider name request
469  */
470 static const gchar *
gda_mysql_provider_get_name(G_GNUC_UNUSED GdaServerProvider * provider)471 gda_mysql_provider_get_name (G_GNUC_UNUSED GdaServerProvider *provider)
472 {
473 	return MYSQL_PROVIDER_NAME;
474 }
475 
476 /*
477  * Get provider's version, no need to change this
478  */
479 static const gchar *
gda_mysql_provider_get_version(G_GNUC_UNUSED GdaServerProvider * provider)480 gda_mysql_provider_get_version (G_GNUC_UNUSED GdaServerProvider  *provider)
481 {
482 	return PACKAGE_VERSION;
483 }
484 
485 
486 /*
487  * Open a MYSQL connection.
488  * If @port <= 0 then @port is not used.
489  */
490 static MYSQL *
real_open_connection(const gchar * host,gint port,const gchar * socket,const gchar * db,const gchar * username,const gchar * password,gboolean use_ssl,gboolean compress,const gchar * proto,GError ** error)491 real_open_connection (const gchar  *host,
492 		      gint          port,
493 		      const gchar  *socket,
494 		      const gchar  *db,
495 		      const gchar  *username,
496 		      const gchar  *password,
497 		      gboolean      use_ssl,
498 		      gboolean      compress,
499 		      const gchar  *proto,
500 		      GError      **error)
501 {
502 	unsigned int flags = CLIENT_FOUND_ROWS;
503 
504 	/* Exclusive: host/pair otherwise unix socket. */
505 	if ((host || port > 0) && socket) {
506 		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_MISUSE_ERROR,
507 			     "%s",
508 			     _("Cannot give a UNIX SOCKET if you also provide "
509 			       "either a HOST or a PORT"));
510 		return NULL;
511 	}
512 
513 	if (port > 65535) {
514 		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_MISUSE_ERROR,
515 			     "%s",
516 			     _("Invalid port number"));
517 		return NULL;
518 	}
519 
520 	/* Defaults. */
521 	if (!socket) {
522 		if (!host)
523 			host = "localhost";
524 		else if (port <= 0)
525 			port = 3306;
526 	}
527 
528 	if (use_ssl)
529 		flags |= CLIENT_SSL;
530 	if (compress)
531 		flags |= CLIENT_COMPRESS;
532 
533 	MYSQL *mysql = NULL;
534 	mysql = mysql_init (NULL);
535 
536 	if ((port > 0) || proto) {
537 		gint p = MYSQL_PROTOCOL_DEFAULT;
538 		if (proto) {
539 			if (! g_ascii_strcasecmp (proto, "DEFAULT"))
540 				p = MYSQL_PROTOCOL_DEFAULT;
541 			else if (! g_ascii_strcasecmp (proto, "TCP"))
542 				p = MYSQL_PROTOCOL_TCP;
543 			else if (! g_ascii_strcasecmp (proto, "SOCKET"))
544 				p = MYSQL_PROTOCOL_SOCKET;
545 			else if (! g_ascii_strcasecmp (proto, "PIPE"))
546 				p = MYSQL_PROTOCOL_PIPE;
547 			else if (! g_ascii_strcasecmp (proto, "MEMORY"))
548 				p = MYSQL_PROTOCOL_MEMORY;
549 			else {
550 				g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_OPEN_ERROR,
551 					     _("Unknown MySQL protocol '%s'"), proto);
552 				mysql_close (mysql);
553 				return NULL;
554 			}
555 		}
556 		else
557 			p = MYSQL_PROTOCOL_TCP;
558 
559 		if (mysql_options (mysql, MYSQL_OPT_PROTOCOL, (const char *) &p)) {
560 			g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_OPEN_ERROR,
561 				     "%s", mysql_error (mysql));
562 			mysql_close (mysql);
563 			return NULL;
564 		}
565 	}
566 
567 	MYSQL *return_mysql = mysql_real_connect (mysql, host,
568 						  username, password,
569 #if MYSQL_VERSION_ID >= 32200
570 						  db,
571 #endif
572 						  (port > 0) ? port : 0,
573 						  socket, flags);
574 	if (!return_mysql || mysql != return_mysql) {
575 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_OPEN_ERROR,
576 			     "%s", mysql_error (mysql));
577 		mysql_close (mysql);
578 		mysql = NULL;
579 	}
580 
581 	/* Optionnally set some attributes for the newly opened connection (encoding to UTF-8 for example )*/
582 
583 #if MYSQL_VERSION_ID < 32200
584 	if (mysql &&
585 	    mysql_select_db (mysql, db) != 0) {
586 		g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_OPEN_ERROR,
587 			     "%s", mysql_error (mysql));
588 		mysql_close (mysql);
589 		mysql = NULL;
590 	}
591 #endif
592 
593 #if MYSQL_VERSION_ID >= 50007
594 	if (mysql &&
595 	    mysql_set_character_set (mysql, "utf8")) {
596 		g_warning (_("Could not set client charset to UTF8. "
597 			     "Using %s. It'll be problems with non UTF-8 characters"),
598 			   mysql_character_set_name (mysql));
599 	}
600 #endif
601 
602 	return mysql;
603 }
604 
605 int
gda_mysql_real_query_wrap(GdaConnection * cnc,MYSQL * mysql,const char * stmt_str,unsigned long length)606 gda_mysql_real_query_wrap (GdaConnection *cnc, MYSQL *mysql, const char *stmt_str, unsigned long length)
607 {
608 	GdaConnectionEvent *event;
609 
610 	event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_COMMAND);
611 	gda_connection_event_set_description (event, stmt_str);
612 	gda_connection_add_event (cnc, event);
613 
614 	return mysql_real_query (mysql, stmt_str, length);
615 }
616 
617 /*
618  * Open connection request
619  *
620  * In this function, the following _must_ be done:
621  *   - check for the presence and validify of the parameters required to actually open a connection,
622  *     using @params
623  *   - open the real connection to the database using the parameters previously checked
624  *   - create a MysqlConnectionData structure and associate it to @cnc
625  *
626  * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR gonnection event must be added to @cnc)
627  */
628 static gboolean
gda_mysql_provider_open_connection(GdaServerProvider * provider,GdaConnection * cnc,GdaQuarkList * params,GdaQuarkList * auth,G_GNUC_UNUSED guint * task_id,GdaServerProviderAsyncCallback async_cb,gpointer cb_data)629 gda_mysql_provider_open_connection (GdaServerProvider               *provider,
630 				    GdaConnection                   *cnc,
631 				    GdaQuarkList                    *params,
632 				    GdaQuarkList                    *auth,
633 				    G_GNUC_UNUSED guint             *task_id,
634 				    GdaServerProviderAsyncCallback   async_cb,
635 				    gpointer                         cb_data)
636 {
637 	g_return_val_if_fail (GDA_IS_MYSQL_PROVIDER (provider), FALSE);
638 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
639 
640 	/* If asynchronous connection opening is not supported, then exit now */
641 	if (async_cb) {
642 		gda_connection_add_event_string (cnc, _("Provider does not support asynchronous connection open"));
643                 return FALSE;
644 	}
645 
646 	/* Check for connection parameters */
647 	/* TO_ADD: your own connection parameters */
648 	const gchar *db_name;
649 	db_name = gda_quark_list_find (params, "DB_NAME");
650 	if (!db_name) {
651 		gda_connection_add_event_string (cnc,
652 						 _("The connection string must contain the DB_NAME values"));
653 		return FALSE;
654 	}
655 
656 	const gchar *host;
657 	host = gda_quark_list_find (params, "HOST");
658 
659 	const gchar *user, *password;
660 	user = gda_quark_list_find (auth, "USERNAME");
661 	if (!user)
662 		user = gda_quark_list_find (params, "USERNAME");
663 	password = gda_quark_list_find (auth, "PASSWORD");
664 	if (!password)
665 		password = gda_quark_list_find (params, "PASSWORD");
666 
667 	const gchar *port, *unix_socket, *use_ssl, *compress, *proto;
668 	port = gda_quark_list_find (params, "PORT");
669 	unix_socket = gda_quark_list_find (params, "UNIX_SOCKET");
670 	use_ssl = gda_quark_list_find (params, "USE_SSL");
671 	compress = gda_quark_list_find (params, "COMPRESS");
672 	proto = gda_quark_list_find (params, "PROTOCOL");
673 
674 	/* open the real connection to the database */
675 	/* TO_ADD: C API specific function calls;
676 	 * if it fails, add a connection event and return FALSE */
677 	// TO_IMPLEMENT;
678 
679 	GError *error = NULL;
680 	MYSQL *mysql = real_open_connection (host, (port != NULL) ? atoi (port) : -1,
681 					     unix_socket, db_name,
682 					     user, password,
683 					     (use_ssl && ((*use_ssl == 't') || (*use_ssl == 'T'))) ? TRUE : FALSE,
684 					     (compress && ((*compress == 't') || (*compress == 'T'))) ? TRUE : FALSE,
685 					     proto,
686 					     &error);
687 	if (!mysql) {
688 		GdaConnectionEvent *event_error = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
689 		gda_connection_event_set_sqlstate (event_error, _("Unknown"));
690 		gda_connection_event_set_description (event_error,
691 						      error && error->message ? error->message :
692 						      _("No description"));
693 		gda_connection_event_set_code (event_error, GDA_CONNECTION_EVENT_CODE_UNKNOWN);
694 		gda_connection_event_set_source (event_error, "gda-mysql");
695 		gda_connection_add_event (cnc, event_error);
696 		g_clear_error (&error);
697 
698 		return FALSE;
699 	}
700 
701 	/* Set some attributes for the newly opened connection (encoding to UTF-8)*/
702 	int res;
703 	res = mysql_query (mysql, "SET NAMES 'utf8'");
704 	if (res != 0) {
705 		_gda_mysql_make_error (cnc, mysql, NULL, NULL);
706 		mysql_close (mysql);
707 		return FALSE;
708 	}
709 
710 	/* Create a new instance of the provider specific data associated to a connection (MysqlConnectionData),
711 	 * and set its contents */
712 	MysqlConnectionData *cdata;
713 	cdata = g_new0 (MysqlConnectionData, 1);
714 	gda_connection_internal_set_provider_data (cnc, cdata, (GDestroyNotify) gda_mysql_free_cnc_data);
715 	cdata->cnc = cnc;
716 	cdata->mysql = mysql;
717 
718 	/* handle the reuseable part */
719 	GdaProviderReuseableOperations *ops;
720 	ops = _gda_mysql_reuseable_get_ops ();
721 	cdata->reuseable = (GdaMysqlReuseable*) ops->re_new_data ();
722 	if (! _gda_mysql_compute_version (cnc, cdata->reuseable, &error)) {
723 		GdaConnectionEvent *event_error = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
724 		gda_connection_event_set_sqlstate (event_error, _("Unknown"));
725 		gda_connection_event_set_description (event_error,
726 						      error && error->message ? error->message :
727 						      _("No description"));
728 		gda_connection_event_set_code (event_error, GDA_CONNECTION_EVENT_CODE_UNKNOWN);
729 		gda_connection_event_set_source (event_error, "gda-mysql");
730 		gda_connection_add_event (cnc, event_error);
731 		g_clear_error (&error);
732 
733 		gda_mysql_free_cnc_data (cdata);
734 		gda_connection_internal_set_provider_data (cnc, NULL, NULL);
735 		return FALSE;
736 	}
737 
738 	return TRUE;
739 }
740 
741 /*
742  * Close connection request
743  *
744  * In this function, the following _must_ be done:
745  *   - Actually close the connection to the database using @cnc's associated MysqlConnectionData structure
746  *   - Free the MysqlConnectionData structure and its contents
747  *
748  * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR gonnection event must be added to @cnc)
749  */
750 static gboolean
gda_mysql_provider_close_connection(GdaServerProvider * provider,GdaConnection * cnc)751 gda_mysql_provider_close_connection (GdaServerProvider  *provider,
752 				     GdaConnection      *cnc)
753 {
754 	MysqlConnectionData *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 	/* Close the connection using the C API */
760 	cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
761 	if (!cdata)
762 		return FALSE;
763 	// TO_IMPLEMENT;
764 
765 	/* Free the MysqlConnectionData structure and its contents*/
766 	gda_mysql_free_cnc_data (cdata);
767 	gda_connection_internal_set_provider_data (cnc, NULL, NULL);
768 
769 	return TRUE;
770 }
771 
772 /*
773  * Server version request
774  *
775  * Returns the server version as a string, which should be stored in @cnc's associated MysqlConnectionData structure
776  */
777 static const gchar *
gda_mysql_provider_get_server_version(GdaServerProvider * provider,GdaConnection * cnc)778 gda_mysql_provider_get_server_version (GdaServerProvider  *provider,
779 				       GdaConnection      *cnc)
780 {
781 	MysqlConnectionData *cdata;
782 
783 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
784 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
785 
786 	cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
787 	if (!cdata)
788 		return FALSE;
789 	if (! ((GdaProviderReuseable*)cdata->reuseable)->server_version)
790 		_gda_mysql_compute_version (cnc, cdata->reuseable, NULL);
791 	return ((GdaProviderReuseable*)cdata->reuseable)->server_version;
792 }
793 
794 /*
795  * Get database request
796  *
797  * Returns the server version as a string, which should be stored in @cnc's associated MysqlConnectionData structure
798  */
799 static const gchar *
gda_mysql_provider_get_database(GdaServerProvider * provider,GdaConnection * cnc)800 gda_mysql_provider_get_database (GdaServerProvider  *provider,
801 				 GdaConnection      *cnc)
802 {
803 	MysqlConnectionData *cdata;
804 
805 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
806 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
807 
808 	cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
809 	if (!cdata)
810 		return NULL;
811 	TO_IMPLEMENT;
812 	return NULL;
813 }
814 
815 /*
816  * Support operation request
817  *
818  * Tells what the implemented server operations are. To add support for an operation, the following steps are required:
819  *   - create a mysql_specs_....xml.in file describing the required and optional parameters for the operation
820  *   - add it to the Makefile.am
821  *   - make this method return TRUE for the operation type
822  *   - implement the gda_mysql_provider_render_operation() and gda_mysql_provider_perform_operation() methods
823  *
824  * In this example, the GDA_SERVER_OPERATION_CREATE_TABLE is implemented
825  */
826 static gboolean
gda_mysql_provider_supports_operation(GdaServerProvider * provider,GdaConnection * cnc,GdaServerOperationType type,G_GNUC_UNUSED GdaSet * options)827 gda_mysql_provider_supports_operation (GdaServerProvider       *provider,
828 				       GdaConnection           *cnc,
829 				       GdaServerOperationType   type,
830 				       G_GNUC_UNUSED GdaSet                  *options)
831 {
832 	if (cnc) {
833 		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
834 		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
835 	}
836 
837         switch (type) {
838         case GDA_SERVER_OPERATION_CREATE_DB:
839         case GDA_SERVER_OPERATION_DROP_DB:
840         case GDA_SERVER_OPERATION_CREATE_TABLE:
841         case GDA_SERVER_OPERATION_DROP_TABLE:
842         case GDA_SERVER_OPERATION_RENAME_TABLE:
843         case GDA_SERVER_OPERATION_COMMENT_TABLE:
844         case GDA_SERVER_OPERATION_ADD_COLUMN:
845 	case GDA_SERVER_OPERATION_DROP_COLUMN:
846 	case GDA_SERVER_OPERATION_COMMENT_COLUMN:
847         case GDA_SERVER_OPERATION_CREATE_INDEX:
848         case GDA_SERVER_OPERATION_DROP_INDEX:
849         case GDA_SERVER_OPERATION_CREATE_VIEW:
850         case GDA_SERVER_OPERATION_DROP_VIEW:
851 		return TRUE;
852         default:
853                 return FALSE;
854         }
855 }
856 
857 /*
858  * Create operation request
859  *
860  * Creates a #GdaServerOperation. The following code is generic and should only be changed
861  * if some further initialization is required, or if operation's contents is dependent on @cnc
862  */
863 static GdaServerOperation *
gda_mysql_provider_create_operation(GdaServerProvider * provider,GdaConnection * cnc,GdaServerOperationType type,G_GNUC_UNUSED GdaSet * options,GError ** error)864 gda_mysql_provider_create_operation (GdaServerProvider       *provider,
865 				     GdaConnection           *cnc,
866 				     GdaServerOperationType   type,
867 				     G_GNUC_UNUSED GdaSet                  *options,
868 				     GError                 **error)
869 {
870         gchar *file;
871         GdaServerOperation *op;
872         gchar *str;
873 	gchar *dir;
874 
875 	if (cnc) {
876 		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
877 		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
878 	}
879 
880         file = g_utf8_strdown (gda_server_operation_op_type_to_string (type), -1);
881         str = g_strdup_printf ("mysql_specs_%s.xml", file);
882         g_free (file);
883 
884 	dir = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, NULL);
885         file = gda_server_provider_find_file (provider, dir, str);
886 	g_free (dir);
887 
888         if (!file) {
889                 g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_FILE_NOT_FOUND_ERROR,
890 			     _("Missing spec. file '%s'"), str);
891 		g_free (str);
892                 return NULL;
893         }
894         g_free (str);
895 
896         op = gda_server_operation_new (type, file);
897         g_free (file);
898 
899         return op;
900 }
901 
902 /*
903  * Render operation request
904  */
905 static gchar *
gda_mysql_provider_render_operation(GdaServerProvider * provider,GdaConnection * cnc,GdaServerOperation * op,GError ** error)906 gda_mysql_provider_render_operation (GdaServerProvider   *provider,
907 				     GdaConnection       *cnc,
908 				     GdaServerOperation  *op,
909 				     GError             **error)
910 {
911         gchar *sql = NULL;
912         gchar *file;
913         gchar *str;
914 	gchar *dir;
915 
916 	if (cnc) {
917 		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
918 		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
919 	}
920 
921 	/* test @op's validity */
922         file = g_utf8_strdown (gda_server_operation_op_type_to_string (gda_server_operation_get_op_type (op)), -1);
923         str = g_strdup_printf ("mysql_specs_%s.xml", file);
924         g_free (file);
925 
926 	dir = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, NULL);
927         file = gda_server_provider_find_file (provider, dir, str);
928 	g_free (dir);
929 
930         if (!file) {
931                 g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_FILE_NOT_FOUND_ERROR,
932 			     _("Missing spec. file '%s'"), str);
933 		g_free (str);
934                 return NULL;
935         }
936         g_free (str);
937         if (!gda_server_operation_is_valid (op, file, error)) {
938                 g_free (file);
939                 return NULL;
940         }
941         g_free (file);
942 
943 	/* actual rendering */
944         switch (gda_server_operation_get_op_type (op)) {
945         case GDA_SERVER_OPERATION_CREATE_DB:
946 		sql = gda_mysql_render_CREATE_DB (provider, cnc, op, error);
947 		break;
948         case GDA_SERVER_OPERATION_DROP_DB:
949 		sql = gda_mysql_render_DROP_DB (provider, cnc, op, error);
950                 break;
951         case GDA_SERVER_OPERATION_CREATE_TABLE:
952                 sql = gda_mysql_render_CREATE_TABLE (provider, cnc, op, error);
953                 break;
954         case GDA_SERVER_OPERATION_DROP_TABLE:
955 		sql = gda_mysql_render_DROP_TABLE (provider, cnc, op, error);
956 		break;
957         case GDA_SERVER_OPERATION_RENAME_TABLE:
958 		sql = gda_mysql_render_RENAME_TABLE (provider, cnc, op, error);
959 		break;
960         case GDA_SERVER_OPERATION_COMMENT_TABLE:
961 		sql = gda_mysql_render_COMMENT_TABLE (provider, cnc, op, error);
962 		break;
963         case GDA_SERVER_OPERATION_ADD_COLUMN:
964 		sql = gda_mysql_render_ADD_COLUMN (provider, cnc, op, error);
965 		break;
966 	case GDA_SERVER_OPERATION_DROP_COLUMN:
967 		sql = gda_mysql_render_DROP_COLUMN (provider, cnc, op, error);
968 		break;
969 	case GDA_SERVER_OPERATION_COMMENT_COLUMN:
970 		sql = gda_mysql_render_COMMENT_COLUMN (provider, cnc, op, error);
971 		break;
972         case GDA_SERVER_OPERATION_CREATE_INDEX:
973 		sql = gda_mysql_render_CREATE_INDEX (provider, cnc, op, error);
974 		break;
975         case GDA_SERVER_OPERATION_DROP_INDEX:
976 		sql = gda_mysql_render_DROP_INDEX (provider, cnc, op, error);
977 		break;
978         case GDA_SERVER_OPERATION_CREATE_VIEW:
979 		sql = gda_mysql_render_CREATE_VIEW (provider, cnc, op, error);
980 		break;
981         case GDA_SERVER_OPERATION_DROP_VIEW:
982 		sql = gda_mysql_render_DROP_VIEW (provider, cnc, op, error);
983 		break;
984         default:
985                 g_assert_not_reached ();
986         }
987         return sql;
988 }
989 
990 /*
991  * Perform operation request
992  */
993 static gboolean
gda_mysql_provider_perform_operation(GdaServerProvider * provider,GdaConnection * cnc,GdaServerOperation * op,G_GNUC_UNUSED guint * task_id,GdaServerProviderAsyncCallback async_cb,gpointer cb_data,GError ** error)994 gda_mysql_provider_perform_operation (GdaServerProvider               *provider,
995 				      GdaConnection                   *cnc,
996 				      GdaServerOperation              *op,
997 				      G_GNUC_UNUSED guint                           *task_id,
998 				      GdaServerProviderAsyncCallback   async_cb,
999 				      gpointer                         cb_data,
1000 				      GError                         **error)
1001 {
1002         GdaServerOperationType optype;
1003 
1004 	/* If asynchronous connection opening is not supported, then exit now */
1005 	if (async_cb) {
1006 		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
1007 			     "%s", _("Provider does not support asynchronous server operation"));
1008                 return FALSE;
1009 	}
1010 
1011 	if (cnc) {
1012 		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1013 		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1014 	}
1015         optype = gda_server_operation_get_op_type (op);
1016 	if (!cnc &&
1017 	    ((optype == GDA_SERVER_OPERATION_CREATE_DB) ||
1018 	     (optype == GDA_SERVER_OPERATION_DROP_DB))) {
1019 		const GValue *value;
1020 		MYSQL *mysql;
1021 		const gchar *login = NULL;
1022 		const gchar *password = NULL;
1023 		const gchar *host = NULL;
1024 		gint         port = -1;
1025 		const gchar *socket = NULL;
1026 		gboolean     usessl = FALSE;
1027 		const gchar *proto = NULL;
1028 
1029 		value = gda_server_operation_get_value_at (op, "/SERVER_CNX_P/HOST");
1030 		if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value))
1031 			host = g_value_get_string (value);
1032 
1033 		value = gda_server_operation_get_value_at (op, "/SERVER_CNX_P/PORT");
1034 		if (value && G_VALUE_HOLDS (value, G_TYPE_INT) && (g_value_get_int (value) > 0))
1035 			port = g_value_get_int (value);
1036 
1037 		value = gda_server_operation_get_value_at (op, "/SERVER_CNX_P/UNIX_SOCKET");
1038 		if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value))
1039 			socket = g_value_get_string (value);
1040 
1041 		value = gda_server_operation_get_value_at (op, "/SERVER_CNX_P/USE_SSL");
1042 		if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
1043 			usessl = TRUE;
1044 
1045 		value = gda_server_operation_get_value_at (op, "/SERVER_CNX_P/ADM_LOGIN");
1046 		if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value))
1047 			login = g_value_get_string (value);
1048 
1049 		value = gda_server_operation_get_value_at (op, "/SERVER_CNX_P/ADM_PASSWORD");
1050 		if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value))
1051 			password = g_value_get_string (value);
1052 
1053 		value = gda_server_operation_get_value_at (op, "/SERVER_CNX_P/PROTO");
1054 		if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value))
1055 			proto = g_value_get_string (value);
1056 
1057 		mysql = real_open_connection (host, port, socket,
1058                                               "mysql", login, password, usessl, FALSE, proto, error);
1059                 if (!mysql)
1060                         return FALSE;
1061 		else {
1062 			gchar *sql;
1063 			int res;
1064 
1065 			sql = gda_server_provider_render_operation (provider, cnc, op, error);
1066 			if (!sql)
1067 				return FALSE;
1068 
1069 			res = mysql_query (mysql, sql);
1070 			g_free (sql);
1071 
1072 			if (res) {
1073 			  g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
1074 				       GDA_SERVER_PROVIDER_OPERATION_ERROR,
1075 				       "%s", mysql_error (mysql));
1076 				mysql_close (mysql);
1077 				return FALSE;
1078 			}
1079 			else {
1080 				mysql_close (mysql);
1081 				return TRUE;
1082 			}
1083 		}
1084 	}
1085 	else {
1086 		/* use the SQL from the provider to perform the action */
1087 		return gda_server_provider_perform_operation_default (provider, cnc, op, error);
1088 	}
1089 }
1090 
1091 /*
1092  * Begin transaction request
1093  */
1094 static gboolean
gda_mysql_provider_begin_transaction(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED const gchar * name,GdaTransactionIsolation level,GError ** error)1095 gda_mysql_provider_begin_transaction (GdaServerProvider        *provider,
1096 				      GdaConnection            *cnc,
1097 				      G_GNUC_UNUSED const gchar              *name,
1098 				      GdaTransactionIsolation   level,
1099 				      GError                  **error)
1100 {
1101 	MysqlConnectionData *cdata;
1102 	gint rc;
1103 	GdaConnectionEvent *event = NULL;
1104 
1105 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1106 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1107 
1108 	cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1109 	if (!cdata)
1110 		return FALSE;
1111 
1112 	/* set isolation level */
1113         switch (level) {
1114         case GDA_TRANSACTION_ISOLATION_READ_COMMITTED :
1115                 rc = gda_mysql_real_query_wrap (cnc, cdata->mysql, "SET TRANSACTION ISOLATION LEVEL READ COMMITTED", 46);
1116                 break;
1117         case GDA_TRANSACTION_ISOLATION_READ_UNCOMMITTED :
1118                 rc = gda_mysql_real_query_wrap (cnc, cdata->mysql, "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED", 48);
1119                 break;
1120         case GDA_TRANSACTION_ISOLATION_REPEATABLE_READ :
1121                 rc = gda_mysql_real_query_wrap (cnc, cdata->mysql, "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ", 47);
1122                 break;
1123         case GDA_TRANSACTION_ISOLATION_SERIALIZABLE :
1124                 rc = gda_mysql_real_query_wrap (cnc, cdata->mysql, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE", 44);
1125                 break;
1126         default :
1127                 rc = 0;
1128         }
1129 
1130 	if (rc != 0)
1131                 event = _gda_mysql_make_error (cnc, cdata->mysql, NULL, error);
1132         else {
1133                 /* start the transaction */
1134                 rc = gda_mysql_real_query_wrap (cnc, cdata->mysql, "BEGIN", 5);
1135                 if (rc != 0)
1136                         event = _gda_mysql_make_error (cnc, cdata->mysql, NULL, error);
1137         }
1138 
1139 	if (event)
1140 		return FALSE;
1141 	else {
1142 		gda_connection_internal_transaction_started (cnc, NULL, NULL, level);
1143 		return TRUE;
1144 	}
1145 }
1146 
1147 /*
1148  * Commit transaction request
1149  */
1150 static gboolean
gda_mysql_provider_commit_transaction(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED const gchar * name,GError ** error)1151 gda_mysql_provider_commit_transaction (GdaServerProvider  *provider,
1152 				       GdaConnection      *cnc,
1153 				       G_GNUC_UNUSED const gchar        *name,
1154 				       GError            **error)
1155 {
1156 	MysqlConnectionData *cdata;
1157 	gint rc;
1158 
1159 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1160 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1161 
1162 	cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1163 	if (!cdata)
1164 		return FALSE;
1165 
1166 	rc = gda_mysql_real_query_wrap (cnc, cdata->mysql, "COMMIT", 6);
1167 	if (rc != 0) {
1168 		_gda_mysql_make_error (cnc, cdata->mysql, NULL, error);
1169 		return FALSE;
1170 	}
1171 	else {
1172 		gda_connection_internal_transaction_committed (cnc, NULL);
1173 		return TRUE;
1174 	}
1175 }
1176 
1177 /*
1178  * Rollback transaction request
1179  */
1180 static gboolean
gda_mysql_provider_rollback_transaction(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED const gchar * name,GError ** error)1181 gda_mysql_provider_rollback_transaction (GdaServerProvider  *provider,
1182 					 GdaConnection      *cnc,
1183 					 G_GNUC_UNUSED const gchar        *name,
1184 					 GError            **error)
1185 {
1186 	MysqlConnectionData *cdata;
1187 	gint rc;
1188 
1189 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1190 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1191 
1192 	cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1193 	if (!cdata)
1194 		return FALSE;
1195 
1196 	rc = gda_mysql_real_query_wrap (cnc, cdata->mysql, "ROLLBACK", 8);
1197 	if (rc != 0) {
1198 		_gda_mysql_make_error (cnc, cdata->mysql, NULL, error);
1199 		return FALSE;
1200 	}
1201 	else {
1202 		gda_connection_internal_transaction_rolledback (cnc, NULL);
1203 		return TRUE;
1204 	}
1205 }
1206 
1207 /*
1208  * Add savepoint request
1209  */
1210 static gboolean
gda_mysql_provider_add_savepoint(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED const gchar * name,G_GNUC_UNUSED GError ** error)1211 gda_mysql_provider_add_savepoint (GdaServerProvider  *provider,
1212 				  GdaConnection      *cnc,
1213 				  G_GNUC_UNUSED const gchar        *name,
1214 				  G_GNUC_UNUSED GError            **error)
1215 {
1216 	MysqlConnectionData *cdata;
1217 
1218 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1219 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1220 
1221 	cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1222 	if (!cdata)
1223 		return FALSE;
1224 
1225 	TO_IMPLEMENT;
1226 
1227 	return FALSE;
1228 }
1229 
1230 /*
1231  * Rollback savepoint request
1232  */
1233 static gboolean
gda_mysql_provider_rollback_savepoint(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED const gchar * name,G_GNUC_UNUSED GError ** error)1234 gda_mysql_provider_rollback_savepoint (GdaServerProvider  *provider,
1235 				       GdaConnection      *cnc,
1236 				       G_GNUC_UNUSED const gchar        *name,
1237 				       G_GNUC_UNUSED GError            **error)
1238 {
1239 	MysqlConnectionData *cdata;
1240 
1241 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1242 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1243 
1244 	cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1245 	if (!cdata)
1246 		return FALSE;
1247 
1248 	TO_IMPLEMENT;
1249 
1250 	return FALSE;
1251 }
1252 
1253 /*
1254  * Delete savepoint request
1255  */
1256 static gboolean
gda_mysql_provider_delete_savepoint(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED const gchar * name,G_GNUC_UNUSED GError ** error)1257 gda_mysql_provider_delete_savepoint (GdaServerProvider  *provider,
1258 				     GdaConnection      *cnc,
1259 				     G_GNUC_UNUSED const gchar        *name,
1260 				     G_GNUC_UNUSED GError            **error)
1261 {
1262 	MysqlConnectionData *cdata;
1263 
1264 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1265 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1266 
1267 	cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1268 	if (!cdata)
1269 		return FALSE;
1270 
1271 	TO_IMPLEMENT;
1272 
1273 	return FALSE;
1274 }
1275 
1276 /*
1277  * Feature support request
1278  */
1279 static gboolean
gda_mysql_provider_supports_feature(GdaServerProvider * provider,GdaConnection * cnc,GdaConnectionFeature feature)1280 gda_mysql_provider_supports_feature (GdaServerProvider     *provider,
1281 				     GdaConnection         *cnc,
1282 				     GdaConnectionFeature   feature)
1283 {
1284 	if (cnc) {
1285 		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1286 		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1287 	}
1288 
1289 	switch (feature) {
1290 	case GDA_CONNECTION_FEATURE_SQL :
1291 		return TRUE;
1292 	case GDA_CONNECTION_FEATURE_MULTI_THREADING:
1293 		return mysql_thread_safe () ? TRUE : FALSE;
1294 	default:
1295 		return FALSE;
1296 	}
1297 }
1298 
1299 /*
1300  * Get data handler request
1301  *
1302  * This method allows one to obtain a pointer to a #GdaDataHandler object specific to @type or @dbms_type (@dbms_type
1303  * must be considered only if @type is not a valid GType).
1304  *
1305  * A data handler allows one to convert a value between its different representations which are a human readable string,
1306  * an SQL representation and a GValue.
1307  *
1308  * The recommended method is to create GdaDataHandler objects only when they are needed and to keep a reference to them
1309  * for further usage, using the gda_server_provider_handler_declare() method.
1310  *
1311  * The implementation shown here does not define any specific data handler, but there should be some for at least
1312  * binary and time related types.
1313  */
1314 static GdaDataHandler *
gda_mysql_provider_get_data_handler(GdaServerProvider * provider,GdaConnection * cnc,GType type,const gchar * dbms_type)1315 gda_mysql_provider_get_data_handler (GdaServerProvider  *provider,
1316 				     GdaConnection      *cnc,
1317 				     GType               type,
1318 				     const gchar        *dbms_type)
1319 {
1320 	GdaDataHandler *dh;
1321 	if (cnc) {
1322 		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1323 		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1324 	}
1325 
1326 	if (type == G_TYPE_INVALID) {
1327 		TO_IMPLEMENT; /* use @dbms_type */
1328 		dh = NULL;
1329 	}
1330 	else if (type == GDA_TYPE_BINARY) {
1331 		dh = gda_server_provider_handler_find (provider, cnc, type, NULL);
1332                 if (!dh) {
1333 			dh = _gda_mysql_handler_bin_new ();
1334                         gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_BINARY, NULL);
1335                         g_object_unref (dh);
1336                 }
1337 	}
1338 	else if ((type == GDA_TYPE_TIME) ||
1339 		 (type == GDA_TYPE_TIMESTAMP) ||
1340 		 (type == G_TYPE_DATE)) {
1341 		dh = gda_server_provider_handler_find (provider, NULL, type, NULL);
1342                 if (!dh) {
1343                         dh = gda_handler_time_new ();
1344                         gda_handler_time_set_sql_spec ((GdaHandlerTime *) dh, G_DATE_YEAR,
1345                                                        G_DATE_MONTH, G_DATE_DAY, '-', FALSE);
1346                         gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_DATE, NULL);
1347                         gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_TIME, NULL);
1348                         gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_TIMESTAMP, NULL);
1349                         g_object_unref (dh);
1350                 }
1351 	}
1352 	else if (type == G_TYPE_BOOLEAN){
1353 		dh = gda_server_provider_handler_find (provider, cnc, type, NULL);
1354                 if (!dh) {
1355                         dh = gda_mysql_handler_boolean_new ();
1356                         if (dh) {
1357                                 gda_server_provider_handler_declare (provider, dh, cnc, G_TYPE_BOOLEAN, NULL);
1358                                 g_object_unref (dh);
1359                         }
1360                 }
1361 	}
1362 	else
1363 		dh = gda_server_provider_handler_use_default (provider, type);
1364 
1365 	return dh;
1366 }
1367 
1368 /*
1369  * Get default DBMS type request
1370  *
1371  * This method returns the "preferred" DBMS type for GType
1372  */
1373 static const gchar*
gda_mysql_provider_get_default_dbms_type(GdaServerProvider * provider,GdaConnection * cnc,GType type)1374 gda_mysql_provider_get_default_dbms_type (GdaServerProvider  *provider,
1375 					  GdaConnection      *cnc,
1376 					  GType               type)
1377 {
1378 	if (cnc) {
1379 		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
1380 		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
1381 	}
1382 
1383 	if (type == G_TYPE_INT64)
1384 		return "bigint";
1385 	if (type == G_TYPE_UINT64)
1386 		return "bigint unsigned";
1387 	if (type == GDA_TYPE_BINARY)
1388 		return "varbinary";
1389 	if (type == GDA_TYPE_BLOB)
1390 		return "blob";
1391 	if (type == G_TYPE_BOOLEAN)
1392 		return "bool";
1393 	if (type == G_TYPE_DATE)
1394 		return "date";
1395 	if (type == G_TYPE_DOUBLE)
1396 		return "double";
1397 	if (type == GDA_TYPE_GEOMETRIC_POINT)
1398 		return "point";
1399 	if (type == G_TYPE_OBJECT)
1400 		return "text";
1401 	if (type == G_TYPE_INT)
1402 		return "int";
1403 	if (type == GDA_TYPE_NUMERIC)
1404 		return "numeric";
1405 	if (type == G_TYPE_FLOAT)
1406 		return "float";
1407 	if (type == GDA_TYPE_SHORT)
1408 		return "smallint";
1409 	if (type == GDA_TYPE_USHORT)
1410 		return "smallint unsigned";
1411 	if (type == G_TYPE_STRING)
1412 		return "varchar";
1413 	if (type == GDA_TYPE_TIME)
1414 		return "time";
1415 	if (type == GDA_TYPE_TIMESTAMP)
1416 		return "timestamp";
1417 	if (type == G_TYPE_CHAR)
1418 		return "tinyint";
1419 	if (type == G_TYPE_UCHAR)
1420 		return "tinyint unsigned";
1421 	if (type == G_TYPE_ULONG)
1422 		return "bigint unsigned";
1423 	if (type == G_TYPE_UINT)
1424 		return "int unsigned";
1425 
1426 	if ((type == GDA_TYPE_NULL) ||
1427 	    (type == G_TYPE_GTYPE))
1428 		return NULL;
1429 
1430 	return "text";
1431 }
1432 
1433 /*
1434  * Create parser request
1435  *
1436  * This method is responsible for creating a #GdaSqlParser object specific to the SQL dialect used
1437  * by the database. See the PostgreSQL provider implementation for an example.
1438  */
1439 static GdaSqlParser *
gda_mysql_provider_create_parser(G_GNUC_UNUSED GdaServerProvider * provider,G_GNUC_UNUSED GdaConnection * cnc)1440 gda_mysql_provider_create_parser (G_GNUC_UNUSED GdaServerProvider  *provider,
1441 				  G_GNUC_UNUSED GdaConnection      *cnc)
1442 {
1443 	return (GdaSqlParser *) g_object_new (GDA_TYPE_MYSQL_PARSER,
1444 					      "tokenizer-flavour", GDA_SQL_PARSER_FLAVOUR_MYSQL,
1445 					      NULL);
1446 }
1447 
1448 /*
1449  * GdaStatement to SQL request
1450  *
1451  * This method renders a #GdaStatement into its SQL representation.
1452  */
1453 static gchar *mysql_render_insert (GdaSqlStatementInsert *stmt, GdaSqlRenderingContext *context, GError **error);
1454 static gchar *mysql_render_function (GdaSqlFunction *func, GdaSqlRenderingContext *context, GError **error);
1455 static gchar *mysql_render_expr (GdaSqlExpr *expr, GdaSqlRenderingContext *context,
1456 				 gboolean *is_default, gboolean *is_null,
1457 				 GError **error);
1458 static gchar *
gda_mysql_provider_statement_to_sql(GdaServerProvider * provider,GdaConnection * cnc,GdaStatement * stmt,GdaSet * params,GdaStatementSqlFlag flags,GSList ** params_used,GError ** error)1459 gda_mysql_provider_statement_to_sql (GdaServerProvider    *provider,
1460 				     GdaConnection        *cnc,
1461 				     GdaStatement         *stmt,
1462 				     GdaSet               *params,
1463 				     GdaStatementSqlFlag   flags,
1464 				     GSList              **params_used,
1465 				     GError              **error)
1466 {
1467 	gchar *str;
1468         GdaSqlRenderingContext context;
1469 
1470         g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
1471         if (cnc) {
1472                 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
1473                 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
1474         }
1475 
1476         memset (&context, 0, sizeof (context));
1477 	context.provider = provider;
1478 	context.cnc = cnc;
1479         context.params = params;
1480         context.flags = flags;
1481 	context.render_function = (GdaSqlRenderingFunc) mysql_render_function; /* don't put any space between function name
1482 										* and the opening parenthesis, see
1483 										* http://blog.152.org/2009/12/mysql-error-1305-function-xxx-does-not.html */
1484 	context.render_expr = mysql_render_expr; /* render "FALSE" as 0 and TRUE as 1 */
1485 	context.render_insert = (GdaSqlRenderingFunc) mysql_render_insert;
1486 
1487         str = gda_statement_to_sql_real (stmt, &context, error);
1488 
1489         if (str) {
1490                 if (params_used)
1491                         *params_used = context.params_used;
1492                 else
1493                         g_slist_free (context.params_used);
1494         }
1495         else {
1496                 if (params_used)
1497                         *params_used = NULL;
1498                 g_slist_free (context.params_used);
1499         }
1500         return str;
1501 }
1502 
1503 static gchar *
mysql_render_insert(GdaSqlStatementInsert * stmt,GdaSqlRenderingContext * context,GError ** error)1504 mysql_render_insert (GdaSqlStatementInsert *stmt, GdaSqlRenderingContext *context, GError **error)
1505 {
1506 	GString *string;
1507 	gchar *str;
1508 	GSList *list;
1509 	gboolean pretty = context->flags & GDA_STATEMENT_SQL_PRETTY;
1510 
1511 	g_return_val_if_fail (stmt, NULL);
1512 	g_return_val_if_fail (GDA_SQL_ANY_PART (stmt)->type == GDA_SQL_ANY_STMT_INSERT, NULL);
1513 
1514 	string = g_string_new ("INSERT ");
1515 
1516 	/* conflict algo */
1517 	if (stmt->on_conflict)
1518 		g_string_append_printf (string, "OR %s ", stmt->on_conflict);
1519 
1520 	/* INTO */
1521 	g_string_append (string, "INTO ");
1522 	str = context->render_table (GDA_SQL_ANY_PART (stmt->table), context, error);
1523 	if (!str) goto err;
1524 	g_string_append (string, str);
1525 	g_free (str);
1526 
1527 	/* fields list */
1528 	for (list = stmt->fields_list; list; list = list->next) {
1529 		if (list == stmt->fields_list)
1530 			g_string_append (string, " (");
1531 		else
1532 			g_string_append (string, ", ");
1533 		str = context->render_field (GDA_SQL_ANY_PART (list->data), context, error);
1534 		if (!str) goto err;
1535 		g_string_append (string, str);
1536 		g_free (str);
1537 	}
1538 	if (stmt->fields_list)
1539 		g_string_append_c (string, ')');
1540 
1541 	/* values */
1542 	if (stmt->select) {
1543 		if (pretty)
1544 			g_string_append_c (string, '\n');
1545 		else
1546 			g_string_append_c (string, ' ');
1547 		str = context->render_select (GDA_SQL_ANY_PART (stmt->select), context, error);
1548 		if (!str) goto err;
1549 		g_string_append (string, str);
1550 			g_free (str);
1551 	}
1552 	else {
1553 		for (list = stmt->values_list; list; list = list->next) {
1554 			GSList *rlist;
1555 			if (list == stmt->values_list) {
1556 				if (pretty)
1557 					g_string_append (string, "\nVALUES");
1558 				else
1559 					g_string_append (string, " VALUES");
1560 			}
1561 			else
1562 				g_string_append_c (string, ',');
1563 			for (rlist = (GSList*) list->data; rlist; rlist = rlist->next) {
1564 				if (rlist == (GSList*) list->data)
1565 					g_string_append (string, " (");
1566 				else
1567 					g_string_append (string, ", ");
1568 				str = context->render_expr ((GdaSqlExpr*) rlist->data, context, NULL, NULL, error);
1569 				if (!str) goto err;
1570 				if (pretty && (rlist != (GSList*) list->data))
1571 					g_string_append (string, "\n\t");
1572 				g_string_append (string, str);
1573 				g_free (str);
1574 			}
1575 			g_string_append_c (string, ')');
1576 		}
1577 
1578 		if (!stmt->fields_list && !stmt->values_list)
1579 			g_string_append (string, " () VALUES ()");
1580 	}
1581 
1582 	str = string->str;
1583 	g_string_free (string, FALSE);
1584 	return str;
1585 
1586  err:
1587 	g_string_free (string, TRUE);
1588 	return NULL;
1589 }
1590 
1591 static gchar *
mysql_render_function(GdaSqlFunction * func,GdaSqlRenderingContext * context,GError ** error)1592 mysql_render_function (GdaSqlFunction *func, GdaSqlRenderingContext *context, GError **error)
1593 {
1594 	GString *string;
1595 	gchar *str;
1596 	GSList *list;
1597 
1598 	g_return_val_if_fail (func, NULL);
1599 	g_return_val_if_fail (GDA_SQL_ANY_PART (func)->type == GDA_SQL_ANY_SQL_FUNCTION, NULL);
1600 
1601 	/* can't have: func->function_name == NULL */
1602 	if (!gda_sql_any_part_check_structure (GDA_SQL_ANY_PART (func), error)) return NULL;
1603 
1604 	string = g_string_new (func->function_name);
1605 	g_string_append_c (string, '(');
1606 	for (list = func->args_list; list; list = list->next) {
1607 		if (list != func->args_list)
1608 			g_string_append (string, ", ");
1609 		str = context->render_expr (list->data, context, NULL, NULL, error);
1610 		if (!str) goto err;
1611 		g_string_append (string, str);
1612 		g_free (str);
1613 	}
1614 	g_string_append_c (string, ')');
1615 
1616 	str = string->str;
1617 	g_string_free (string, FALSE);
1618 	return str;
1619 
1620  err:
1621 	g_string_free (string, TRUE);
1622 	return NULL;
1623 }
1624 
1625 /*
1626  * The difference with the default implementation is to render TRUE and FALSE as 0 and 1
1627  */
1628 static gchar *
mysql_render_expr(GdaSqlExpr * expr,GdaSqlRenderingContext * context,gboolean * is_default,gboolean * is_null,GError ** error)1629 mysql_render_expr (GdaSqlExpr *expr, GdaSqlRenderingContext *context, gboolean *is_default,
1630 		   gboolean *is_null, GError **error)
1631 {
1632 	GString *string;
1633 	gchar *str = NULL;
1634 
1635 	g_return_val_if_fail (expr, NULL);
1636 	g_return_val_if_fail (GDA_SQL_ANY_PART (expr)->type == GDA_SQL_ANY_EXPR, NULL);
1637 
1638 	if (is_default)
1639 		*is_default = FALSE;
1640 	if (is_null)
1641 		*is_null = FALSE;
1642 
1643 	/* can't have:
1644 	 *  - expr->cast_as && expr->param_spec
1645 	 */
1646 	if (!gda_sql_any_part_check_structure (GDA_SQL_ANY_PART (expr), error)) return NULL;
1647 
1648 	string = g_string_new ("");
1649 	if (expr->param_spec) {
1650 		str = context->render_param_spec (expr->param_spec, expr, context, is_default, is_null, error);
1651 		if (!str) goto err;
1652 	}
1653 	else if (expr->value) {
1654 		if (G_VALUE_TYPE (expr->value) == G_TYPE_STRING) {
1655 			/* specific treatment for strings, see documentation about GdaSqlExpr's value attribute */
1656 			const gchar *vstr;
1657 			vstr = g_value_get_string (expr->value);
1658 			if (vstr) {
1659 				if (expr->value_is_ident) {
1660 					gchar **ids_array;
1661 					gint i;
1662 					GString *string = NULL;
1663 					GdaConnectionOptions cncoptions = 0;
1664 					if (context->cnc)
1665 						g_object_get (G_OBJECT (context->cnc), "options", &cncoptions, NULL);
1666 					ids_array = gda_sql_identifier_split (vstr);
1667 					if (!ids_array)
1668 						str = g_strdup (vstr);
1669 					else if (!(ids_array[0])) goto err;
1670 					else {
1671 						for (i = 0; ids_array[i]; i++) {
1672 							gchar *tmp;
1673 							if (!string)
1674 								string = g_string_new ("");
1675 							else
1676 								g_string_append_c (string, '.');
1677 							tmp = gda_sql_identifier_quote (ids_array[i], context->cnc,
1678 											context->provider, FALSE,
1679 											cncoptions & GDA_CONNECTION_OPTIONS_SQL_IDENTIFIERS_CASE_SENSITIVE);
1680 							g_string_append (string, tmp);
1681 							g_free (tmp);
1682 						}
1683 						g_strfreev (ids_array);
1684 						str = g_string_free (string, FALSE);
1685 					}
1686 				}
1687 				else {
1688 					/* we don't have an identifier */
1689 					if (!g_ascii_strcasecmp (vstr, "default")) {
1690 						if (is_default)
1691 							*is_default = TRUE;
1692 						str = g_strdup ("DEFAULT");
1693 					}
1694 					else if (!g_ascii_strcasecmp (vstr, "FALSE")) {
1695 						g_free (str);
1696 						str = g_strdup ("0");
1697 					}
1698 					else if (!g_ascii_strcasecmp (vstr, "TRUE")) {
1699 						g_free (str);
1700 						str = g_strdup ("1");
1701 					}
1702 					else
1703 						str = g_strdup (vstr);
1704 				}
1705 			}
1706 			else {
1707 				str = g_strdup ("NULL");
1708 				if (is_null)
1709 					*is_null = TRUE;
1710 			}
1711 		}
1712 		if (!str) {
1713 			/* use a GdaDataHandler to render the value as valid SQL */
1714 			GdaDataHandler *dh;
1715 			if (context->cnc) {
1716 				GdaServerProvider *prov;
1717 				prov = gda_connection_get_provider (context->cnc);
1718 				dh = gda_server_provider_get_data_handler_g_type (prov, context->cnc,
1719 										  G_VALUE_TYPE (expr->value));
1720 				if (!dh) goto err;
1721 			}
1722 			else
1723 				dh = gda_data_handler_get_default (G_VALUE_TYPE (expr->value));
1724 
1725 			if (dh)
1726 				str = gda_data_handler_get_sql_from_value (dh, expr->value);
1727 			else
1728 				str = gda_value_stringify (expr->value);
1729 			if (!str) goto err;
1730 		}
1731 	}
1732 	else if (expr->func) {
1733 		str = context->render_function (GDA_SQL_ANY_PART (expr->func), context, error);
1734 		if (!str) goto err;
1735 	}
1736 	else if (expr->cond) {
1737 		gchar *tmp;
1738 		tmp = context->render_operation (GDA_SQL_ANY_PART (expr->cond), context, error);
1739 		if (!tmp) goto err;
1740 		str = NULL;
1741 		if (GDA_SQL_ANY_PART (expr)->parent) {
1742 			if (GDA_SQL_ANY_PART (expr)->parent->type == GDA_SQL_ANY_STMT_SELECT) {
1743 				GdaSqlStatementSelect *selst;
1744 				selst = (GdaSqlStatementSelect*) (GDA_SQL_ANY_PART (expr)->parent);
1745 				if ((expr == selst->where_cond) ||
1746 				    (expr == selst->having_cond))
1747 					str = tmp;
1748 			}
1749 			else if (GDA_SQL_ANY_PART (expr)->parent->type == GDA_SQL_ANY_STMT_DELETE) {
1750 				GdaSqlStatementDelete *delst;
1751 				delst = (GdaSqlStatementDelete*) (GDA_SQL_ANY_PART (expr)->parent);
1752 				if (expr == delst->cond)
1753 					str = tmp;
1754 			}
1755 			else if (GDA_SQL_ANY_PART (expr)->parent->type == GDA_SQL_ANY_STMT_UPDATE) {
1756 				GdaSqlStatementUpdate *updst;
1757 				updst = (GdaSqlStatementUpdate*) (GDA_SQL_ANY_PART (expr)->parent);
1758 				if (expr == updst->cond)
1759 					str = tmp;
1760 			}
1761 		}
1762 
1763 		if (!str) {
1764 			str = g_strconcat ("(", tmp, ")", NULL);
1765 			g_free (tmp);
1766 		}
1767 	}
1768 	else if (expr->select) {
1769 		gchar *str1;
1770 		if (GDA_SQL_ANY_PART (expr->select)->type == GDA_SQL_ANY_STMT_SELECT)
1771 			str1 = context->render_select (GDA_SQL_ANY_PART (expr->select), context, error);
1772 		else if (GDA_SQL_ANY_PART (expr->select)->type == GDA_SQL_ANY_STMT_COMPOUND)
1773 			str1 = context->render_compound (GDA_SQL_ANY_PART (expr->select), context, error);
1774 		else
1775 			g_assert_not_reached ();
1776 		if (!str1) goto err;
1777 
1778 		if (! GDA_SQL_ANY_PART (expr)->parent ||
1779 		    (GDA_SQL_ANY_PART (expr)->parent->type != GDA_SQL_ANY_SQL_FUNCTION)) {
1780 			str = g_strconcat ("(", str1, ")", NULL);
1781 			g_free (str1);
1782 		}
1783 		else
1784 			str = str1;
1785 	}
1786 	else if (expr->case_s) {
1787 		str = context->render_case (GDA_SQL_ANY_PART (expr->case_s), context, error);
1788 		if (!str) goto err;
1789 	}
1790 	else {
1791 		if (is_null)
1792 			*is_null = TRUE;
1793 		str = g_strdup ("NULL");
1794 	}
1795 
1796 	if (!str) goto err;
1797 
1798 	if (expr->cast_as)
1799 		g_string_append_printf (string, "CAST (%s AS %s)", str, expr->cast_as);
1800 	else
1801 		g_string_append (string, str);
1802 	g_free (str);
1803 
1804 	str = string->str;
1805 	g_string_free (string, FALSE);
1806 	return str;
1807 
1808  err:
1809 	g_string_free (string, TRUE);
1810 	return NULL;
1811 }
1812 
1813 static GdaMysqlPStmt *
real_prepare(GdaServerProvider * provider,GdaConnection * cnc,GdaStatement * stmt,GError ** error)1814 real_prepare (GdaServerProvider *provider, GdaConnection *cnc, GdaStatement *stmt, GError **error)
1815 {
1816 	GdaMysqlPStmt *ps = NULL;
1817 	MysqlConnectionData *cdata;
1818 
1819 	cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1820 	if (!cdata)
1821 		return NULL;
1822 
1823 	/* Render as SQL understood by Mysql. */
1824 	GdaSet *set;
1825 	if (!gda_statement_get_parameters (stmt, &set, error))
1826 		return NULL;
1827 
1828 	GSList *used_set = NULL;
1829 	gchar *sql = gda_mysql_provider_statement_to_sql (provider, cnc, stmt, set,
1830 							  GDA_STATEMENT_SQL_PARAMS_AS_UQMARK, &used_set, error);
1831 
1832 	if (!sql)
1833 		goto cleanup;
1834 
1835 	MYSQL_STMT *mysql_stmt = mysql_stmt_init (cdata->mysql);
1836 	if (!mysql_stmt) {
1837 		_gda_mysql_make_error (cnc, NULL, mysql_stmt, error);
1838 		return FALSE;
1839 	}
1840 
1841 	my_bool update_max_length = 1;
1842 	if (mysql_stmt_attr_set (mysql_stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (const void *) &update_max_length)) {
1843 		_gda_mysql_make_error (cnc, NULL, mysql_stmt, error);
1844 		mysql_stmt_close (mysql_stmt);
1845 		return FALSE;
1846 	}
1847 
1848 	if (mysql_stmt_prepare (mysql_stmt, sql, strlen (sql))) {
1849 		_gda_mysql_make_error (cdata->cnc, NULL, mysql_stmt, error);
1850 		mysql_stmt_close (mysql_stmt);
1851 		goto cleanup;
1852 	}
1853 
1854 	GSList *param_ids = NULL, *current;
1855 	for (current = used_set; current; current = current->next) {
1856 		const gchar *id = gda_holder_get_id
1857 			(GDA_HOLDER(current->data));
1858 		if (id) {
1859 			param_ids = g_slist_append (param_ids, g_strdup (id));
1860 		}
1861 		else {
1862 			g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
1863 				     GDA_SERVER_PROVIDER_PREPARE_STMT_ERROR,
1864 				     "%s", _("Unnamed statement parameter is not allowed in prepared statement."));
1865 			g_slist_foreach (param_ids, (GFunc) g_free, NULL);
1866 			g_slist_free (param_ids);
1867 			param_ids = NULL;
1868 			mysql_stmt_close (mysql_stmt);
1869 			goto cleanup;
1870 		}
1871 	}
1872 
1873 	/* Create prepared statement. */
1874 	ps = gda_mysql_pstmt_new (cnc, cdata->mysql, mysql_stmt);
1875 
1876 	if (!ps)
1877 		return NULL;
1878 	else {
1879 		gda_pstmt_set_gda_statement (_GDA_PSTMT(ps), stmt);
1880 		_GDA_PSTMT(ps)->param_ids = param_ids;
1881 		_GDA_PSTMT(ps)->sql = sql;
1882 		return ps;
1883 	}
1884 
1885  cleanup:
1886 
1887 	if (set)
1888 		g_object_unref (G_OBJECT(set));
1889 	if (used_set)
1890 		g_slist_free (used_set);
1891 	g_free (sql);
1892 
1893 	return NULL;
1894 }
1895 
1896 /*
1897  * Statement prepare request
1898  *
1899  * This methods "converts" @stmt into a prepared statement. A prepared statement is a notion
1900  * specific in its implementation details to the C API used here. If successfull, it must create
1901  * a new #GdaMysqlPStmt object and declare it to @cnc.
1902  */
1903 static gboolean
gda_mysql_provider_statement_prepare(GdaServerProvider * provider,GdaConnection * cnc,GdaStatement * stmt,GError ** error)1904 gda_mysql_provider_statement_prepare (GdaServerProvider  *provider,
1905 				      GdaConnection      *cnc,
1906 				      GdaStatement       *stmt,
1907 				      GError            **error)
1908 {
1909 	GdaMysqlPStmt *ps;
1910 
1911 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1912 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1913 	g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE);
1914 
1915 	/* fetch prepares stmt if already done */
1916 	ps = (GdaMysqlPStmt*) gda_connection_get_prepared_statement (cnc, stmt);
1917 	if (ps)
1918 		return TRUE;
1919 
1920 	ps = real_prepare (provider, cnc, stmt, error);
1921         if (!ps)
1922                 return FALSE;
1923         else {
1924                 gda_connection_add_prepared_statement (cnc, stmt, (GdaPStmt *) ps);
1925                 g_object_unref (ps);
1926                 return TRUE;
1927         }
1928 }
1929 
1930 
1931 static GdaMysqlPStmt *
prepare_stmt_simple(MysqlConnectionData * cdata,const gchar * sql,GError ** error,gboolean * out_protocol_error)1932 prepare_stmt_simple (MysqlConnectionData  *cdata,
1933 		     const gchar          *sql,
1934 		     GError              **error,
1935 		     gboolean *out_protocol_error)
1936 {
1937 	GdaMysqlPStmt *ps = NULL;
1938 	*out_protocol_error = FALSE;
1939 	g_return_val_if_fail (sql != NULL, NULL);
1940 
1941 	MYSQL_STMT *mysql_stmt = mysql_stmt_init (cdata->mysql);
1942 	if (!mysql_stmt) {
1943 		_gda_mysql_make_error (cdata->cnc, NULL, mysql_stmt, error);
1944 		return FALSE;
1945 	}
1946 
1947 	my_bool update_max_length = 1;
1948 	if (mysql_stmt_attr_set (mysql_stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (const void *) &update_max_length)) {
1949 		_gda_mysql_make_error (cdata->cnc, NULL, mysql_stmt, error);
1950 		mysql_stmt_close (mysql_stmt);
1951 		return FALSE;
1952 	}
1953 
1954 	if (mysql_stmt_prepare (mysql_stmt, sql, strlen (sql))) {
1955 		_gda_mysql_make_error (cdata->cnc, NULL, mysql_stmt, error);
1956 		if (mysql_stmt_errno (mysql_stmt) == ER_UNSUPPORTED_PS)
1957 			*out_protocol_error = TRUE;
1958 		mysql_stmt_close (mysql_stmt);
1959 		ps = NULL;
1960 	}
1961 	else {
1962 		ps = gda_mysql_pstmt_new (cdata->cnc, cdata->mysql, mysql_stmt);
1963 		_GDA_PSTMT(ps)->param_ids = NULL;
1964 		_GDA_PSTMT(ps)->sql = g_strdup (sql);
1965 	}
1966 
1967 	return ps;
1968 }
1969 
1970 static GdaSet *
make_last_inserted_set(GdaConnection * cnc,GdaStatement * stmt,my_ulonglong last_id)1971 make_last_inserted_set (GdaConnection *cnc, GdaStatement *stmt, my_ulonglong last_id)
1972 {
1973 	GError *lerror = NULL;
1974 
1975 	/* analyze @stmt */
1976 	GdaSqlStatement *sql_insert;
1977 	GdaSqlStatementInsert *insert;
1978 	if (gda_statement_get_statement_type (stmt) != GDA_SQL_STATEMENT_INSERT)
1979 		/* unable to compute anything */
1980 		return NULL;
1981 
1982 	g_object_get (G_OBJECT (stmt), "structure", &sql_insert, NULL);
1983 	g_assert (sql_insert);
1984 	insert = (GdaSqlStatementInsert *) sql_insert->contents;
1985 
1986 	/* find the name of the 1st column which has the AUTO_INCREMENT */
1987 	gchar *autoinc_colname = NULL;
1988 	gint rc;
1989 	gchar *sql;
1990 	MysqlConnectionData *cdata;
1991 	cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
1992 	if (!cdata)
1993 		return NULL;
1994 	sql = g_strdup_printf ("DESCRIBE %s", insert->table->table_name);
1995 	rc = gda_mysql_real_query_wrap (cnc, cdata->mysql, sql, strlen (sql));
1996 	g_free (sql);
1997 	if (!rc) {
1998 		MYSQL_RES *result;
1999 		result = mysql_store_result (cdata->mysql);
2000 		if (result) {
2001 			MYSQL_ROW row;
2002 			unsigned int nfields;
2003 			nfields = mysql_num_fields (result);
2004 			while ((row = mysql_fetch_row(result))) {
2005 				if (row [nfields-1] &&
2006 				    !g_ascii_strcasecmp (row [nfields-1], "auto_increment")) {
2007 					autoinc_colname = g_strdup (row [0]);
2008 					break;
2009 				}
2010 			}
2011 			mysql_free_result (result);
2012 		}
2013 	}
2014 	if (! autoinc_colname) {
2015 		gda_sql_statement_free (sql_insert);
2016 		return NULL;
2017 	}
2018 
2019 	/* build corresponding SELECT statement */
2020 	GdaSqlStatementSelect *select;
2021         GdaSqlSelectTarget *target;
2022         GdaSqlStatement *sql_statement = gda_sql_statement_new (GDA_SQL_STATEMENT_SELECT);
2023 
2024 	select = g_new0 (GdaSqlStatementSelect, 1);
2025         GDA_SQL_ANY_PART (select)->type = GDA_SQL_ANY_STMT_SELECT;
2026         sql_statement->contents = select;
2027 
2028 	/* FROM */
2029         select->from = gda_sql_select_from_new (GDA_SQL_ANY_PART (select));
2030         target = gda_sql_select_target_new (GDA_SQL_ANY_PART (select->from));
2031         gda_sql_select_from_take_new_target (select->from, target);
2032 
2033 	/* Filling in the target */
2034         GValue *value;
2035         g_value_set_string ((value = gda_value_new (G_TYPE_STRING)), insert->table->table_name);
2036         gda_sql_select_target_take_table_name (target, value);
2037 	gda_sql_statement_free (sql_insert);
2038 
2039 	/* selected fields */
2040         GdaSqlSelectField *field;
2041         GSList *fields_list = NULL;
2042 
2043 	field = gda_sql_select_field_new (GDA_SQL_ANY_PART (select));
2044 	g_value_set_string ((value = gda_value_new (G_TYPE_STRING)), "*");
2045 	gda_sql_select_field_take_star_value (field, value);
2046 	fields_list = g_slist_append (fields_list, field);
2047 
2048 	gda_sql_statement_select_take_expr_list (sql_statement, fields_list);
2049 
2050 	/* WHERE */
2051         GdaSqlExpr *where, *expr;
2052 	GdaSqlOperation *cond;
2053 	where = gda_sql_expr_new (GDA_SQL_ANY_PART (select));
2054 	cond = gda_sql_operation_new (GDA_SQL_ANY_PART (where));
2055 	where->cond = cond;
2056 	cond->operator_type = GDA_SQL_OPERATOR_TYPE_EQ;
2057 	expr = gda_sql_expr_new (GDA_SQL_ANY_PART (cond));
2058 	g_value_take_string ((value = gda_value_new (G_TYPE_STRING)), autoinc_colname);
2059 	expr->value = value;
2060 	cond->operands = g_slist_append (NULL, expr);
2061 	gchar *str;
2062 	str = g_strdup_printf ("%llu", last_id);
2063 	expr = gda_sql_expr_new (GDA_SQL_ANY_PART (cond));
2064 	g_value_take_string ((value = gda_value_new (G_TYPE_STRING)), str);
2065 	expr->value = value;
2066 	cond->operands = g_slist_append (cond->operands, expr);
2067 
2068 	gda_sql_statement_select_take_where_cond (sql_statement, where);
2069 
2070 	if (gda_sql_statement_check_structure (sql_statement, &lerror) == FALSE) {
2071                 g_warning (_("Can't build SELECT statement to get last inserted row: %s"),
2072 			     lerror && lerror->message ? lerror->message : _("No detail"));
2073 		if (lerror)
2074 			g_error_free (lerror);
2075                 gda_sql_statement_free (sql_statement);
2076                 return NULL;
2077         }
2078 
2079 	/* execute SELECT statement */
2080 	GdaDataModel *model;
2081 	GdaStatement *statement = g_object_new (GDA_TYPE_STATEMENT, "structure", sql_statement, NULL);
2082         gda_sql_statement_free (sql_statement);
2083         model = gda_connection_statement_execute_select (cnc, statement, NULL, &lerror);
2084 	g_object_unref (statement);
2085         if (!model) {
2086                 g_warning (_("Can't execute SELECT statement to get last inserted row: %s"),
2087 			   lerror && lerror->message ? lerror->message : _("No detail"));
2088 		if (lerror)
2089 			g_error_free (lerror);
2090 		return NULL;
2091         }
2092 	else {
2093 		GdaSet *set = NULL;
2094 		GSList *holders = NULL;
2095 		gint nrows, ncols, i;
2096 
2097 		nrows = gda_data_model_get_n_rows (model);
2098 		if (nrows <= 0) {
2099 			g_warning (_("SELECT statement to get last inserted row did not return any row"));
2100 			return NULL;
2101 		}
2102 		else if (nrows > 1) {
2103 			g_warning (_("SELECT statement to get last inserted row returned too many (%d) rows"),
2104 				   nrows);
2105 			return NULL;
2106 		}
2107 		ncols = gda_data_model_get_n_columns (model);
2108 		for (i = 0; i < ncols; i++) {
2109 			GdaHolder *h;
2110 			GdaColumn *col;
2111 			gchar *id;
2112 			const GValue *cvalue;
2113 
2114 			col = gda_data_model_describe_column (model, i);
2115 			h = gda_holder_new (gda_column_get_g_type (col));
2116 			id = g_strdup_printf ("+%d", i);
2117 			g_object_set (G_OBJECT (h), "id", id, "not-null", FALSE,
2118 				      "name", gda_column_get_name (col), NULL);
2119 			g_free (id);
2120 			cvalue = gda_data_model_get_value_at (model, i, 0, NULL);
2121 			if (!cvalue || !gda_holder_set_value (h, cvalue, NULL)) {
2122 				if (holders) {
2123 					g_slist_foreach (holders, (GFunc) g_object_unref, NULL);
2124 					g_slist_free (holders);
2125 					holders = NULL;
2126 				}
2127 				break;
2128 			}
2129 			holders = g_slist_prepend (holders, h);
2130 		}
2131 		g_object_unref (model);
2132 
2133 		if (holders) {
2134 			holders = g_slist_reverse (holders);
2135 			set = gda_set_new (holders);
2136 			g_slist_foreach (holders, (GFunc) g_object_unref, NULL);
2137 			g_slist_free (holders);
2138 		}
2139 
2140 		return set;
2141 	}
2142 }
2143 
2144 static void
free_bind_param_data(GSList * mem_to_free)2145 free_bind_param_data (GSList *mem_to_free)
2146 {
2147 	if (mem_to_free) {
2148 		g_slist_foreach (mem_to_free, (GFunc) g_free, NULL);
2149 		g_slist_free (mem_to_free);
2150 	}
2151 }
2152 
2153 /*
2154  * Execute statement request
2155  *
2156  * Executes a statement. This method should do the following:
2157  *    - try to prepare the statement if not yet done
2158  *    - optionnally reset the prepared statement
2159  *    - bind the variables's values (which are in @params)
2160  *    - add a connection event to log the execution
2161  *    - execute the prepared statement
2162  *
2163  * If @stmt is an INSERT statement and @last_inserted_row is not NULL then additional actions must be taken to return the
2164  * actual inserted row
2165  */
2166 static GObject *
gda_mysql_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)2167 gda_mysql_provider_statement_execute (GdaServerProvider               *provider,
2168 				      GdaConnection                   *cnc,
2169 				      GdaStatement                    *stmt,
2170 				      GdaSet                          *params,
2171 				      GdaStatementModelUsage           model_usage,
2172 				      GType                           *col_types,
2173 				      GdaSet                         **last_inserted_row,
2174 				      guint                           *task_id,
2175 				      GdaServerProviderExecCallback    async_cb,
2176 				      gpointer                         cb_data,
2177 				      GError                         **error)
2178 {
2179 	GdaMysqlPStmt *ps;
2180 	MysqlConnectionData *cdata;
2181 	gboolean allow_noparam;
2182         gboolean empty_rs = FALSE; /* TRUE when @allow_noparam is TRUE and there is a problem with @params
2183                                       => resulting data model will be empty (0 row) */
2184 
2185 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
2186 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
2187 	g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
2188 
2189 	/* If asynchronous connection opening is not supported, then exit now */
2190 	if (async_cb) {
2191 		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
2192 			     "%s", _("Provider does not support asynchronous statement execution"));
2193                 return FALSE;
2194 	}
2195 
2196 	allow_noparam = (model_usage & GDA_STATEMENT_MODEL_ALLOW_NOPARAM) &&
2197 		(gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT);
2198 
2199 	if (last_inserted_row)
2200 		*last_inserted_row = NULL;
2201 
2202 	cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
2203 	if (!cdata)
2204 		return FALSE;
2205 
2206 	/* get/create new prepared statement */
2207 	ps = (GdaMysqlPStmt *) gda_connection_get_prepared_statement (cnc, stmt);
2208 	if (!ps) {
2209 		if (!gda_mysql_provider_statement_prepare (provider, cnc, stmt, NULL)) {
2210 			/* this case can appear for example if some variables are used in places
2211 			 * where the C API cannot allow them (for example if the variable is the table name
2212 			 * in a SELECT statement). The action here is to get the actual SQL code for @stmt,
2213 			 * and use that SQL instead of @stmt to create another GdaMysqlPStmt object.
2214 			 */
2215 			gchar *sql = gda_mysql_provider_statement_to_sql (provider, cnc, stmt,
2216 									  params, GDA_STATEMENT_SQL_TIMEZONE_TO_GMT, NULL, error);
2217 			gboolean proto_error;
2218 			if (!sql)
2219 				return NULL;
2220 			ps = prepare_stmt_simple (cdata, sql, error, &proto_error);
2221 			if (!ps) {
2222 				if (proto_error) {
2223 					/* MySQL's "command is not supported in the prepared
2224 					 * statement protocol yet" error
2225 					 * => try to execute the SQL using mysql_real_query() */
2226 					GdaConnectionEvent *event;
2227 					if (mysql_real_query (cdata->mysql, sql, strlen (sql))) {
2228 						event = _gda_mysql_make_error (cnc, cdata->mysql, NULL, error);
2229 						gda_connection_add_event (cnc, event);
2230 						g_free (sql);
2231 						return NULL;
2232 					}
2233 
2234 					g_free (sql);
2235 					my_ulonglong affected_rows;
2236 					/* Create a #GdaSet containing "IMPACTED_ROWS" */
2237 					/* Create GdaConnectionEvent notice with the type of command and impacted rows */
2238 					affected_rows = mysql_affected_rows (cdata->mysql);
2239 					if (affected_rows == (my_ulonglong)~0) {
2240 						GdaDataModelAccessFlags flags;
2241 
2242 						if (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS)
2243 							flags = GDA_DATA_MODEL_ACCESS_RANDOM;
2244 						else
2245 							flags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD;
2246 						gda_connection_internal_statement_executed (cnc, stmt,
2247 											    NULL, NULL); /* required: help @cnc keep some stats */
2248 
2249 						return (GObject *) gda_mysql_recordset_new_direct (cnc,
2250 												   flags,
2251 												   col_types);
2252 					}
2253 					else {
2254 						gchar *str;
2255 						event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_NOTICE);
2256 						str = g_strdup_printf ("%llu", affected_rows);
2257 						gda_connection_event_set_description (event, str);
2258 						g_free (str);
2259 
2260 						gda_connection_internal_statement_executed (cnc, stmt, params, event); /* required: help @cnc keep some stats */
2261 						return (GObject *) gda_set_new_inline
2262 							(1, "IMPACTED_ROWS", G_TYPE_INT, (int) affected_rows);
2263 					}
2264 				}
2265 				else {
2266 					g_free (sql);
2267 					return NULL;
2268 				}
2269 			}
2270 			g_free (sql);
2271 		}
2272 		else {
2273 			ps = (GdaMysqlPStmt *) gda_connection_get_prepared_statement (cnc, stmt);
2274 			g_object_ref (ps);
2275 		}
2276 	}
2277 	else
2278 		g_object_ref (ps);
2279 
2280 	g_assert (ps);
2281 	if (ps->stmt_used) {
2282                 /* Don't use @ps => prepare stmt again */
2283                 GdaMysqlPStmt *nps;
2284                 nps = real_prepare (provider, cnc, stmt, error);
2285                 if (!nps)
2286                         return NULL;
2287                 //gda_pstmt_copy_contents ((GdaPStmt *) ps, (GdaPStmt *) nps);
2288 		g_object_unref (ps);
2289 		ps = nps;
2290 	}
2291 
2292 	/* bind statement's parameters */
2293 	GSList *list;
2294 	GdaConnectionEvent *event = NULL;
2295 	int i;
2296 
2297 	gint nb_params = g_slist_length (_GDA_PSTMT (ps)->param_ids);
2298 	/*g_print ("NB=%d, SQL=%s\n", nb_params, _GDA_PSTMT(ps)->sql);*/
2299 
2300 	MYSQL_BIND *mysql_bind_param = NULL;
2301 	GSList *mem_to_free = NULL;
2302 
2303 	if (nb_params > 0) {
2304 		mysql_bind_param = g_new0 (MYSQL_BIND, nb_params);
2305 		mem_to_free = g_slist_prepend (mem_to_free, mysql_bind_param);
2306 	}
2307 
2308 	for (i = 0, list = _GDA_PSTMT (ps)->param_ids; list; list = list->next, i++) {
2309 		const gchar *pname = (gchar *) list->data;
2310 
2311 		/* find requested parameter */
2312 		if (!params) {
2313 			event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
2314 			gda_connection_event_set_description (event, _("Missing parameter(s) to execute query"));
2315 			g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
2316 				     GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR,
2317 				     "%s", _("Missing parameter(s) to execute query"));
2318 			break;
2319 		}
2320 
2321 		GdaHolder *h = gda_set_get_holder (params, pname);
2322 		if (!h) {
2323 			gchar *tmp = gda_alphanum_to_text (g_strdup (pname + 1));
2324 			if (tmp) {
2325 				h = gda_set_get_holder (params, tmp);
2326 				g_free (tmp);
2327 			}
2328 		}
2329 		if (!h) {
2330 			if (allow_noparam) {
2331                                 /* bind param to NULL */
2332 				mysql_bind_param[i].buffer_type = MYSQL_TYPE_NULL;
2333 				mysql_bind_param[i].is_null = (my_bool*)1;
2334                                 empty_rs = TRUE;
2335                                 continue;
2336 			}
2337 			else {
2338 				gchar *str;
2339 				str = g_strdup_printf (_("Missing parameter '%s' to execute query"), pname);
2340 				event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
2341 				gda_connection_event_set_description (event, str);
2342 				g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
2343 					     GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, "%s", str);
2344 				g_free (str);
2345 				break;
2346 			}
2347 		}
2348 
2349 		if (!gda_holder_is_valid (h)) {
2350 			if (allow_noparam) {
2351                                 /* bind param to NULL */
2352 				mysql_bind_param[i].buffer_type = MYSQL_TYPE_NULL;
2353 				mysql_bind_param[i].is_null = (my_bool*)1;
2354                                 empty_rs = TRUE;
2355                                 continue;
2356 			}
2357 			else {
2358 				gchar *str;
2359 				str = g_strdup_printf (_("Parameter '%s' is invalid"), pname);
2360 				event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
2361 				gda_connection_event_set_description (event, str);
2362 				g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
2363 					     GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, "%s", str);
2364 				g_free (str);
2365 				break;
2366                         }
2367 		}
2368 		else if (gda_holder_value_is_default (h) && !gda_holder_get_value (h)) {
2369 			/* create a new GdaStatement to handle all default values and execute it instead */
2370 			GdaSqlStatement *sqlst;
2371 			GError *lerror = NULL;
2372 			sqlst = gda_statement_rewrite_for_default_values (stmt, params, FALSE, &lerror);
2373 			if (!sqlst) {
2374 				event = gda_connection_point_available_event (cnc,
2375 									      GDA_CONNECTION_EVENT_ERROR);
2376 				gda_connection_event_set_description (event, lerror && lerror->message ?
2377 								      lerror->message :
2378 								      _("Can't rewrite statement handle default values"));
2379 				g_propagate_error (error, lerror);
2380 				break;
2381 			}
2382 
2383 			GdaStatement *rstmt;
2384 			GObject *res;
2385 			rstmt = g_object_new (GDA_TYPE_STATEMENT, "structure", sqlst, NULL);
2386 			gda_sql_statement_free (sqlst);
2387 			free_bind_param_data (mem_to_free);
2388 			res = gda_mysql_provider_statement_execute (provider, cnc,
2389 								    rstmt, params,
2390 								    model_usage,
2391 								    col_types, last_inserted_row,
2392 								    task_id,
2393 								    async_cb, cb_data, error);
2394 			g_object_unref (rstmt);
2395 			return res;
2396 		}
2397 
2398 		/* actual binding using the C API, for parameter at position @i */
2399 		const GValue *value = gda_holder_get_value (h);
2400 
2401 		if (!value || gda_value_is_null (value)) {
2402 			GdaStatement *rstmt;
2403 			if (! gda_rewrite_statement_for_null_parameters (stmt, params, &rstmt, error)) {
2404 				mysql_bind_param[i].buffer_type = MYSQL_TYPE_NULL;
2405 				mysql_bind_param[i].is_null = (my_bool*)1;
2406 			}
2407 			else if (!rstmt)
2408 				return NULL;
2409 			else {
2410 				free_bind_param_data (mem_to_free);
2411 
2412 				/* The strategy here is to execute @rstmt using its prepared
2413 				 * statement, but with common data from @ps. Beware that
2414 				 * the @param_ids attribute needs to be retained (i.e. it must not
2415 				 * be the one copied from @ps) */
2416 				GObject *obj;
2417 				GdaMysqlPStmt *tps;
2418 				GdaPStmt *gtps;
2419 				GSList *prep_param_ids, *copied_param_ids;
2420 				if (!gda_mysql_provider_statement_prepare (provider, cnc,
2421 									   rstmt, error))
2422 					return NULL;
2423 				tps = (GdaMysqlPStmt *)
2424 					gda_connection_get_prepared_statement (cnc, rstmt);
2425 				gtps = (GdaPStmt *) tps;
2426 
2427 				/* keep @param_ids to avoid being cleared by gda_pstmt_copy_contents() */
2428 				prep_param_ids = gtps->param_ids;
2429 				gtps->param_ids = NULL;
2430 
2431 				/* actual copy */
2432 				gda_pstmt_copy_contents ((GdaPStmt *) ps, (GdaPStmt *) tps);
2433 
2434 				/* restore previous @param_ids */
2435 				copied_param_ids = gtps->param_ids;
2436 				gtps->param_ids = prep_param_ids;
2437 
2438 				/* execute */
2439 				obj = gda_mysql_provider_statement_execute (provider, cnc,
2440 									    rstmt, params,
2441 									    model_usage,
2442 									    col_types,
2443 									    last_inserted_row,
2444 									    task_id, async_cb,
2445 									    cb_data, error);
2446 				/* clear original @param_ids and restore copied one */
2447 				g_slist_foreach (prep_param_ids, (GFunc) g_free, NULL);
2448 				g_slist_free (prep_param_ids);
2449 
2450 				gtps->param_ids = copied_param_ids;
2451 
2452 				/*if (GDA_IS_DATA_MODEL (obj))
2453 				  gda_data_model_dump ((GdaDataModel*) obj, NULL);*/
2454 
2455 				g_object_unref (rstmt);
2456 				return obj;
2457 			}
2458 		}
2459 		else if (G_VALUE_TYPE (value) == GDA_TYPE_TIMESTAMP) {
2460 			GdaTimestamp *ts;
2461 
2462 			ts = (GdaTimestamp*) gda_value_get_timestamp (value);
2463 			if (!ts) {
2464 				mysql_bind_param[i].buffer_type = MYSQL_TYPE_NULL;
2465 				mysql_bind_param[i].is_null = (my_bool*)1;
2466 			}
2467 			else {
2468 				gboolean tofree = FALSE;
2469 				if (ts->timezone != GDA_TIMEZONE_INVALID) {
2470 					/* MySQL does not store timezone information, so if timezone information is
2471 					 * provided, we do our best and convert it to GMT */
2472 					ts = gda_timestamp_copy (ts);
2473 					tofree = TRUE;
2474 					gda_timestamp_change_timezone (ts, 0);
2475 				}
2476 
2477 				MYSQL_TIME *mtime;
2478 				mtime = g_new0 (MYSQL_TIME, 1);
2479 				mem_to_free = g_slist_prepend (mem_to_free, mtime);
2480 				mtime->year = ts->year;
2481 				mtime->month = ts->month;
2482 				mtime->day = ts->day;
2483 				mtime->hour = ts->hour;
2484 				mtime->minute = ts->minute;
2485 				mtime->second = ts->second;
2486 				mtime->second_part = ts->fraction;
2487 				if (tofree)
2488 					gda_timestamp_free (ts);
2489 
2490 				mysql_bind_param[i].buffer_type= MYSQL_TYPE_TIMESTAMP;
2491 				mysql_bind_param[i].buffer= (char *)mtime;
2492 				mysql_bind_param[i].buffer_length = sizeof (MYSQL_TIME);
2493 			}
2494 		}
2495 		else if (G_VALUE_TYPE (value) == GDA_TYPE_TIME) {
2496 			GdaTime *ts;
2497 
2498 			ts = (GdaTime*) gda_value_get_time (value);
2499 			if (!ts) {
2500 				mysql_bind_param[i].buffer_type = MYSQL_TYPE_NULL;
2501 				mysql_bind_param[i].is_null = (my_bool*)1;
2502 			}
2503 			else {
2504 				gboolean tofree = FALSE;
2505 				if (ts->timezone != GDA_TIMEZONE_INVALID) {
2506 					/* MySQL does not store timezone information, so if timezone information is
2507 					 * provided, we do our best and convert it to GMT */
2508 					ts = gda_time_copy (ts);
2509 					tofree = TRUE;
2510 					gda_time_change_timezone (ts, 0);
2511 				}
2512 
2513 				MYSQL_TIME *mtime;
2514 				mtime = g_new0 (MYSQL_TIME, 1);
2515 				mem_to_free = g_slist_prepend (mem_to_free, mtime);
2516 				mtime->hour = ts->hour;
2517 				mtime->minute = ts->minute;
2518 				mtime->second = ts->second;
2519 				mtime->second_part = ts->fraction;
2520 				if (tofree)
2521 					gda_time_free (ts);
2522 
2523 				mysql_bind_param[i].buffer_type= MYSQL_TYPE_TIME;
2524 				mysql_bind_param[i].buffer= (char *)mtime;
2525 				mysql_bind_param[i].buffer_length = sizeof (MYSQL_TIME);
2526 			}
2527 		}
2528 		else if (G_VALUE_TYPE (value) == G_TYPE_DATE) {
2529 			const GDate *ts;
2530 
2531 			ts = (GDate*) g_value_get_boxed (value);
2532 			if (!ts) {
2533 				mysql_bind_param[i].buffer_type = MYSQL_TYPE_NULL;
2534 				mysql_bind_param[i].is_null = (my_bool*)1;
2535 			}
2536 			else {
2537 				MYSQL_TIME *mtime;
2538 				mtime = g_new0 (MYSQL_TIME, 1);
2539 				mem_to_free = g_slist_prepend (mem_to_free, mtime);
2540 				mtime->year = g_date_get_year (ts);
2541 				mtime->month = g_date_get_month (ts);
2542 				mtime->day = g_date_get_day (ts);
2543 
2544 				mysql_bind_param[i].buffer_type= MYSQL_TYPE_DATE;
2545 				mysql_bind_param[i].buffer= (char *)mtime;
2546 				mysql_bind_param[i].buffer_length = sizeof (MYSQL_TIME);
2547 			}
2548 		}
2549 		else if (G_VALUE_TYPE (value) == G_TYPE_STRING) {
2550 			const gchar *str;
2551 			str = g_value_get_string (value);
2552 			if (!str) {
2553 				mysql_bind_param[i].buffer_type = MYSQL_TYPE_NULL;
2554 				mysql_bind_param[i].is_null = (my_bool*)1;
2555 			}
2556 			else {
2557 				mysql_bind_param[i].buffer_type= MYSQL_TYPE_STRING;
2558 				mysql_bind_param[i].buffer= (char *) str;
2559 				mysql_bind_param[i].buffer_length = strlen (str);
2560 				mysql_bind_param[i].length = NULL; /* str is 0 terminated */
2561 			}
2562 		}
2563 		else if (G_VALUE_TYPE (value) == G_TYPE_DOUBLE) {
2564 			gdouble *pv;
2565 			pv = g_new (gdouble, 1);
2566 			mem_to_free = g_slist_prepend (mem_to_free, pv);
2567 			*pv = g_value_get_double (value);
2568 			mysql_bind_param[i].buffer_type= MYSQL_TYPE_DOUBLE;
2569 			mysql_bind_param[i].buffer= pv;
2570 			mysql_bind_param[i].buffer_length = sizeof (gdouble);
2571 			mysql_bind_param[i].length = NULL;
2572 		}
2573 		else if (G_VALUE_TYPE (value) == G_TYPE_FLOAT) {
2574 			gfloat *pv;
2575 			pv = g_new (gfloat, 1);
2576 			mem_to_free = g_slist_prepend (mem_to_free, pv);
2577 			*pv = g_value_get_float (value);
2578 			mysql_bind_param[i].buffer_type= MYSQL_TYPE_FLOAT;
2579 			mysql_bind_param[i].buffer= pv;
2580 			mysql_bind_param[i].buffer_length = sizeof (gfloat);
2581 			mysql_bind_param[i].length = NULL;
2582 		}
2583 		else if (G_VALUE_TYPE (value) == G_TYPE_CHAR) {
2584 			gint8 *pv;
2585 			pv = g_new (gint8, 1);
2586 			*pv = g_value_get_schar (value);
2587 			mem_to_free = g_slist_prepend (mem_to_free, pv);
2588 			mysql_bind_param[i].buffer_type= MYSQL_TYPE_TINY;
2589 			mysql_bind_param[i].buffer = pv;
2590 			mysql_bind_param[i].buffer_length = sizeof (gchar);
2591 			mysql_bind_param[i].length = NULL;
2592 		}
2593 		else if (G_VALUE_TYPE (value) == GDA_TYPE_SHORT) {
2594 			gshort *pv;
2595 			pv = g_new (gshort, 1);
2596 			mem_to_free = g_slist_prepend (mem_to_free, pv);
2597 			*pv = gda_value_get_short (value);
2598 			mysql_bind_param[i].buffer_type= MYSQL_TYPE_SHORT;
2599 			mysql_bind_param[i].buffer= pv;
2600 			mysql_bind_param[i].buffer_length = sizeof (gshort);
2601 			mysql_bind_param[i].length = NULL;
2602 		}
2603 		else if (G_VALUE_TYPE (value) == G_TYPE_LONG) {
2604 			glong *pv;
2605 			pv = g_new (glong, 1);
2606 			mem_to_free = g_slist_prepend (mem_to_free, pv);
2607 			*pv = g_value_get_long (value);
2608 			mysql_bind_param[i].buffer_type= MYSQL_TYPE_LONG;
2609 			mysql_bind_param[i].buffer= pv;
2610 			mysql_bind_param[i].buffer_length = sizeof (glong);
2611 			mysql_bind_param[i].length = NULL;
2612 		}
2613 		else if (G_VALUE_TYPE (value) == G_TYPE_INT64) {
2614 			gint64 *pv;
2615 			pv = g_new (gint64, 1);
2616 			mem_to_free = g_slist_prepend (mem_to_free, pv);
2617 			*pv = g_value_get_long (value);
2618 			mysql_bind_param[i].buffer_type= MYSQL_TYPE_LONGLONG;
2619 			mysql_bind_param[i].buffer= pv;
2620 			mysql_bind_param[i].buffer_length = sizeof (gint64);
2621 			mysql_bind_param[i].length = NULL;
2622 		}
2623 		else if (G_VALUE_TYPE (value) == GDA_TYPE_BLOB) {
2624 			const GdaBinary *bin = NULL;
2625 			GdaBlob *blob = (GdaBlob*) gda_value_get_blob (value);
2626 
2627 			bin = ((GdaBinary*) blob);
2628 			if (!bin) {
2629 				mysql_bind_param[i].buffer_type = MYSQL_TYPE_NULL;
2630 				mysql_bind_param[i].is_null = (my_bool*)1;
2631 			}
2632 			else {
2633 				gchar *str = NULL;
2634 				glong blob_len;
2635 				if (blob->op) {
2636 					blob_len = gda_blob_op_get_length (blob->op);
2637 					if ((blob_len != bin->binary_length) &&
2638 					    ! gda_blob_op_read_all (blob->op, blob)) {
2639 						/* force reading the complete BLOB into memory */
2640 						str = _("Can't read whole BLOB into memory");
2641 					}
2642 				}
2643 				else
2644 					blob_len = bin->binary_length;
2645 				if (blob_len < 0)
2646 					str = _("Can't get BLOB's length");
2647 				else if (blob_len >= G_MAXINT)
2648 					str = _("BLOB is too big");
2649 
2650 				if (str) {
2651 					event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
2652 					gda_connection_event_set_description (event, str);
2653 					g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
2654 						     GDA_SERVER_PROVIDER_DATA_ERROR, "%s", str);
2655 					break;
2656 				}
2657 
2658 				else {
2659 					mysql_bind_param[i].buffer_type= MYSQL_TYPE_BLOB;
2660 					mysql_bind_param[i].buffer= (char *) bin->data;
2661 					mysql_bind_param[i].buffer_length = bin->binary_length;
2662 					mysql_bind_param[i].length = NULL;
2663 				}
2664 			}
2665 		}
2666 		else if (G_VALUE_TYPE (value) == GDA_TYPE_BINARY) {
2667 			const GdaBinary *bin;
2668 			bin = gda_value_get_binary (value);
2669 			if (!bin) {
2670 				mysql_bind_param[i].buffer_type = MYSQL_TYPE_NULL;
2671 				mysql_bind_param[i].is_null = (my_bool*)1;
2672 			}
2673 			else {
2674 				mysql_bind_param[i].buffer_type= MYSQL_TYPE_BLOB;
2675 				mysql_bind_param[i].buffer= (char *) bin->data;
2676 				mysql_bind_param[i].buffer_length = bin->binary_length;
2677 				mysql_bind_param[i].length = NULL;
2678 			}
2679 		}
2680 		else {
2681 			gchar *str = NULL;
2682 			GdaDataHandler *data_handler =
2683 				gda_server_provider_get_data_handler_g_type (provider, cnc,
2684 									     G_VALUE_TYPE (value));
2685 			if (data_handler == NULL) {
2686 				/* there is an error here */
2687 				str = g_strdup_printf(_("Unhandled data type '%s', please report this bug to "
2688 							"http://bugzilla.gnome.org/ for the \"libgda\" product."),
2689 						      gda_g_type_to_string (G_VALUE_TYPE (value)));
2690 				event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
2691 				gda_connection_event_set_description (event, str);
2692 				g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
2693 					     GDA_SERVER_PROVIDER_DATA_ERROR, "%s", str);
2694 				g_free (str);
2695 				break;
2696 			}
2697 			else {
2698 				str = gda_data_handler_get_str_from_value (data_handler, value);
2699 				mem_to_free = g_slist_prepend (mem_to_free, str);
2700 				mysql_bind_param[i].buffer_type = MYSQL_TYPE_STRING;
2701 				mysql_bind_param[i].buffer = str;
2702 				mysql_bind_param[i].buffer_length = strlen (str);
2703 				mysql_bind_param[i].length = NULL; /* str is 0 terminated */
2704 			}
2705 		}
2706 	}
2707 
2708 	if (!event && mysql_bind_param && mysql_stmt_bind_param (ps->mysql_stmt, mysql_bind_param)) {
2709 		//g_warning ("mysql_stmt_bind_param failed: %s\n", mysql_stmt_error (ps->mysql_stmt));
2710 		event = _gda_mysql_make_error (cnc, cdata->mysql, ps->mysql_stmt, error);
2711 	}
2712 
2713 	if (event) {
2714 		gda_connection_add_event (cnc, event);
2715 		g_object_unref (ps);
2716 		free_bind_param_data (mem_to_free);
2717 		return NULL;
2718 	}
2719 
2720 
2721 	/* use cursor when retrieving result */
2722 	if ((model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS) == 0 &&
2723 	    gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT) {
2724 #if MYSQL_VERSION_ID >= 50002
2725 		const unsigned long cursor_type = CURSOR_TYPE_READ_ONLY;
2726 		if (mysql_stmt_attr_set (ps->mysql_stmt, STMT_ATTR_CURSOR_TYPE, (void *) &cursor_type)) {
2727 			_gda_mysql_make_error (cnc, NULL, ps->mysql_stmt, NULL);
2728 			g_object_unref (ps);
2729 			free_bind_param_data (mem_to_free);
2730 			return NULL;
2731 		}
2732 #else
2733 		model_usage = GDA_STATEMENT_MODEL_RANDOM_ACCESS;
2734 		g_warning (_("Could not use CURSOR. Mysql version 5.0 at least is required. "
2735 			     "Using random access anyway."));
2736 #endif
2737 	}
2738 
2739 	/* add a connection event for the execution */
2740 	event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_COMMAND);
2741         gda_connection_event_set_description (event, _GDA_PSTMT (ps)->sql);
2742         gda_connection_add_event (cnc, event);
2743 
2744 	if (empty_rs) {
2745 		/* There are some missing parameters, so the SQL can't be executed but we still want
2746 		 * to execute something to get the columns correctly. A possibility is to actually
2747 		 * execute another SQL which is the code shown here.
2748 		 *
2749 		 * To adapt depending on the C API and its features */
2750 		GdaStatement *stmt_for_empty;
2751                 gchar *sql_for_empty;
2752                 stmt_for_empty = gda_select_alter_select_for_empty (stmt, error);
2753                 if (!stmt_for_empty) {
2754 			g_object_unref (ps);
2755 			free_bind_param_data (mem_to_free);
2756                         return NULL;
2757 		}
2758                 sql_for_empty = gda_statement_to_sql (stmt_for_empty, NULL, error);
2759                 g_object_unref (stmt_for_empty);
2760                 if (!sql_for_empty) {
2761 			g_object_unref (ps);
2762 			free_bind_param_data (mem_to_free);
2763                         return NULL;
2764 		}
2765 
2766 		/* This is a re-prepare of the statement.  The function mysql_stmt_prepare
2767 		 * will handle this on the server side. */
2768 		if (mysql_stmt_prepare (ps->mysql_stmt, sql_for_empty, strlen (sql_for_empty))) {
2769 			_gda_mysql_make_error (cdata->cnc, NULL, ps->mysql_stmt, error);
2770 			g_object_unref (ps);
2771 			free_bind_param_data (mem_to_free);
2772 			return NULL;
2773 		}
2774 
2775 		/* Execute the 'sql_for_empty' SQL code */
2776                 g_free (sql_for_empty);
2777 	}
2778 
2779 
2780 	GObject *return_value = NULL;
2781 	if (mysql_stmt_execute (ps->mysql_stmt)) {
2782 		event = _gda_mysql_make_error (cnc, NULL, ps->mysql_stmt, error);
2783 	}
2784 	else {
2785 		/* execute prepared statement using C API depending on its kind */
2786 		my_ulonglong affected_rows;
2787 		affected_rows = mysql_stmt_affected_rows (ps->mysql_stmt);
2788 		if ((affected_rows == (my_ulonglong)~0) ||
2789 		    !g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "SELECT", 6) ||
2790 		    !g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "SHOW", 4) ||
2791 		    !g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "DESCRIBE", 8) ||
2792 		    !g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "EXECUTE", 7) ||
2793 		    !g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "EXPLAIN", 7)) {
2794 			if (mysql_stmt_store_result (ps->mysql_stmt)) {
2795 				_gda_mysql_make_error (cnc, NULL, ps->mysql_stmt, error);
2796 			}
2797 			else {
2798 				GdaDataModelAccessFlags flags;
2799 
2800 				if (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS)
2801 					flags = GDA_DATA_MODEL_ACCESS_RANDOM;
2802 				else
2803 					flags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD;
2804 
2805 				return_value = (GObject *) gda_mysql_recordset_new (cnc, ps, params, flags, col_types);
2806 				gda_connection_internal_statement_executed (cnc, stmt, params, NULL); /* required: help @cnc keep some stats */
2807 			}
2808 		}
2809 		else {
2810 
2811 			/* Create a #GdaSet containing "IMPACTED_ROWS" */
2812 			/* Create GdaConnectionEvent notice with the type of command and impacted rows */
2813 			GdaConnectionEvent *event;
2814 			gchar *str;
2815 			event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_NOTICE);
2816 			str = g_strdup_printf ("%llu", affected_rows);
2817 			gda_connection_event_set_description (event, str);
2818 			g_free (str);
2819 
2820 			return_value = (GObject *) gda_set_new_inline
2821 				(1, "IMPACTED_ROWS", G_TYPE_INT, (int) affected_rows);
2822 
2823 			gda_connection_internal_statement_executed (cnc, stmt, params, event); /* required: help @cnc keep some stats */
2824 
2825 			if (last_inserted_row) {
2826 				my_ulonglong last_row;
2827 				last_row = mysql_insert_id (cdata->mysql);
2828 				if (last_row)
2829 					*last_inserted_row = make_last_inserted_set (cnc, stmt, last_row);
2830 			}
2831 
2832 		}
2833 	}
2834 	g_object_unref (ps);
2835 	free_bind_param_data (mem_to_free);
2836 	return return_value;
2837 }
2838 
2839 /*
2840  * Rewrites a statement in case some parameters in @params are set to DEFAULT, for INSERT or UPDATE statements
2841  */
2842 static GdaSqlStatement *
gda_mysql_statement_rewrite(GdaServerProvider * provider,GdaConnection * cnc,GdaStatement * stmt,GdaSet * params,GError ** error)2843 gda_mysql_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
2844 			     GdaStatement *stmt, GdaSet *params, GError **error)
2845 {
2846 	if (cnc) {
2847 		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
2848 		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
2849 	}
2850 	return gda_statement_rewrite_for_default_values (stmt, params, FALSE, error);
2851 }
2852 
2853 
2854 /*
2855  * starts a distributed transaction: put the XA transaction in the ACTIVE state
2856  */
2857 static gboolean
gda_mysql_provider_xa_start(GdaServerProvider * provider,GdaConnection * cnc,const GdaXaTransactionId * xid,G_GNUC_UNUSED GError ** error)2858 gda_mysql_provider_xa_start (GdaServerProvider         *provider,
2859 			     GdaConnection             *cnc,
2860 			     const GdaXaTransactionId  *xid,
2861 			     G_GNUC_UNUSED GError                   **error)
2862 {
2863 	MysqlConnectionData *cdata;
2864 
2865 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
2866 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
2867 	g_return_val_if_fail (xid, FALSE);
2868 
2869 	cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
2870 	if (!cdata)
2871 		return FALSE;
2872 
2873 	TO_IMPLEMENT;
2874 	return FALSE;
2875 }
2876 
2877 /*
2878  * put the XA transaction in the IDLE state: the connection won't accept any more modifications.
2879  * This state is required by some database providers before actually going to the PREPARED state
2880  */
2881 static gboolean
gda_mysql_provider_xa_end(GdaServerProvider * provider,GdaConnection * cnc,const GdaXaTransactionId * xid,G_GNUC_UNUSED GError ** error)2882 gda_mysql_provider_xa_end (GdaServerProvider         *provider,
2883 			   GdaConnection             *cnc,
2884 			   const GdaXaTransactionId  *xid,
2885 			   G_GNUC_UNUSED GError                   **error)
2886 {
2887 	MysqlConnectionData *cdata;
2888 
2889 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
2890 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
2891 	g_return_val_if_fail (xid, FALSE);
2892 
2893 	cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
2894 	if (!cdata)
2895 		return FALSE;
2896 
2897 	TO_IMPLEMENT;
2898 	return FALSE;
2899 }
2900 
2901 /*
2902  * prepares the distributed transaction: put the XA transaction in the PREPARED state
2903  */
2904 static gboolean
gda_mysql_provider_xa_prepare(GdaServerProvider * provider,GdaConnection * cnc,const GdaXaTransactionId * xid,G_GNUC_UNUSED GError ** error)2905 gda_mysql_provider_xa_prepare (GdaServerProvider         *provider,
2906 			       GdaConnection             *cnc,
2907 			       const GdaXaTransactionId  *xid,
2908 			       G_GNUC_UNUSED GError                   **error)
2909 {
2910 	MysqlConnectionData *cdata;
2911 
2912 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
2913 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
2914 	g_return_val_if_fail (xid, FALSE);
2915 
2916 	cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
2917 	if (!cdata)
2918 		return FALSE;
2919 
2920 	TO_IMPLEMENT;
2921 	return FALSE;
2922 }
2923 
2924 /*
2925  * commits the distributed transaction: actually write the prepared data to the database and
2926  * terminates the XA transaction
2927  */
2928 static gboolean
gda_mysql_provider_xa_commit(GdaServerProvider * provider,GdaConnection * cnc,const GdaXaTransactionId * xid,G_GNUC_UNUSED GError ** error)2929 gda_mysql_provider_xa_commit (GdaServerProvider         *provider,
2930 			      GdaConnection             *cnc,
2931 			      const GdaXaTransactionId  *xid,
2932 			      G_GNUC_UNUSED GError                   **error)
2933 {
2934 	MysqlConnectionData *cdata;
2935 
2936 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
2937 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
2938 	g_return_val_if_fail (xid, FALSE);
2939 
2940 	cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
2941 	if (!cdata)
2942 		return FALSE;
2943 
2944 	TO_IMPLEMENT;
2945 	return FALSE;
2946 }
2947 
2948 /*
2949  * Rolls back an XA transaction, possible only if in the ACTIVE, IDLE or PREPARED state
2950  */
2951 static gboolean
gda_mysql_provider_xa_rollback(GdaServerProvider * provider,GdaConnection * cnc,const GdaXaTransactionId * xid,G_GNUC_UNUSED GError ** error)2952 gda_mysql_provider_xa_rollback (GdaServerProvider         *provider,
2953 				GdaConnection             *cnc,
2954 				const GdaXaTransactionId  *xid,
2955 				G_GNUC_UNUSED GError                   **error)
2956 {
2957 	MysqlConnectionData *cdata;
2958 
2959 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
2960 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
2961 	g_return_val_if_fail (xid, FALSE);
2962 
2963 	cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
2964 	if (!cdata)
2965 		return FALSE;
2966 
2967 	TO_IMPLEMENT;
2968 	return FALSE;
2969 }
2970 
2971 /*
2972  * Lists all XA transactions that are in the PREPARED state
2973  *
2974  * Returns: a list of GdaXaTransactionId structures, which will be freed by the caller
2975  */
2976 static GList *
gda_mysql_provider_xa_recover(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED GError ** error)2977 gda_mysql_provider_xa_recover (GdaServerProvider  *provider,
2978 			       GdaConnection      *cnc,
2979 			       G_GNUC_UNUSED GError            **error)
2980 {
2981 	MysqlConnectionData *cdata;
2982 
2983 	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
2984 	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
2985 
2986 	cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
2987 	if (!cdata)
2988 		return NULL;
2989 
2990 	TO_IMPLEMENT;
2991 	return NULL;
2992 }
2993 
2994 static gchar *
identifier_add_quotes(const gchar * str)2995 identifier_add_quotes (const gchar *str)
2996 {
2997         gchar *retval, *rptr;
2998         const gchar *sptr;
2999         gint len;
3000 
3001         if (!str)
3002                 return NULL;
3003 
3004         len = strlen (str);
3005         retval = g_new (gchar, 2*len + 3);
3006         *retval = '`';
3007         for (rptr = retval+1, sptr = str; *sptr; sptr++, rptr++) {
3008                 if (*sptr == '`') {
3009                         *rptr = '\\';
3010                         rptr++;
3011                         *rptr = *sptr;
3012                 }
3013                 else
3014                         *rptr = *sptr;
3015         }
3016         *rptr = '`';
3017         rptr++;
3018         *rptr = 0;
3019         return retval;
3020 }
3021 
3022 static gboolean
_sql_identifier_needs_quotes(const gchar * str)3023 _sql_identifier_needs_quotes (const gchar *str)
3024 {
3025 	const gchar *ptr;
3026 
3027 	g_return_val_if_fail (str, FALSE);
3028 	for (ptr = str; *ptr; ptr++) {
3029 		/* quote if 1st char is a number */
3030 		if ((*ptr <= '9') && (*ptr >= '0')) {
3031 			if (ptr == str)
3032 				return TRUE;
3033 			continue;
3034 		}
3035 		if (((*ptr >= 'A') && (*ptr <= 'Z')) ||
3036 		    ((*ptr >= 'a') && (*ptr <= 'z')))
3037 			continue;
3038 
3039 		if ((*ptr != '$') && (*ptr != '_') && (*ptr != '#'))
3040 			return TRUE;
3041 	}
3042 	return FALSE;
3043 }
3044 
3045 /* Returns: @str */
3046 static gchar *
my_remove_quotes(gchar * str)3047 my_remove_quotes (gchar *str)
3048 {
3049         glong total;
3050         gchar *ptr;
3051         glong offset = 0;
3052 	char delim;
3053 
3054 	if (!str)
3055 		return NULL;
3056 	delim = *str;
3057 	if ((delim != '`') && (delim != '"'))
3058 		return str;
3059 
3060         total = strlen (str);
3061         if (str[total-1] == delim) {
3062 		/* string is correctly terminated */
3063 		memmove (str, str+1, total-2);
3064 		total -=2;
3065 	}
3066 	else {
3067 		/* string is _not_ correctly terminated */
3068 		memmove (str, str+1, total-1);
3069 		total -=1;
3070 	}
3071         str[total] = 0;
3072 
3073         ptr = (gchar *) str;
3074         while (offset < total) {
3075                 /* we accept the "''" as a synonym of "\'" */
3076                 if (*ptr == delim) {
3077                         if (*(ptr+1) == delim) {
3078                                 memmove (ptr+1, ptr+2, total - offset);
3079                                 offset += 2;
3080                         }
3081                         else {
3082                                 *str = 0;
3083                                 return str;
3084                         }
3085                 }
3086                 if (*ptr == '\\') {
3087                         if (*(ptr+1) == '\\') {
3088                                 memmove (ptr+1, ptr+2, total - offset);
3089                                 offset += 2;
3090                         }
3091                         else {
3092                                 if (*(ptr+1) == delim) {
3093                                         *ptr = delim;
3094                                         memmove (ptr+1, ptr+2, total - offset);
3095                                         offset += 2;
3096                                 }
3097                                 else {
3098                                         *str = 0;
3099                                         return str;
3100                                 }
3101                         }
3102                 }
3103                 else
3104                         offset ++;
3105 
3106                 ptr++;
3107         }
3108 
3109         return str;
3110 }
3111 
3112 static gchar *
gda_mysql_identifier_quote(GdaServerProvider * provider,GdaConnection * cnc,const gchar * id,gboolean for_meta_store,gboolean force_quotes)3113 gda_mysql_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
3114 			    const gchar *id,
3115 			    gboolean for_meta_store, gboolean force_quotes)
3116 {
3117 	GdaSqlReservedKeywordsFunc kwfunc;
3118 	MysqlConnectionData *cdata = NULL;
3119 	gboolean case_sensitive = TRUE;
3120 
3121 	if (cnc) {
3122 		cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
3123 		if (cdata)
3124 			case_sensitive = cdata->reuseable->identifiers_case_sensitive;
3125 	}
3126 	if (!cdata && ((GdaMysqlProvider*) provider)->test_mode)
3127 		case_sensitive = ((GdaMysqlProvider*) provider)->test_identifiers_case_sensitive;
3128 
3129 	kwfunc = _gda_mysql_reuseable_get_reserved_keywords_func
3130 		(cdata ? (GdaProviderReuseable*) cdata->reuseable : NULL);
3131 
3132 	if (case_sensitive) {
3133 		/*
3134 		 * case sensitive mode
3135 		 */
3136 		if (for_meta_store) {
3137 			gchar *tmp, *ptr;
3138 			tmp = my_remove_quotes (g_strdup (id));
3139 			if (kwfunc (tmp)) {
3140 				ptr = gda_sql_identifier_force_quotes (tmp);
3141 				g_free (tmp);
3142 				return ptr;
3143 			}
3144 			for (ptr = tmp; *ptr; ptr++) {
3145 				if (((*ptr >= 'a') && (*ptr <= 'z')) ||
3146 				    ((*ptr >= '0') && (*ptr <= '9') && (ptr != tmp)) ||
3147 				    (*ptr == '_'))
3148 					continue;
3149 				else {
3150 					ptr = gda_sql_identifier_force_quotes (tmp);
3151 					g_free (tmp);
3152 					return ptr;
3153 				}
3154 			}
3155 			return tmp;
3156 			/*			ptr = gda_sql_identifier_force_quotes (tmp);
3157 			g_free (tmp);
3158 			return ptr;*/
3159 		}
3160 		else {
3161 			if ((*id == '`') || (*id == '"'))  {
3162 				/* there are already some quotes */
3163 				gchar *ptr, *tmp = g_strdup (id);
3164 				for (ptr = tmp; *ptr; ptr++)
3165 					if (*ptr == '"')
3166 						*ptr = '`';
3167 				return tmp;
3168 			}
3169 			return identifier_add_quotes (id);
3170 		}
3171 	}
3172 	else {
3173 		/*
3174 		 * case insensitive mode
3175 		 */
3176 		if (for_meta_store) {
3177 			gchar *tmp, *ptr;
3178 			tmp = my_remove_quotes (g_strdup (id));
3179 			if (kwfunc (tmp)) {
3180 				ptr = gda_sql_identifier_force_quotes (tmp);
3181 				g_free (tmp);
3182 				return ptr;
3183 			}
3184 			else if (0 && force_quotes) {
3185 				/* quote if non LC characters or digits at the 1st char or non allowed characters */
3186 				for (ptr = tmp; *ptr; ptr++) {
3187 					if (((*ptr >= 'a') && (*ptr <= 'z')) ||
3188 					    ((*ptr >= '0') && (*ptr <= '9') && (ptr != tmp)) ||
3189 					    (*ptr == '_'))
3190 						continue;
3191 					else {
3192 						ptr = gda_sql_identifier_force_quotes (tmp);
3193 						g_free (tmp);
3194 						return ptr;
3195 					}
3196 				}
3197 				return tmp;
3198 			}
3199 			else {
3200 				for (ptr = tmp; *ptr; ptr++) {
3201 					if ((*ptr >= 'A') && (*ptr <= 'Z'))
3202 						*ptr += 'a' - 'A';
3203 					else if (((*ptr >= 'a') && (*ptr <= 'z')) ||
3204 					    ((*ptr >= '0') && (*ptr <= '9') && (ptr != tmp)) ||
3205 					    (*ptr == '_'))
3206 						continue;
3207 					else {
3208 						ptr = gda_sql_identifier_force_quotes (tmp);
3209 						g_free (tmp);
3210 						return ptr;
3211 					}
3212 				}
3213 				return tmp;
3214 			}
3215 		}
3216 		else {
3217 			if ((*id == '`') || (*id == '"'))  {
3218 				/* there are already some quotes */
3219 				gchar *ptr, *tmp = g_strdup (id);
3220 				for (ptr = tmp; *ptr; ptr++)
3221 					if (*ptr == '"')
3222 						*ptr = '`';
3223 				return tmp;
3224 			}
3225 			if (kwfunc (id) || _sql_identifier_needs_quotes (id) || force_quotes)
3226 				return identifier_add_quotes (id);
3227 
3228 			/* nothing to do */
3229 			return g_strdup (id);
3230 		}
3231 	}
3232 }
3233 
3234 /*
3235  * Free connection's specific data
3236  */
3237 static void
gda_mysql_free_cnc_data(MysqlConnectionData * cdata)3238 gda_mysql_free_cnc_data (MysqlConnectionData  *cdata)
3239 {
3240 	if (!cdata)
3241 		return;
3242 
3243 	if (cdata->mysql) {
3244 		mysql_close (cdata->mysql);
3245 		cdata->mysql = NULL;
3246 	}
3247 
3248 	if (cdata->reuseable) {
3249 		GdaProviderReuseable *rdata = (GdaProviderReuseable*)cdata->reuseable;
3250 		rdata->operations->re_reset_data (rdata);
3251 		g_free (cdata->reuseable);
3252 	}
3253 
3254 	g_free (cdata);
3255 }
3256