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 (®istering);
428 if (type == 0)
429 type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, "GdaMysqlProvider", &info, 0);
430 g_mutex_unlock (®istering);
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