1 /*
2 * Copyright (C) 2008 - 2011 Murray Cumming <murrayc@murrayc.com>
3 * Copyright (C) 2008 - 2013 Vivien Malerba <malerba@gnome-db.org>
4 * Copyright (C) 2009 Bas Driessen <bas.driessen@xobas.com>
5 * Copyright (C) 2010 David King <davidk@openismus.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <string.h>
27 #include <glib/gi18n-lib.h>
28 #include <glib/gstdio.h>
29 #include <libgda/libgda.h>
30 #include <libgda/gda-data-model-private.h>
31 #include <libgda/gda-server-provider-extra.h>
32 #include <libgda/binreloc/gda-binreloc.h>
33 #include <libgda/gda-statement-extra.h>
34 #include <sql-parser/gda-sql-parser.h>
35 #include "gda-jdbc.h"
36 #include "gda-jdbc-provider.h"
37 #include "gda-jdbc-recordset.h"
38 #include "gda-jdbc-ddl.h"
39 #include "gda-jdbc-meta.h"
40 #include "gda-jdbc-util.h"
41 #include "jni-wrapper.h"
42 #include "jni-globals.h"
43 #include "jdbc-resources.h"
44 #include <libgda/gda-debug-macros.h>
45
46 #define _GDA_PSTMT(x) ((GdaPStmt*)(x))
47
48 /*
49 * GObject methods
50 */
51 static void gda_jdbc_provider_class_init (GdaJdbcProviderClass *klass);
52 static void gda_jdbc_provider_init (GdaJdbcProvider *provider,
53 GdaJdbcProviderClass *klass);
54 static GObjectClass *parent_class = NULL;
55
56 /*
57 * GdaServerProvider's virtual methods
58 */
59 /* connection management */
60 static gboolean gda_jdbc_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
61 GdaQuarkList *params, GdaQuarkList *auth,
62 guint *task_id, GdaServerProviderAsyncCallback async_cb, gpointer cb_data);
63 static gboolean gda_jdbc_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc);
64 static const gchar *gda_jdbc_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc);
65
66 /* DDL operations */
67 static gboolean gda_jdbc_provider_supports_operation (GdaServerProvider *provider, GdaConnection *cnc,
68 GdaServerOperationType type, GdaSet *options);
69 static GdaServerOperation *gda_jdbc_provider_create_operation (GdaServerProvider *provider, GdaConnection *cnc,
70 GdaServerOperationType type,
71 GdaSet *options, GError **error);
72 static gchar *gda_jdbc_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc,
73 GdaServerOperation *op, GError **error);
74
75 static gboolean gda_jdbc_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
76 GdaServerOperation *op, guint *task_id,
77 GdaServerProviderAsyncCallback async_cb, gpointer cb_data,
78 GError **error);
79 /* transactions */
80 static gboolean gda_jdbc_provider_begin_transaction (GdaServerProvider *provider, GdaConnection *cnc,
81 const gchar *name, GdaTransactionIsolation level, GError **error);
82 static gboolean gda_jdbc_provider_commit_transaction (GdaServerProvider *provider, GdaConnection *cnc,
83 const gchar *name, GError **error);
84 static gboolean gda_jdbc_provider_rollback_transaction (GdaServerProvider *provider, GdaConnection * cnc,
85 const gchar *name, GError **error);
86 static gboolean gda_jdbc_provider_add_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
87 const gchar *name, GError **error);
88 static gboolean gda_jdbc_provider_rollback_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
89 const gchar *name, GError **error);
90 static gboolean gda_jdbc_provider_delete_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
91 const gchar *name, GError **error);
92
93 /* information retrieval */
94 static const gchar *gda_jdbc_provider_get_version (GdaServerProvider *provider);
95 static gboolean gda_jdbc_provider_supports_feature (GdaServerProvider *provider, GdaConnection *cnc,
96 GdaConnectionFeature feature);
97
98 static const gchar *gda_jdbc_provider_get_name (GdaServerProvider *provider);
99
100 static GdaDataHandler *gda_jdbc_provider_get_data_handler (GdaServerProvider *provider, GdaConnection *cnc,
101 GType g_type, const gchar *dbms_type);
102
103 static const gchar* gda_jdbc_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConnection *cnc,
104 GType type);
105 /* statements */
106 static gchar *gda_jdbc_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection *cnc,
107 GdaStatement *stmt, GdaSet *params,
108 GdaStatementSqlFlag flags,
109 GSList **params_used, GError **error);
110 static gboolean gda_jdbc_provider_statement_prepare (GdaServerProvider *provider, GdaConnection *cnc,
111 GdaStatement *stmt, GError **error);
112 static GObject *gda_jdbc_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
113 GdaStatement *stmt, GdaSet *params,
114 GdaStatementModelUsage model_usage,
115 GType *col_types, GdaSet **last_inserted_row,
116 guint *task_id, GdaServerProviderExecCallback async_cb,
117 gpointer cb_data, GError **error);
118 static GdaSqlStatement *gda_jdbc_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
119 GdaStatement *stmt, GdaSet *params, GError **error);
120
121
122 /* distributed transactions */
123 static gboolean gda_jdbc_provider_xa_start (GdaServerProvider *provider, GdaConnection *cnc,
124 const GdaXaTransactionId *xid, GError **error);
125
126 static gboolean gda_jdbc_provider_xa_end (GdaServerProvider *provider, GdaConnection *cnc,
127 const GdaXaTransactionId *xid, GError **error);
128 static gboolean gda_jdbc_provider_xa_prepare (GdaServerProvider *provider, GdaConnection *cnc,
129 const GdaXaTransactionId *xid, GError **error);
130
131 static gboolean gda_jdbc_provider_xa_commit (GdaServerProvider *provider, GdaConnection *cnc,
132 const GdaXaTransactionId *xid, GError **error);
133 static gboolean gda_jdbc_provider_xa_rollback (GdaServerProvider *provider, GdaConnection *cnc,
134 const GdaXaTransactionId *xid, GError **error);
135
136 static GList *gda_jdbc_provider_xa_recover (GdaServerProvider *provider, GdaConnection *cnc,
137 GError **error);
138
139 /*
140 * private connection data destroy
141 */
142 static void gda_jdbc_free_cnc_data (JdbcConnectionData *cdata);
143
144
145 /*
146 * Prepared internal statements
147 * TO_ADD: any prepared statement to be used internally by the provider should be
148 * declared here, as constants and as SQL statements
149 */
150 static GMutex init_mutex;
151 static GdaStatement **internal_stmt = NULL;
152
153 typedef enum {
154 INTERNAL_STMT1
155 } InternalStatementItem;
156
157 static gchar *internal_sql[] = {
158 "SQL for INTERNAL_STMT1"
159 };
160
161 /*
162 * GdaJdbcProvider class implementation
163 */
164 static void
gda_jdbc_provider_class_init(GdaJdbcProviderClass * klass)165 gda_jdbc_provider_class_init (GdaJdbcProviderClass *klass)
166 {
167 GdaServerProviderClass *provider_class = GDA_SERVER_PROVIDER_CLASS (klass);
168
169 parent_class = g_type_class_peek_parent (klass);
170
171 provider_class->get_version = gda_jdbc_provider_get_version;
172 provider_class->get_server_version = gda_jdbc_provider_get_server_version;
173 provider_class->get_name = gda_jdbc_provider_get_name;
174 provider_class->supports_feature = gda_jdbc_provider_supports_feature;
175
176 provider_class->get_data_handler = gda_jdbc_provider_get_data_handler;
177 provider_class->get_def_dbms_type = gda_jdbc_provider_get_default_dbms_type;
178
179 provider_class->open_connection = gda_jdbc_provider_open_connection;
180 provider_class->close_connection = gda_jdbc_provider_close_connection;
181 provider_class->get_database = NULL;
182
183 provider_class->supports_operation = gda_jdbc_provider_supports_operation;
184 provider_class->create_operation = gda_jdbc_provider_create_operation;
185 provider_class->render_operation = gda_jdbc_provider_render_operation;
186 provider_class->perform_operation = gda_jdbc_provider_perform_operation;
187
188 provider_class->begin_transaction = gda_jdbc_provider_begin_transaction;
189 provider_class->commit_transaction = gda_jdbc_provider_commit_transaction;
190 provider_class->rollback_transaction = gda_jdbc_provider_rollback_transaction;
191 provider_class->add_savepoint = gda_jdbc_provider_add_savepoint;
192 provider_class->rollback_savepoint = gda_jdbc_provider_rollback_savepoint;
193 provider_class->delete_savepoint = gda_jdbc_provider_delete_savepoint;
194
195 provider_class->create_parser = NULL;
196 provider_class->statement_to_sql = NULL; /* don't use gda_jdbc_provider_statement_to_sql()
197 * because it only calls gda_statement_to_sql_extended() */
198 provider_class->statement_prepare = gda_jdbc_provider_statement_prepare;
199 provider_class->statement_execute = gda_jdbc_provider_statement_execute;
200 provider_class->statement_rewrite = gda_jdbc_statement_rewrite;
201
202 provider_class->is_busy = NULL;
203 provider_class->cancel = NULL;
204 provider_class->create_connection = NULL;
205
206 memset (&(provider_class->meta_funcs), 0, sizeof (GdaServerProviderMeta));
207 provider_class->meta_funcs._info = _gda_jdbc_meta__info;
208 provider_class->meta_funcs._btypes = _gda_jdbc_meta__btypes;
209 provider_class->meta_funcs._udt = _gda_jdbc_meta__udt;
210 provider_class->meta_funcs.udt = _gda_jdbc_meta_udt;
211 provider_class->meta_funcs._udt_cols = _gda_jdbc_meta__udt_cols;
212 provider_class->meta_funcs.udt_cols = _gda_jdbc_meta_udt_cols;
213 provider_class->meta_funcs._enums = _gda_jdbc_meta__enums;
214 provider_class->meta_funcs.enums = _gda_jdbc_meta_enums;
215 provider_class->meta_funcs._domains = _gda_jdbc_meta__domains;
216 provider_class->meta_funcs.domains = _gda_jdbc_meta_domains;
217 provider_class->meta_funcs._constraints_dom = _gda_jdbc_meta__constraints_dom;
218 provider_class->meta_funcs.constraints_dom = _gda_jdbc_meta_constraints_dom;
219 provider_class->meta_funcs._el_types = _gda_jdbc_meta__el_types;
220 provider_class->meta_funcs.el_types = _gda_jdbc_meta_el_types;
221 provider_class->meta_funcs._collations = _gda_jdbc_meta__collations;
222 provider_class->meta_funcs.collations = _gda_jdbc_meta_collations;
223 provider_class->meta_funcs._character_sets = _gda_jdbc_meta__character_sets;
224 provider_class->meta_funcs.character_sets = _gda_jdbc_meta_character_sets;
225 provider_class->meta_funcs._schemata = _gda_jdbc_meta__schemata;
226 provider_class->meta_funcs.schemata = _gda_jdbc_meta_schemata;
227 provider_class->meta_funcs._tables_views = _gda_jdbc_meta__tables_views;
228 provider_class->meta_funcs.tables_views = _gda_jdbc_meta_tables_views;
229 provider_class->meta_funcs._columns = _gda_jdbc_meta__columns;
230 provider_class->meta_funcs.columns = _gda_jdbc_meta_columns;
231 provider_class->meta_funcs._view_cols = _gda_jdbc_meta__view_cols;
232 provider_class->meta_funcs.view_cols = _gda_jdbc_meta_view_cols;
233 provider_class->meta_funcs._constraints_tab = _gda_jdbc_meta__constraints_tab;
234 provider_class->meta_funcs.constraints_tab = _gda_jdbc_meta_constraints_tab;
235 provider_class->meta_funcs._constraints_ref = _gda_jdbc_meta__constraints_ref;
236 provider_class->meta_funcs.constraints_ref = _gda_jdbc_meta_constraints_ref;
237 provider_class->meta_funcs._key_columns = _gda_jdbc_meta__key_columns;
238 provider_class->meta_funcs.key_columns = _gda_jdbc_meta_key_columns;
239 provider_class->meta_funcs._check_columns = _gda_jdbc_meta__check_columns;
240 provider_class->meta_funcs.check_columns = _gda_jdbc_meta_check_columns;
241 provider_class->meta_funcs._triggers = _gda_jdbc_meta__triggers;
242 provider_class->meta_funcs.triggers = _gda_jdbc_meta_triggers;
243 provider_class->meta_funcs._routines = _gda_jdbc_meta__routines;
244 provider_class->meta_funcs.routines = _gda_jdbc_meta_routines;
245 provider_class->meta_funcs._routine_col = _gda_jdbc_meta__routine_col;
246 provider_class->meta_funcs.routine_col = _gda_jdbc_meta_routine_col;
247 provider_class->meta_funcs._routine_par = _gda_jdbc_meta__routine_par;
248 provider_class->meta_funcs.routine_par = _gda_jdbc_meta_routine_par;
249 provider_class->meta_funcs._indexes_tab = _gda_jdbc_meta__indexes_tab;
250 provider_class->meta_funcs.indexes_tab = _gda_jdbc_meta_indexes_tab;
251 provider_class->meta_funcs._index_cols = _gda_jdbc_meta__index_cols;
252 provider_class->meta_funcs.index_cols = _gda_jdbc_meta_index_cols;
253
254 /* distributed transactions: if not supported, then provider_class->xa_funcs should be set to NULL */
255 provider_class->xa_funcs = g_new0 (GdaServerProviderXa, 1);
256 provider_class->xa_funcs->xa_start = gda_jdbc_provider_xa_start;
257 provider_class->xa_funcs->xa_end = gda_jdbc_provider_xa_end;
258 provider_class->xa_funcs->xa_prepare = gda_jdbc_provider_xa_prepare;
259 provider_class->xa_funcs->xa_commit = gda_jdbc_provider_xa_commit;
260 provider_class->xa_funcs->xa_rollback = gda_jdbc_provider_xa_rollback;
261 provider_class->xa_funcs->xa_recover = gda_jdbc_provider_xa_recover;
262
263 /* not limiting to current thread */
264 provider_class->limiting_thread = NULL;
265 }
266
267 extern JavaVM *_jdbc_provider_java_vm;
268
269 static void
gda_jdbc_provider_init(GdaJdbcProvider * jdbc_prv,G_GNUC_UNUSED GdaJdbcProviderClass * klass)270 gda_jdbc_provider_init (GdaJdbcProvider *jdbc_prv, G_GNUC_UNUSED GdaJdbcProviderClass *klass)
271 {
272 g_mutex_lock (&init_mutex);
273
274 if (!internal_stmt) {
275 InternalStatementItem i;
276 GdaSqlParser *parser;
277
278 parser = gda_server_provider_internal_get_parser ((GdaServerProvider*) jdbc_prv);
279 internal_stmt = g_new0 (GdaStatement *, sizeof (internal_sql) / sizeof (gchar*));
280 for (i = INTERNAL_STMT1; i < sizeof (internal_sql) / sizeof (gchar*); i++) {
281 internal_stmt[i] = gda_sql_parser_parse_string (parser, internal_sql[i], NULL, NULL);
282 if (!internal_stmt[i])
283 g_error ("Could not parse internal statement: %s\n", internal_sql[i]);
284 }
285 }
286
287 /* meta data init */
288 _gda_jdbc_provider_meta_init ((GdaServerProvider*) jdbc_prv);
289
290 /* TO_ADD: any other provider's init should be added here */
291
292 g_mutex_unlock (&init_mutex);
293 }
294
295 GType
gda_jdbc_provider_get_type(void)296 gda_jdbc_provider_get_type (void)
297 {
298 static GType type = 0;
299
300 if (G_UNLIKELY (type == 0)) {
301 static GMutex registering;
302 static GTypeInfo info = {
303 sizeof (GdaJdbcProviderClass),
304 (GBaseInitFunc) NULL,
305 (GBaseFinalizeFunc) NULL,
306 (GClassInitFunc) gda_jdbc_provider_class_init,
307 NULL, NULL,
308 sizeof (GdaJdbcProvider),
309 0,
310 (GInstanceInitFunc) gda_jdbc_provider_init,
311 0
312 };
313 g_mutex_lock (®istering);
314 if (type == 0)
315 type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, "GdaJdbcProvider", &info, 0);
316 g_mutex_unlock (®istering);
317 }
318
319 return type;
320 }
321
322
323 /*
324 * Get provider name request
325 */
326 static const gchar *
gda_jdbc_provider_get_name(GdaServerProvider * provider)327 gda_jdbc_provider_get_name (GdaServerProvider *provider)
328 {
329 return GDA_JDBC_PROVIDER (provider)->jdbc_driver;
330 }
331
332 /*
333 * Get provider's version, no need to change this
334 */
335 static const gchar *
gda_jdbc_provider_get_version(G_GNUC_UNUSED GdaServerProvider * provider)336 gda_jdbc_provider_get_version (G_GNUC_UNUSED GdaServerProvider *provider)
337 {
338 return PACKAGE_VERSION;
339 }
340
341 /*
342 * make_url_from_params:
343 *
344 * Creates the URL to pass to the JDBC driver to open a connection. It uses the
345 * jdbc_mappings.xml file
346 *
347 * Returns: a new string, or %NULL if not enough information found to create the connection URL
348 */
349 static gchar *
make_url_from_params(GdaServerProvider * provider,GdaConnection * cnc,GdaQuarkList * params,G_GNUC_UNUSED GdaQuarkList * auth)350 make_url_from_params (GdaServerProvider *provider, GdaConnection *cnc,
351 GdaQuarkList *params, G_GNUC_UNUSED GdaQuarkList *auth)
352 {
353 GBytes *data;
354 const gchar *xmlstr;
355 gsize data_size = 0;
356 _jdbc_register_resource ();
357 data = g_resources_lookup_data ("/jdbc/jdbc-mappings.xml", G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
358 g_assert (data);
359 xmlstr = g_bytes_get_data (data, &data_size);
360
361 xmlDocPtr doc;
362 doc = xmlParseMemory (xmlstr, data_size);
363 g_bytes_unref (data);
364 _jdbc_unregister_resource ();
365
366 if (!doc)
367 return NULL;
368
369 xmlNodePtr root, node;
370 GString *url = NULL;
371 root = xmlDocGetRootElement (doc);
372 if (strcmp ((gchar*) root->name, "jdbc-mappings"))
373 goto out;
374
375 for (node = root->children; node; node = node->next) {
376 if (strcmp ((gchar *) node->name, "driver"))
377 continue;
378 xmlChar *prop;
379 prop = xmlGetProp (node, BAD_CAST "name");
380 if (!prop)
381 continue;
382 if (!strcmp ((gchar*) prop, gda_server_provider_get_name (provider))) {
383 xmlFree (prop);
384 break;
385 }
386 xmlFree (prop);
387 }
388 if (!node)
389 goto out;
390
391 url = g_string_new ("");
392 for (node = node->children; node; node = node->next) {
393 if (!strcmp ((gchar *) node->name, "prefix")) {
394 xmlChar *contents;
395 contents = xmlNodeGetContent (node);
396 if (contents && *contents)
397 g_string_append (url, (gchar*) contents);
398 }
399 else if (!strcmp ((gchar *) node->name, "part")) {
400 xmlChar *prop;
401 const gchar *cvarvalue = NULL;
402 gchar *varvalue = NULL;
403 gboolean opt = FALSE;
404 prop = xmlGetProp (node, BAD_CAST "variable");
405 if (prop) {
406 cvarvalue = gda_quark_list_find (params, (gchar*) prop);
407 xmlFree (prop);
408 }
409 prop = xmlGetProp (node, BAD_CAST "optional");
410 if (prop) {
411 if ((*prop == 't') || (*prop == 'T'))
412 opt = TRUE;
413 xmlFree (prop);
414 }
415
416 prop = xmlGetProp (node, BAD_CAST "if");
417 if (prop) {
418 if (!strcmp ((gchar*) prop, "CncReadOnly")) {
419 if (gda_connection_get_options (cnc) & GDA_CONNECTION_OPTIONS_READ_ONLY) {
420 xmlFree (prop);
421 prop = xmlGetProp (node, BAD_CAST "value");
422 if (prop)
423 varvalue = g_strdup ((gchar*) prop);
424 }
425 }
426 if (prop)
427 xmlFree (prop);
428 }
429
430 if (cvarvalue || varvalue) {
431 prop = xmlGetProp (node, BAD_CAST "prefix");
432 if (prop) {
433 g_string_append (url, (gchar*) prop);
434 xmlFree (prop);
435 }
436 g_string_append (url, varvalue ? varvalue : cvarvalue);
437 g_free (varvalue);
438 }
439 else if (!varvalue && !cvarvalue && !opt) {
440 /* missing parameter */
441 g_string_free (url, TRUE);
442 url = NULL;
443 goto out;
444 }
445 }
446 }
447
448 out:
449 xmlFreeDoc (doc);
450 if (url)
451 return g_string_free (url, FALSE);
452 else
453 return NULL;
454 }
455
456 /*
457 * Open connection request
458 *
459 * In this function, the following _must_ be done:
460 * - check for the presence and validify of the parameters required to actually open a connection,
461 * using @params
462 * - open the real connection to the database using the parameters previously checked
463 * - create a JdbcConnectionData structure and associate it to @cnc
464 *
465 * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR gonnection event must be added to @cnc)
466 */
467 static gboolean
gda_jdbc_provider_open_connection(GdaServerProvider * provider,GdaConnection * cnc,GdaQuarkList * params,GdaQuarkList * auth,G_GNUC_UNUSED guint * task_id,GdaServerProviderAsyncCallback async_cb,G_GNUC_UNUSED gpointer cb_data)468 gda_jdbc_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
469 GdaQuarkList *params, GdaQuarkList *auth,
470 G_GNUC_UNUSED guint *task_id, GdaServerProviderAsyncCallback async_cb,
471 G_GNUC_UNUSED gpointer cb_data)
472 {
473 GdaJdbcProvider *jprov;
474 g_return_val_if_fail (GDA_IS_JDBC_PROVIDER (provider), FALSE);
475 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
476 jprov = (GdaJdbcProvider*) provider;
477
478 /* If asynchronous connection opening is not supported, then exit now */
479 if (async_cb) {
480 gda_connection_add_event_string (cnc, _("Provider does not support asynchronous connection open"));
481 return FALSE;
482 }
483
484 /* Check for connection parameters */
485 gchar *url;
486 const gchar *cstr;
487 cstr = gda_quark_list_find (params, "URL");
488 if (cstr)
489 url = g_strdup (cstr);
490 else {
491 url = make_url_from_params (provider, cnc, params, auth);
492 if (!url) {
493 gda_connection_add_event_string (cnc,
494 _("Missing parameters to open database connection"));
495 return FALSE;
496 }
497 }
498
499 /* Check for username / password */
500 const gchar *username = NULL, *password = NULL;
501 if (auth) {
502 username = gda_quark_list_find (auth, "USERNAME");
503 password = gda_quark_list_find (auth, "PASSWORD");
504 }
505
506 /* open the real connection to the database */
507 g_assert (jprov->jprov_obj);
508 GValue *obj_value;
509 jstring jstr, jstr1, jstr2;
510 JNIEnv *env;
511 GError *error = NULL;
512 gint error_code;
513 gchar *sql_state;
514 gboolean jni_detach;
515
516 env = _gda_jdbc_get_jenv (&jni_detach, &error);
517
518 if (!env) {
519 gda_connection_add_event_string (cnc, "%s",
520 error && error->message ? error->message : _("No detail"));
521 if (error)
522 g_error_free (error);
523 g_free (url);
524 return FALSE;
525 }
526
527 jstr = (*env)->NewStringUTF (env, url);
528 /*g_print ("URL = [%s] USERNAME = [%s] PASSWORD = [%s]\n", url, username, password);*/
529 g_free (url);
530 url = NULL;
531 if (username)
532 jstr1 = (*env)->NewStringUTF (env, username);
533 else
534 jstr1 = NULL;
535 if (password)
536 jstr2 = (*env)->NewStringUTF (env, password);
537 else
538 jstr2 = NULL;
539
540 obj_value = jni_wrapper_method_call (env, GdaJProvider__openConnection,
541 jprov->jprov_obj, &error_code, &sql_state, &error,
542 jstr, jstr1, jstr2);
543 (*env)->DeleteLocalRef(env, jstr);
544 if (jstr1)
545 (*env)->DeleteLocalRef(env, jstr1);
546 if (jstr2)
547 (*env)->DeleteLocalRef(env, jstr2);
548
549 if (!obj_value) {
550 _gda_jdbc_make_error (cnc, error_code, sql_state, error);
551 _gda_jdbc_release_jenv (jni_detach);
552 return FALSE;
553 }
554
555 /* Create a new instance of the provider specific data associated to a connection (JdbcConnectionData),
556 * and set its contents */
557 JdbcConnectionData *cdata;
558 cdata = g_new0 (JdbcConnectionData, 1);
559 gda_connection_internal_set_provider_data (cnc, cdata, (GDestroyNotify) gda_jdbc_free_cnc_data);
560 cdata->jcnc_obj = obj_value;
561
562 _gda_jdbc_release_jenv (jni_detach);
563 return TRUE;
564 }
565
566 /*
567 * Close connection request
568 *
569 * In this function, the following _must_ be done:
570 * - Actually close the connection to the database using @cnc's associated JdbcConnectionData structure
571 * - Free the JdbcConnectionData structure and its contents
572 *
573 * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR gonnection event must be added to @cnc)
574 */
575 static gboolean
gda_jdbc_provider_close_connection(GdaServerProvider * provider,GdaConnection * cnc)576 gda_jdbc_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc)
577 {
578 JdbcConnectionData *cdata;
579
580 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
581 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
582
583 /* Close the connection using the C API */
584 cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
585 if (!cdata)
586 return FALSE;
587
588 /* Free the JdbcConnectionData structure and its contents */
589 gda_jdbc_free_cnc_data (cdata);
590 gda_connection_internal_set_provider_data (cnc, NULL, NULL);
591
592 return TRUE;
593 }
594
595 /*
596 * Server version request
597 *
598 * Returns the server version as a string
599 */
600 static const gchar *
gda_jdbc_provider_get_server_version(GdaServerProvider * provider,GdaConnection * cnc)601 gda_jdbc_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc)
602 {
603 JdbcConnectionData *cdata;
604
605 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
606 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
607
608 cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
609 if (!cdata)
610 return FALSE;
611
612 if (! cdata->server_version && cdata->jcnc_obj) {
613 JNIEnv *jenv = NULL;
614 gboolean jni_detach;
615 GError *error = NULL;
616
617 jenv = _gda_jdbc_get_jenv (&jni_detach, &error);
618 if (!jenv) {
619 g_warning ("%s", error->message);
620 g_error_free (error);
621 }
622 else {
623 GValue *res;
624 res = jni_wrapper_method_call (jenv, GdaJConnection__getServerVersion,
625 cdata->jcnc_obj, NULL, NULL, NULL);
626 if (res) {
627 cdata->server_version = g_value_dup_string (res);
628 gda_value_free (res);
629 }
630 _gda_jdbc_release_jenv (jni_detach);
631 }
632 }
633
634 return cdata->server_version;
635 }
636
637 /*
638 * Support operation request
639 *
640 * Tells what the implemented server operations are. To add support for an operation, the following steps are required:
641 * - create a jdbc_specs_....xml.in file describing the required and optional parameters for the operation
642 * - add it to the Makefile.am
643 * - make this method return TRUE for the operation type
644 * - implement the gda_jdbc_provider_render_operation() and gda_jdbc_provider_perform_operation() methods
645 *
646 */
647 static gboolean
gda_jdbc_provider_supports_operation(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED GdaServerOperationType type,G_GNUC_UNUSED GdaSet * options)648 gda_jdbc_provider_supports_operation (GdaServerProvider *provider, GdaConnection *cnc,
649 G_GNUC_UNUSED GdaServerOperationType type,
650 G_GNUC_UNUSED GdaSet *options)
651 {
652 if (cnc) {
653 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
654 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
655 }
656
657 /* use native provider for help */
658 TO_IMPLEMENT;
659
660 return FALSE;
661 }
662
663 /*
664 * Create operation request
665 *
666 * Creates a #GdaServerOperation. The following code is generic and should only be changed
667 * if some further initialization is required, or if operation's contents is dependent on @cnc
668 */
669 static GdaServerOperation *
gda_jdbc_provider_create_operation(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED GdaServerOperationType type,G_GNUC_UNUSED GdaSet * options,G_GNUC_UNUSED GError ** error)670 gda_jdbc_provider_create_operation (GdaServerProvider *provider, GdaConnection *cnc,
671 G_GNUC_UNUSED GdaServerOperationType type, G_GNUC_UNUSED GdaSet *options,
672 G_GNUC_UNUSED GError **error)
673 {
674 if (cnc) {
675 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
676 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
677 }
678
679 /* use native provider for help */
680 TO_IMPLEMENT;
681
682 return NULL;
683 }
684
685 /*
686 * Render operation request
687 */
688 static gchar *
gda_jdbc_provider_render_operation(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED GdaServerOperation * op,G_GNUC_UNUSED GError ** error)689 gda_jdbc_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc,
690 G_GNUC_UNUSED GdaServerOperation *op, G_GNUC_UNUSED GError **error)
691 {
692 if (cnc) {
693 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
694 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
695 }
696
697 /* use native provider for help */
698 TO_IMPLEMENT;
699
700 return NULL;
701 }
702
703 /*
704 * Perform operation request
705 */
706 static gboolean
gda_jdbc_provider_perform_operation(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED GdaServerOperation * op,G_GNUC_UNUSED guint * task_id,GdaServerProviderAsyncCallback async_cb,G_GNUC_UNUSED gpointer cb_data,GError ** error)707 gda_jdbc_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
708 G_GNUC_UNUSED GdaServerOperation *op, G_GNUC_UNUSED guint *task_id,
709 GdaServerProviderAsyncCallback async_cb, G_GNUC_UNUSED gpointer cb_data,
710 GError **error)
711 {
712 /* If asynchronous connection opening is not supported, then exit now */
713 if (async_cb) {
714 g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
715 "%s", _("Provider does not support asynchronous server operation"));
716 return FALSE;
717 }
718
719 if (cnc) {
720 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
721 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
722 }
723
724 /* use native provider for help */
725 TO_IMPLEMENT;
726 return FALSE;
727 }
728
729 /*
730 * Begin transaction request
731 */
732 static gboolean
gda_jdbc_provider_begin_transaction(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED const gchar * name,G_GNUC_UNUSED GdaTransactionIsolation level,GError ** error)733 gda_jdbc_provider_begin_transaction (GdaServerProvider *provider, GdaConnection *cnc,
734 G_GNUC_UNUSED const gchar *name,
735 G_GNUC_UNUSED GdaTransactionIsolation level, GError **error)
736 {
737 JdbcConnectionData *cdata;
738 GValue *jexec_res;
739 GError *lerror = NULL;
740 JNIEnv *jenv = NULL;
741 gboolean jni_detach;
742 gint error_code;
743 gchar *sql_state;
744
745 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
746 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
747
748 cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
749 if (!cdata)
750 return FALSE;
751
752 jenv = _gda_jdbc_get_jenv (&jni_detach, error);
753 if (!jenv)
754 return FALSE;
755
756 jexec_res = jni_wrapper_method_call (jenv, GdaJConnection__begin,
757 cdata->jcnc_obj, &error_code, &sql_state, &lerror);
758 if (!jexec_res) {
759 if (error && lerror)
760 *error = g_error_copy (lerror);
761 _gda_jdbc_make_error (cnc, error_code, sql_state, lerror);
762 _gda_jdbc_release_jenv (jni_detach);
763 return FALSE;
764 }
765 gda_value_free (jexec_res);
766 _gda_jdbc_release_jenv (jni_detach);
767
768 return TRUE;
769 }
770
771 /*
772 * Commit transaction request
773 */
774 static gboolean
gda_jdbc_provider_commit_transaction(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED const gchar * name,GError ** error)775 gda_jdbc_provider_commit_transaction (GdaServerProvider *provider, GdaConnection *cnc,
776 G_GNUC_UNUSED const gchar *name, GError **error)
777 {
778 JdbcConnectionData *cdata;
779 GValue *jexec_res;
780 GError *lerror = NULL;
781 JNIEnv *jenv = NULL;
782 gboolean jni_detach;
783 gint error_code;
784 gchar *sql_state;
785
786 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
787 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
788
789 cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
790 if (!cdata)
791 return FALSE;
792
793 jenv = _gda_jdbc_get_jenv (&jni_detach, error);
794 if (!jenv)
795 return FALSE;
796
797 jexec_res = jni_wrapper_method_call (jenv, GdaJConnection__commit,
798 cdata->jcnc_obj, &error_code, &sql_state, &lerror);
799 if (!jexec_res) {
800 if (error && lerror)
801 *error = g_error_copy (lerror);
802 _gda_jdbc_make_error (cnc, error_code, sql_state, lerror);
803 _gda_jdbc_release_jenv (jni_detach);
804 return FALSE;
805 }
806 gda_value_free (jexec_res);
807 _gda_jdbc_release_jenv (jni_detach);
808
809 return TRUE;
810 }
811
812 /*
813 * Rollback transaction request
814 */
815 static gboolean
gda_jdbc_provider_rollback_transaction(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED const gchar * name,GError ** error)816 gda_jdbc_provider_rollback_transaction (GdaServerProvider *provider, GdaConnection *cnc,
817 G_GNUC_UNUSED const gchar *name, GError **error)
818 {
819 JdbcConnectionData *cdata;
820 GValue *jexec_res;
821 GError *lerror = NULL;
822 JNIEnv *jenv = NULL;
823 gboolean jni_detach;
824 gint error_code;
825 gchar *sql_state;
826
827 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
828 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
829
830 cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
831 if (!cdata)
832 return FALSE;
833
834 jenv = _gda_jdbc_get_jenv (&jni_detach, error);
835 if (!jenv)
836 return FALSE;
837
838 jexec_res = jni_wrapper_method_call (jenv, GdaJConnection__rollback,
839 cdata->jcnc_obj, &error_code, &sql_state, &lerror);
840 if (!jexec_res) {
841 if (error && lerror)
842 *error = g_error_copy (lerror);
843 _gda_jdbc_make_error (cnc, error_code, sql_state, lerror);
844 _gda_jdbc_release_jenv (jni_detach);
845 return FALSE;
846 }
847 gda_value_free (jexec_res);
848 _gda_jdbc_release_jenv (jni_detach);
849
850 return TRUE;
851 }
852
853 /*
854 * Add savepoint request
855 */
856 static gboolean
gda_jdbc_provider_add_savepoint(GdaServerProvider * provider,GdaConnection * cnc,const gchar * name,GError ** error)857 gda_jdbc_provider_add_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
858 const gchar *name, GError **error)
859 {
860 JdbcConnectionData *cdata;
861 GValue *jexec_res;
862 GError *lerror = NULL;
863 JNIEnv *jenv = NULL;
864 gboolean jni_detach;
865 gint error_code;
866 gchar *sql_state;
867 jstring jname;
868
869 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
870 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
871
872 cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
873 if (!cdata)
874 return FALSE;
875
876 jenv = _gda_jdbc_get_jenv (&jni_detach, error);
877 if (!jenv)
878 return FALSE;
879
880 if (name)
881 jname = (*jenv)->NewStringUTF (jenv, name);
882 else
883 jname = (*jenv)->NewStringUTF (jenv, "");
884 if ((*jenv)->ExceptionCheck (jenv)) {
885 _gda_jdbc_release_jenv (jni_detach);
886 return FALSE;
887 }
888
889 jexec_res = jni_wrapper_method_call (jenv, GdaJConnection__addSavepoint,
890 cdata->jcnc_obj, &error_code, &sql_state, &lerror, jname);
891 (*jenv)->DeleteLocalRef (jenv, jname);
892 if (!jexec_res) {
893 if (error && lerror)
894 *error = g_error_copy (lerror);
895 _gda_jdbc_make_error (cnc, error_code, sql_state, lerror);
896 _gda_jdbc_release_jenv (jni_detach);
897 return FALSE;
898 }
899 gda_value_free (jexec_res);
900 _gda_jdbc_release_jenv (jni_detach);
901
902 return TRUE;
903 }
904
905 /*
906 * Rollback savepoint request
907 */
908 static gboolean
gda_jdbc_provider_rollback_savepoint(GdaServerProvider * provider,GdaConnection * cnc,const gchar * name,GError ** error)909 gda_jdbc_provider_rollback_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
910 const gchar *name, GError **error)
911 {
912 JdbcConnectionData *cdata;
913 GValue *jexec_res;
914 GError *lerror = NULL;
915 JNIEnv *jenv = NULL;
916 gboolean jni_detach;
917 gint error_code;
918 gchar *sql_state;
919 jstring jname;
920
921 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
922 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
923
924 cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
925 if (!cdata)
926 return FALSE;
927
928 jenv = _gda_jdbc_get_jenv (&jni_detach, error);
929 if (!jenv)
930 return FALSE;
931
932 if (name)
933 jname = (*jenv)->NewStringUTF (jenv, name);
934 else
935 jname = (*jenv)->NewStringUTF (jenv, "");
936 if ((*jenv)->ExceptionCheck (jenv)) {
937 _gda_jdbc_release_jenv (jni_detach);
938 return FALSE;
939 }
940
941 jexec_res = jni_wrapper_method_call (jenv, GdaJConnection__rollbackSavepoint,
942 cdata->jcnc_obj, &error_code, &sql_state, &lerror, jname);
943 (*jenv)->DeleteLocalRef (jenv, jname);
944 if (!jexec_res) {
945 if (error && lerror)
946 *error = g_error_copy (lerror);
947 _gda_jdbc_make_error (cnc, error_code, sql_state, lerror);
948 _gda_jdbc_release_jenv (jni_detach);
949 return FALSE;
950 }
951 gda_value_free (jexec_res);
952 _gda_jdbc_release_jenv (jni_detach);
953
954 return TRUE;
955 }
956
957 /*
958 * Delete savepoint request
959 */
960 static gboolean
gda_jdbc_provider_delete_savepoint(GdaServerProvider * provider,GdaConnection * cnc,const gchar * name,GError ** error)961 gda_jdbc_provider_delete_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
962 const gchar *name, GError **error)
963 {
964 JdbcConnectionData *cdata;
965 GValue *jexec_res;
966 GError *lerror = NULL;
967 JNIEnv *jenv = NULL;
968 gboolean jni_detach;
969 gint error_code;
970 gchar *sql_state;
971 jstring jname;
972
973 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
974 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
975
976 cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
977 if (!cdata)
978 return FALSE;
979
980 jenv = _gda_jdbc_get_jenv (&jni_detach, error);
981 if (!jenv)
982 return FALSE;
983
984 if (name)
985 jname = (*jenv)->NewStringUTF (jenv, name);
986 else
987 jname = (*jenv)->NewStringUTF (jenv, "");
988 if ((*jenv)->ExceptionCheck (jenv)) {
989 _gda_jdbc_release_jenv (jni_detach);
990 return FALSE;
991 }
992
993 jexec_res = jni_wrapper_method_call (jenv, GdaJConnection__releaseSavepoint,
994 cdata->jcnc_obj, &error_code, &sql_state, &lerror, jname);
995 (*jenv)->DeleteLocalRef (jenv, jname);
996 if (!jexec_res) {
997 if (error && lerror)
998 *error = g_error_copy (lerror);
999 _gda_jdbc_make_error (cnc, error_code, sql_state, lerror);
1000 _gda_jdbc_release_jenv (jni_detach);
1001 return FALSE;
1002 }
1003 gda_value_free (jexec_res);
1004 _gda_jdbc_release_jenv (jni_detach);
1005
1006 return TRUE;
1007 }
1008
1009 /*
1010 * Feature support request
1011 */
1012 static gboolean
gda_jdbc_provider_supports_feature(GdaServerProvider * provider,GdaConnection * cnc,GdaConnectionFeature feature)1013 gda_jdbc_provider_supports_feature (GdaServerProvider *provider, GdaConnection *cnc, GdaConnectionFeature feature)
1014 {
1015 if (cnc) {
1016 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1017 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1018 }
1019
1020 switch (feature) {
1021 case GDA_CONNECTION_FEATURE_SQL :
1022 return TRUE;
1023 default:
1024 return FALSE;
1025 }
1026 }
1027
1028 /*
1029 * Get data handler request
1030 *
1031 * This method allows one to obtain a pointer to a #GdaDataHandler object specific to @type or @dbms_type (@dbms_type
1032 * must be considered only if @type is not a valid GType).
1033 *
1034 * A data handler allows one to convert a value between its different representations which are a human readable string,
1035 * an SQL representation and a GValue.
1036 *
1037 * The recommended method is to create GdaDataHandler objects only when they are needed and to keep a reference to them
1038 * for further usage, using the gda_server_provider_handler_declare() method.
1039 *
1040 * The implementation shown here does not define any specific data handler, but there should be some for at least
1041 * binary and time related types.
1042 */
1043 static GdaDataHandler *
gda_jdbc_provider_get_data_handler(GdaServerProvider * provider,GdaConnection * cnc,GType type,const gchar * dbms_type)1044 gda_jdbc_provider_get_data_handler (GdaServerProvider *provider, GdaConnection *cnc,
1045 GType type, const gchar *dbms_type)
1046 {
1047 GdaDataHandler *dh;
1048 if (cnc) {
1049 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1050 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1051 }
1052
1053 if (type == G_TYPE_INVALID) {
1054 TO_IMPLEMENT; /* use @dbms_type */
1055 dh = NULL;
1056 }
1057 /*
1058 else if ((type == GDA_TYPE_BINARY) ||
1059 (type == GDA_TYPE_BLOB)) {
1060 dh = gda_server_provider_handler_find (provider, cnc, type, NULL);
1061 if (!dh) {
1062 dh = gda_postgres_handler_bin_new (cnc);
1063 if (dh) {
1064 gda_server_provider_handler_declare (provider, dh, cnc, GDA_TYPE_BINARY, NULL);
1065 gda_server_provider_handler_declare (provider, dh, cnc, GDA_TYPE_BLOB, NULL);
1066 g_object_unref (dh);
1067 }
1068 }
1069 }
1070 */
1071 else if ((type == GDA_TYPE_TIME) ||
1072 (type == GDA_TYPE_TIMESTAMP) ||
1073 (type == G_TYPE_DATE)) {
1074 dh = gda_server_provider_handler_find (provider, NULL, type, NULL);
1075 if (!dh) {
1076 dh = gda_handler_time_new ();
1077 gda_handler_time_set_sql_spec ((GdaHandlerTime *) dh, G_DATE_YEAR,
1078 G_DATE_MONTH, G_DATE_DAY, '-', FALSE);
1079 gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_DATE, NULL);
1080 gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_TIME, NULL);
1081 gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_TIMESTAMP, NULL);
1082 g_object_unref (dh);
1083 }
1084 }
1085 else
1086 dh = gda_server_provider_handler_use_default (provider, type);
1087
1088 return dh;
1089 }
1090
1091 /*
1092 * Get default DBMS type request
1093 *
1094 * This method returns the "preferred" DBMS type for GType
1095 */
1096 static const gchar*
gda_jdbc_provider_get_default_dbms_type(GdaServerProvider * provider,GdaConnection * cnc,GType type)1097 gda_jdbc_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConnection *cnc, GType type)
1098 {
1099 if (cnc) {
1100 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
1101 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
1102 }
1103
1104 TO_IMPLEMENT;
1105
1106 if ((type == G_TYPE_INT64) ||
1107 (type == G_TYPE_INT) ||
1108 (type == GDA_TYPE_SHORT) ||
1109 (type == GDA_TYPE_USHORT) ||
1110 (type == G_TYPE_CHAR) ||
1111 (type == G_TYPE_UCHAR) ||
1112 (type == G_TYPE_ULONG) ||
1113 (type == G_TYPE_UINT) ||
1114 (type == G_TYPE_UINT64))
1115 return "integer";
1116
1117 if ((type == GDA_TYPE_BINARY) ||
1118 (type == GDA_TYPE_BLOB))
1119 return "blob";
1120
1121 if (type == G_TYPE_BOOLEAN)
1122 return "boolean";
1123
1124 if ((type == G_TYPE_DATE) ||
1125 (type == GDA_TYPE_GEOMETRIC_POINT) ||
1126 (type == G_TYPE_OBJECT) ||
1127 (type == G_TYPE_STRING) ||
1128 (type == GDA_TYPE_TIME) ||
1129 (type == GDA_TYPE_TIMESTAMP) ||
1130 (type == G_TYPE_GTYPE))
1131 return "string";
1132
1133 if ((type == G_TYPE_DOUBLE) ||
1134 (type == GDA_TYPE_NUMERIC) ||
1135 (type == G_TYPE_FLOAT))
1136 return "real";
1137
1138 if (type == GDA_TYPE_TIME)
1139 return "time";
1140 if (type == GDA_TYPE_TIMESTAMP)
1141 return "timestamp";
1142 if (type == G_TYPE_DATE)
1143 return "date";
1144
1145 if ((type == GDA_TYPE_NULL) ||
1146 (type == G_TYPE_GTYPE))
1147 return NULL;
1148
1149 return "text";
1150 }
1151
1152 /*
1153 * GdaStatement to SQL request
1154 *
1155 * This method renders a #GdaStatement into its SQL representation.
1156 *
1157 * The implementation show here simply calls gda_statement_to_sql_extended() but the rendering
1158 * can be specialized to the database's SQL dialect, see the implementation of gda_statement_to_sql_extended()
1159 * and SQLite's specialized rendering for more details
1160 *
1161 * NOTE: This implementation MUST NOT call gda_statement_to_sql_extended() if it is
1162 * the GdaServerProvider::statement_to_sql() virtual method's implementation
1163 */
1164 static gchar *
gda_jdbc_provider_statement_to_sql(GdaServerProvider * provider,GdaConnection * cnc,GdaStatement * stmt,GdaSet * params,GdaStatementSqlFlag flags,GSList ** params_used,GError ** error)1165 gda_jdbc_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection *cnc,
1166 GdaStatement *stmt, GdaSet *params, GdaStatementSqlFlag flags,
1167 GSList **params_used, GError **error)
1168 {
1169 g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
1170 if (cnc) {
1171 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
1172 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
1173 }
1174
1175 return gda_statement_to_sql_extended (stmt, cnc, params, flags, params_used, error);
1176 }
1177
1178 /*
1179 * Statement prepare request
1180 *
1181 * This methods "converts" @stmt into a prepared statement. A prepared statement is a notion
1182 * specific in its implementation details to the C API used here. If successfull, it must create
1183 * a new #GdaJdbcPStmt object and declare it to @cnc.
1184 */
1185 static gboolean
gda_jdbc_provider_statement_prepare(GdaServerProvider * provider,GdaConnection * cnc,GdaStatement * stmt,GError ** error)1186 gda_jdbc_provider_statement_prepare (GdaServerProvider *provider, GdaConnection *cnc,
1187 GdaStatement *stmt, GError **error)
1188 {
1189 GdaJdbcPStmt *ps;
1190 JdbcConnectionData *cdata;
1191 gboolean retval = FALSE;
1192
1193 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1194 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1195 g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE);
1196
1197 /* fetch prepares stmt if already done */
1198 ps = (GdaJdbcPStmt *) gda_connection_get_prepared_statement (cnc, stmt);
1199 if (ps)
1200 return TRUE;
1201
1202 /* Get private data */
1203 cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1204 if (!cdata)
1205 return FALSE;
1206
1207 /* render as SQL understood by JDBC */
1208 GdaSet *params = NULL;
1209 gchar *sql;
1210 GSList *used_params = NULL;
1211 if (! gda_statement_get_parameters (stmt, ¶ms, error))
1212 return FALSE;
1213 sql = gda_jdbc_provider_statement_to_sql (provider, cnc, stmt, params, GDA_STATEMENT_SQL_PARAMS_AS_UQMARK,
1214 &used_params, error);
1215
1216 JNIEnv *jenv = NULL;
1217 if (!sql)
1218 goto out;
1219
1220 /* prepare @stmt using the C API, creates @ps */
1221 GValue *pstmt_obj;
1222 gboolean jni_detach = FALSE;
1223 jstring jsql;
1224
1225 jenv = _gda_jdbc_get_jenv (&jni_detach, error);
1226 if (!jenv)
1227 goto out;
1228
1229 jsql = (*jenv)->NewStringUTF (jenv, sql);
1230 pstmt_obj = jni_wrapper_method_call (jenv, GdaJConnection__prepareStatement,
1231 cdata->jcnc_obj, NULL, NULL, error, jsql);
1232 (*jenv)->DeleteLocalRef (jenv, jsql);
1233 if (!pstmt_obj)
1234 goto out;
1235
1236 /* make a list of the parameter names used in the statement */
1237 GSList *param_ids = NULL;
1238 if (used_params) {
1239 GSList *list;
1240 jbyte *ctypes;
1241 gint i, nparams;
1242
1243 nparams = g_slist_length (used_params);
1244 ctypes = g_new (jbyte, nparams);
1245
1246 for (i = 0, list = used_params;
1247 list;
1248 i++, list = list->next) {
1249 const gchar *cid;
1250 cid = gda_holder_get_id (GDA_HOLDER (list->data));
1251 if (cid) {
1252 param_ids = g_slist_append (param_ids, g_strdup (cid));
1253 ctypes [i] = _gda_jdbc_gtype_to_proto_type (gda_holder_get_g_type ((GdaHolder*) list->data));
1254 /* g_print ("PREPARATION: param ID: %s\n", cid);*/
1255 }
1256 else {
1257 g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_PREPARE_STMT_ERROR,
1258 "%s", _("Unnamed parameter is not allowed in prepared statements"));
1259 g_slist_foreach (param_ids, (GFunc) g_free, NULL);
1260 g_slist_free (param_ids);
1261 g_free (ctypes);
1262 goto out;
1263 }
1264 }
1265
1266 /* inform JDBC of the parameters' data types */
1267 jbyteArray jtypes;
1268 jtypes = (*jenv)->NewByteArray (jenv, nparams);
1269 if (jni_wrapper_handle_exception (jenv, NULL, NULL, error)) {
1270 g_free (ctypes);
1271 g_slist_foreach (param_ids, (GFunc) g_free, NULL);
1272 g_slist_free (param_ids);
1273 goto out;
1274 }
1275
1276 (*jenv)->SetByteArrayRegion (jenv, jtypes, 0, nparams, ctypes);
1277 if (jni_wrapper_handle_exception (jenv, NULL, NULL, error)) {
1278 g_free (ctypes);
1279 (*jenv)->DeleteLocalRef (jenv, jtypes);
1280 g_slist_foreach (param_ids, (GFunc) g_free, NULL);
1281 g_slist_free (param_ids);
1282 goto out;
1283 }
1284
1285 GValue *jexec_res;
1286 jexec_res = jni_wrapper_method_call (jenv, GdaJPStmt__declareParamTypes,
1287 pstmt_obj, NULL, NULL, error, jni_cpointer_to_jlong (cnc), jtypes);
1288 (*jenv)->DeleteLocalRef (jenv, jtypes);
1289 g_free (ctypes);
1290
1291 if (!jexec_res) {
1292 g_slist_foreach (param_ids, (GFunc) g_free, NULL);
1293 g_slist_free (param_ids);
1294 goto out;
1295 }
1296 gda_value_free (jexec_res);
1297 }
1298
1299 /* create a prepared statement object */
1300 ps = gda_jdbc_pstmt_new (pstmt_obj);
1301 gda_pstmt_set_gda_statement (_GDA_PSTMT (ps), stmt);
1302 _GDA_PSTMT (ps)->param_ids = param_ids;
1303 _GDA_PSTMT (ps)->sql = sql;
1304
1305 gda_connection_add_prepared_statement (cnc, stmt, (GdaPStmt *) ps);
1306 g_object_unref (ps);
1307 retval = TRUE;
1308
1309 out:
1310 if (used_params)
1311 g_slist_free (used_params);
1312 if (params)
1313 g_object_unref (params);
1314 if (jenv)
1315 _gda_jdbc_release_jenv (jni_detach);
1316
1317 return retval;
1318 }
1319
1320 /*
1321 * Execute statement request
1322 *
1323 * Executes a statement. This method should do the following:
1324 * - try to prepare the statement if not yet done
1325 * - optionnally reset the prepared statement
1326 * - bind the variables's values (which are in @params)
1327 * - add a connection event to log the execution
1328 * - execute the prepared statement
1329 *
1330 * If @stmt is an INSERT statement and @last_inserted_row is not NULL then additional actions must be taken to return the
1331 * actual inserted row
1332 */
1333 static GObject *
gda_jdbc_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)1334 gda_jdbc_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
1335 GdaStatement *stmt, GdaSet *params,
1336 GdaStatementModelUsage model_usage,
1337 GType *col_types, GdaSet **last_inserted_row,
1338 guint *task_id,
1339 GdaServerProviderExecCallback async_cb, gpointer cb_data, GError **error)
1340 {
1341 GdaJdbcPStmt *ps;
1342 JdbcConnectionData *cdata;
1343 gboolean allow_noparam;
1344 gboolean empty_rs = FALSE; /* TRUE when @allow_noparam is TRUE and there is a problem with @params
1345 => resulting data model will be empty (0 row) */
1346 JNIEnv *jenv = NULL;
1347 gboolean jni_detach;
1348
1349 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
1350 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
1351 g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
1352
1353 /* If asynchronous connection opening is not supported, then exit now */
1354 if (async_cb) {
1355 g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
1356 "%s", _("Provider does not support asynchronous statement execution"));
1357 return NULL;
1358 }
1359
1360 if (! (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS) &&
1361 ! (model_usage & GDA_STATEMENT_MODEL_CURSOR_FORWARD))
1362 model_usage |= GDA_STATEMENT_MODEL_RANDOM_ACCESS;
1363
1364 allow_noparam = (model_usage & GDA_STATEMENT_MODEL_ALLOW_NOPARAM) &&
1365 (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT);
1366
1367 if (last_inserted_row)
1368 *last_inserted_row = NULL;
1369
1370 /* Get private data */
1371 cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1372 if (!cdata)
1373 return NULL;
1374
1375 jenv = _gda_jdbc_get_jenv (&jni_detach, error);
1376 if (!jenv)
1377 return NULL;
1378
1379 /* get/create new prepared statement */
1380 ps = (GdaJdbcPStmt *) gda_connection_get_prepared_statement (cnc, stmt);
1381 if (!ps) {
1382 if (!gda_jdbc_provider_statement_prepare (provider, cnc, stmt, NULL)) {
1383 /* this case can appear for example if some variables are used in places
1384 * where the C API cannot allow them (for example if the variable is the table name
1385 * in a SELECT statement). The action here is to get the actual SQL code for @stmt,
1386 * and use that SQL instead of @stmt to create another GdaJdbcPStmt object.
1387 */
1388 gchar *sql;
1389 jstring jsql;
1390 GValue *pstmt_obj;
1391
1392 sql = gda_jdbc_provider_statement_to_sql (provider, cnc, stmt, params, 0, NULL, error);
1393 if (!sql) {
1394 _gda_jdbc_release_jenv (jni_detach);
1395 return NULL;
1396 }
1397
1398 jsql = (*jenv)->NewStringUTF (jenv, sql);
1399 pstmt_obj = jni_wrapper_method_call (jenv, GdaJConnection__prepareStatement,
1400 cdata->jcnc_obj, NULL, NULL, error, jsql);
1401 (*jenv)->DeleteLocalRef (jenv, jsql);
1402 g_free (sql);
1403
1404 if (!pstmt_obj) {
1405 _gda_jdbc_release_jenv (jni_detach);
1406 return NULL;
1407 }
1408
1409 ps = gda_jdbc_pstmt_new (pstmt_obj);
1410 }
1411 else {
1412 ps = (GdaJdbcPStmt *) gda_connection_get_prepared_statement (cnc, stmt);
1413 g_object_ref (ps);
1414 }
1415 }
1416 else
1417 g_object_ref (ps);
1418 g_assert (ps);
1419
1420 /* reset the prepared statement's parameters */
1421 GValue *jexec_res;
1422 jexec_res = jni_wrapper_method_call (jenv, GdaJPStmt__clearParameters,
1423 ps->pstmt_obj, NULL, NULL, error);
1424 if (!jexec_res) {
1425 g_object_unref (ps);
1426 _gda_jdbc_release_jenv (jni_detach);
1427 return NULL;
1428 }
1429 gda_value_free (jexec_res);
1430
1431 /* bind statement's parameters */
1432 GSList *list;
1433 GdaConnectionEvent *event = NULL;
1434 int i;
1435 for (i = 0, list = _GDA_PSTMT (ps)->param_ids; list; list = list->next, i++) {
1436 const gchar *pname = (gchar *) list->data;
1437 GdaHolder *h;
1438 GError *lerror = NULL;
1439
1440 /* find requested parameter */
1441 if (!params) {
1442 event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
1443 gda_connection_event_set_description (event, _("Missing parameter(s) to execute query"));
1444 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
1445 GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR,
1446 "%s", _("Missing parameter(s) to execute query"));
1447 break;
1448 }
1449
1450 h = gda_set_get_holder (params, pname);
1451 if (!h) {
1452 gchar *tmp = gda_alphanum_to_text (g_strdup (pname + 1));
1453 if (tmp) {
1454 h = gda_set_get_holder (params, tmp);
1455 g_free (tmp);
1456 }
1457 }
1458 if (!h) {
1459 if (allow_noparam) {
1460 /* bind param to NULL */
1461 jexec_res = jni_wrapper_method_call (jenv, GdaJPStmt__setParameterValue,
1462 ps->pstmt_obj, NULL, NULL, &lerror, i, 0);
1463 if (!jexec_res) {
1464 event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
1465 if (lerror)
1466 gda_connection_event_set_description (event,
1467 lerror->message ? lerror->message : _("No detail"));
1468 g_propagate_error (error, lerror);
1469 break;
1470 }
1471 gda_value_free (jexec_res);
1472 empty_rs = TRUE;
1473 continue;
1474 }
1475 else {
1476 gchar *str;
1477 str = g_strdup_printf (_("Missing parameter '%s' to execute query"), pname);
1478 event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
1479 gda_connection_event_set_description (event, str);
1480 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
1481 GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, "%s", str);
1482 g_free (str);
1483 break;
1484 }
1485
1486 }
1487 if (!gda_holder_is_valid (h)) {
1488 if (allow_noparam) {
1489 /* bind param to NULL */
1490 jexec_res = jni_wrapper_method_call (jenv, GdaJPStmt__setParameterValue,
1491 ps->pstmt_obj, NULL, NULL, &lerror, i, 0);
1492 if (!jexec_res) {
1493 event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
1494 if (lerror)
1495 gda_connection_event_set_description (event,
1496 lerror->message ? lerror->message : _("No detail"));
1497 g_propagate_error (error, lerror);
1498 break;
1499 }
1500 gda_value_free (jexec_res);
1501 empty_rs = TRUE;
1502 continue;
1503 }
1504 else {
1505 gchar *str;
1506 str = g_strdup_printf (_("Parameter '%s' is invalid"), pname);
1507 event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
1508 gda_connection_event_set_description (event, str);
1509 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
1510 GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, "%s", str);
1511 g_free (str);
1512 break;
1513 }
1514 }
1515 else if (gda_holder_value_is_default (h) && !gda_holder_get_value (h)) {
1516 /* create a new GdaStatement to handle all default values and execute it instead */
1517 GdaSqlStatement *sqlst;
1518 GError *lerror = NULL;
1519 sqlst = gda_statement_rewrite_for_default_values (stmt, params, TRUE, &lerror);
1520 if (!sqlst) {
1521 event = gda_connection_point_available_event (cnc,
1522 GDA_CONNECTION_EVENT_ERROR);
1523 gda_connection_event_set_description (event, lerror && lerror->message ?
1524 lerror->message :
1525 _("Can't rewrite statement handle default values"));
1526 g_propagate_error (error, lerror);
1527 break;
1528 }
1529
1530 GdaStatement *rstmt;
1531 GObject *res;
1532 rstmt = g_object_new (GDA_TYPE_STATEMENT, "structure", sqlst, NULL);
1533 gda_sql_statement_free (sqlst);
1534 g_object_unref (ps);
1535 _gda_jdbc_release_jenv (jni_detach);
1536 res = gda_jdbc_provider_statement_execute (provider, cnc,
1537 rstmt, params,
1538 model_usage,
1539 col_types, last_inserted_row,
1540 task_id,
1541 async_cb, cb_data, error);
1542 g_object_unref (rstmt);
1543 return res;
1544 }
1545
1546 /* actual binding using the C API, for parameter at position @i */
1547 const GValue *value = gda_holder_get_value (h);
1548 if (!value || gda_value_is_null (value)) {
1549 GdaStatement *rstmt;
1550 if (! gda_rewrite_statement_for_null_parameters (stmt, params, &rstmt, error)) {
1551 jexec_res = jni_wrapper_method_call (jenv, GdaJPStmt__setParameterValue,
1552 ps->pstmt_obj, NULL, NULL, &lerror, i,
1553 (G_VALUE_TYPE (value) == GDA_TYPE_NULL) ? (glong) 0 : (glong) value);
1554 if (!jexec_res) {
1555 event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
1556 if (lerror)
1557 gda_connection_event_set_description (event,
1558 lerror->message ? lerror->message : _("No detail"));
1559
1560 g_propagate_error (error, lerror);
1561 break;
1562 }
1563 gda_value_free (jexec_res);
1564 }
1565 else if (!rstmt)
1566 return NULL;
1567 else {
1568 _gda_jdbc_release_jenv (jni_detach);
1569
1570 /* The strategy here is to execute @rstmt using its prepared
1571 * statement, but with common data from @ps. Beware that
1572 * the @param_ids attribute needs to be retained (i.e. it must not
1573 * be the one copied from @ps) */
1574 GObject *obj;
1575 GdaJdbcPStmt *tps;
1576 GdaPStmt *gtps;
1577 GSList *prep_param_ids, *copied_param_ids;
1578 if (!gda_jdbc_provider_statement_prepare (provider, cnc,
1579 rstmt, error))
1580 return NULL;
1581 tps = (GdaJdbcPStmt *)
1582 gda_connection_get_prepared_statement (cnc, rstmt);
1583 gtps = (GdaPStmt *) tps;
1584
1585 /* keep @param_ids to avoid being cleared by gda_pstmt_copy_contents() */
1586 prep_param_ids = gtps->param_ids;
1587 gtps->param_ids = NULL;
1588
1589 /* actual copy */
1590 gda_pstmt_copy_contents ((GdaPStmt *) ps, (GdaPStmt *) tps);
1591
1592 /* restore previous @param_ids */
1593 copied_param_ids = gtps->param_ids;
1594 gtps->param_ids = prep_param_ids;
1595
1596 /* execute */
1597 obj = gda_jdbc_provider_statement_execute (provider, cnc,
1598 rstmt, params,
1599 model_usage,
1600 col_types,
1601 last_inserted_row,
1602 task_id, async_cb,
1603 cb_data, error);
1604 /* clear original @param_ids and restore copied one */
1605 g_slist_foreach (prep_param_ids, (GFunc) g_free, NULL);
1606 g_slist_free (prep_param_ids);
1607
1608 gtps->param_ids = copied_param_ids;
1609
1610 /*if (GDA_IS_DATA_MODEL (obj))
1611 gda_data_model_dump ((GdaDataModel*) obj, NULL);*/
1612
1613 g_object_unref (rstmt);
1614 g_object_unref (ps);
1615 return obj;
1616 }
1617 }
1618 else {
1619 jexec_res = jni_wrapper_method_call (jenv, GdaJPStmt__setParameterValue,
1620 ps->pstmt_obj, NULL, NULL, &lerror, i,
1621 (G_VALUE_TYPE (value) == GDA_TYPE_NULL) ? (glong) 0 : (glong) value);
1622 if (!jexec_res) {
1623 event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_ERROR);
1624 if (lerror)
1625 gda_connection_event_set_description (event,
1626 lerror->message ? lerror->message : _("No detail"));
1627
1628 g_propagate_error (error, lerror);
1629 break;
1630 }
1631 gda_value_free (jexec_res);
1632 }
1633 }
1634
1635 if (event) {
1636 gda_connection_add_event (cnc, event);
1637 g_object_unref (ps);
1638 _gda_jdbc_release_jenv (jni_detach);
1639 return NULL;
1640 }
1641
1642 /* add a connection event for the execution */
1643 event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_COMMAND);
1644 gda_connection_event_set_description (event, _GDA_PSTMT (ps)->sql);
1645 gda_connection_add_event (cnc, event);
1646
1647 if (empty_rs) {
1648 /* There are some missing parameters, so the SQL can't be executed but we still want
1649 * to execute something to get the columns correctly. A possibility is to actually
1650 * execute another SQL which is the code shown here.
1651 *
1652 * To adapt depending on the C API and its features */
1653 GdaStatement *estmt;
1654 gchar *esql;
1655 jstring jsql;
1656 estmt = gda_select_alter_select_for_empty (stmt, error);
1657 if (!estmt) {
1658 g_object_unref (ps);
1659 _gda_jdbc_release_jenv (jni_detach);
1660 return NULL;
1661 }
1662 esql = gda_statement_to_sql (estmt, NULL, error);
1663 g_object_unref (estmt);
1664 if (!esql) {
1665 g_object_unref (ps);
1666 _gda_jdbc_release_jenv (jni_detach);
1667 return NULL;
1668 }
1669
1670 /* Execute the 'esql' SQL code */
1671 jsql = (*jenv)->NewStringUTF (jenv, esql);
1672 g_free (esql);
1673 jexec_res = jni_wrapper_method_call (jenv, GdaJConnection__executeDirectSQL,
1674 cdata->jcnc_obj, NULL, NULL, error, jsql);
1675 (*jenv)->DeleteLocalRef (jenv, jsql);
1676 if (!jexec_res) {
1677 g_object_unref (ps);
1678 _gda_jdbc_release_jenv (jni_detach);
1679 return NULL;
1680 }
1681 }
1682 else {
1683 /* Execute the _GDA_PSTMT (ps)->sql SQL code */
1684 gboolean is_rs;
1685 jexec_res = jni_wrapper_method_call (jenv, GdaJPStmt__execute,
1686 ps->pstmt_obj, NULL, NULL, error);
1687 if (!jexec_res) {
1688 g_object_unref (ps);
1689 _gda_jdbc_release_jenv (jni_detach);
1690 return NULL;
1691 }
1692
1693 is_rs = g_value_get_boolean (jexec_res);
1694 gda_value_free (jexec_res);
1695 if (is_rs) {
1696 jexec_res = jni_wrapper_method_call (jenv, GdaJPStmt__getResultSet,
1697 ps->pstmt_obj, NULL, NULL, error);
1698 if (!jexec_res) {
1699 g_object_unref (ps);
1700 _gda_jdbc_release_jenv (jni_detach);
1701 return NULL;
1702 }
1703 }
1704 else {
1705 jexec_res = jni_wrapper_method_call (jenv, GdaJPStmt__getImpactedRows,
1706 ps->pstmt_obj, NULL, NULL, error);
1707 if (!jexec_res) {
1708 g_object_unref (ps);
1709 _gda_jdbc_release_jenv (jni_detach);
1710 return NULL;
1711 }
1712 }
1713 }
1714
1715 if (G_VALUE_TYPE (jexec_res) == GDA_TYPE_JNI_OBJECT) {
1716 /* Note: at this point jexec_res must contain a GdaJResultSet JAVA object */
1717 GObject *data_model;
1718 GdaDataModelAccessFlags flags;
1719
1720 if (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS)
1721 flags = GDA_DATA_MODEL_ACCESS_RANDOM;
1722 else
1723 flags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD;
1724
1725 data_model = (GObject *) gda_jdbc_recordset_new (cnc, ps, params, jenv, jexec_res, flags, col_types);
1726 gda_connection_internal_statement_executed (cnc, stmt, params, NULL); /* required: help @cnc keep some stats */
1727
1728 g_object_unref (ps);
1729 _gda_jdbc_release_jenv (jni_detach);
1730 return data_model;
1731 }
1732 else {
1733 GdaSet *set = NULL;
1734
1735 /*
1736 gchar *str;
1737 GdaConnectionEvent *event;
1738
1739 event = gda_connection_point_available_event (cnc, GDA_CONNECTION_EVENT_NOTICE);
1740 str = g_strdup (PQcmdStatus (pg_res));
1741 gda_connection_event_set_description (event, str);
1742 g_free (str);
1743 gda_connection_add_event (cnc, event);
1744 */
1745
1746 set = gda_set_new_inline (1, "IMPACTED_ROWS", G_TYPE_INT, g_value_get_int (jexec_res));
1747 gda_value_free (jexec_res);
1748
1749 /*
1750 if ((PQoidValue (pg_res) != InvalidOid) && last_inserted_row)
1751 *last_inserted_row = make_last_inserted_set (cnc, stmt, PQoidValue (pg_res));
1752 */
1753 gda_connection_internal_statement_executed (cnc, stmt, params, event); /* required: help @cnc keep some stats */
1754 g_object_unref (ps);
1755 _gda_jdbc_release_jenv (jni_detach);
1756 return (GObject*) set;
1757 }
1758 }
1759
1760 /*
1761 * Rewrites a statement in case some parameters in @params are set to DEFAULT, for INSERT or UPDATE statements
1762 *
1763 * Safely removes any default value inserted or updated
1764 */
1765 static GdaSqlStatement *
gda_jdbc_statement_rewrite(GdaServerProvider * provider,GdaConnection * cnc,GdaStatement * stmt,GdaSet * params,GError ** error)1766 gda_jdbc_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
1767 GdaStatement *stmt, GdaSet *params, GError **error)
1768 {
1769 if (cnc) {
1770 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
1771 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
1772 }
1773 return gda_statement_rewrite_for_default_values (stmt, params, TRUE, error);
1774 }
1775
1776 /*
1777 * starts a distributed transaction: put the XA transaction in the ACTIVE state
1778 */
1779 static gboolean
gda_jdbc_provider_xa_start(GdaServerProvider * provider,GdaConnection * cnc,const GdaXaTransactionId * xid,G_GNUC_UNUSED GError ** error)1780 gda_jdbc_provider_xa_start (GdaServerProvider *provider, GdaConnection *cnc,
1781 const GdaXaTransactionId *xid, G_GNUC_UNUSED GError **error)
1782 {
1783 JdbcConnectionData *cdata;
1784
1785 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1786 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1787 g_return_val_if_fail (xid, FALSE);
1788
1789 cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1790 if (!cdata)
1791 return FALSE;
1792
1793 /*
1794 * see Sun's Java Transaction API:
1795 * http://java.sun.com/javaee/technologies/jta/index.jsp
1796 */
1797 TO_IMPLEMENT;
1798 return FALSE;
1799 }
1800
1801 /*
1802 * put the XA transaction in the IDLE state: the connection won't accept any more modifications.
1803 * This state is required by some database providers before actually going to the PREPARED state
1804 */
1805 static gboolean
gda_jdbc_provider_xa_end(GdaServerProvider * provider,GdaConnection * cnc,const GdaXaTransactionId * xid,G_GNUC_UNUSED GError ** error)1806 gda_jdbc_provider_xa_end (GdaServerProvider *provider, GdaConnection *cnc,
1807 const GdaXaTransactionId *xid, G_GNUC_UNUSED GError **error)
1808 {
1809 JdbcConnectionData *cdata;
1810
1811 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1812 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1813 g_return_val_if_fail (xid, FALSE);
1814
1815 cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1816 if (!cdata)
1817 return FALSE;
1818
1819 TO_IMPLEMENT;
1820 return FALSE;
1821 }
1822
1823 /*
1824 * prepares the distributed transaction: put the XA transaction in the PREPARED state
1825 */
1826 static gboolean
gda_jdbc_provider_xa_prepare(GdaServerProvider * provider,GdaConnection * cnc,const GdaXaTransactionId * xid,G_GNUC_UNUSED GError ** error)1827 gda_jdbc_provider_xa_prepare (GdaServerProvider *provider, GdaConnection *cnc,
1828 const GdaXaTransactionId *xid, G_GNUC_UNUSED GError **error)
1829 {
1830 JdbcConnectionData *cdata;
1831
1832 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1833 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1834 g_return_val_if_fail (xid, FALSE);
1835
1836 cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1837 if (!cdata)
1838 return FALSE;
1839
1840 TO_IMPLEMENT;
1841 return FALSE;
1842 }
1843
1844 /*
1845 * commits the distributed transaction: actually write the prepared data to the database and
1846 * terminates the XA transaction
1847 */
1848 static gboolean
gda_jdbc_provider_xa_commit(GdaServerProvider * provider,GdaConnection * cnc,const GdaXaTransactionId * xid,G_GNUC_UNUSED GError ** error)1849 gda_jdbc_provider_xa_commit (GdaServerProvider *provider, GdaConnection *cnc,
1850 const GdaXaTransactionId *xid, G_GNUC_UNUSED GError **error)
1851 {
1852 JdbcConnectionData *cdata;
1853
1854 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1855 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1856 g_return_val_if_fail (xid, FALSE);
1857
1858 cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1859 if (!cdata)
1860 return FALSE;
1861
1862 TO_IMPLEMENT;
1863 return FALSE;
1864 }
1865
1866 /*
1867 * Rolls back an XA transaction, possible only if in the ACTIVE, IDLE or PREPARED state
1868 */
1869 static gboolean
gda_jdbc_provider_xa_rollback(GdaServerProvider * provider,GdaConnection * cnc,const GdaXaTransactionId * xid,G_GNUC_UNUSED GError ** error)1870 gda_jdbc_provider_xa_rollback (GdaServerProvider *provider, GdaConnection *cnc,
1871 const GdaXaTransactionId *xid, G_GNUC_UNUSED GError **error)
1872 {
1873 JdbcConnectionData *cdata;
1874
1875 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
1876 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
1877 g_return_val_if_fail (xid, FALSE);
1878
1879 cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1880 if (!cdata)
1881 return FALSE;
1882
1883 TO_IMPLEMENT;
1884 return FALSE;
1885 }
1886
1887 /*
1888 * Lists all XA transactions that are in the PREPARED state
1889 *
1890 * Returns: a list of GdaXaTransactionId structures, which will be freed by the caller
1891 */
1892 static GList *
gda_jdbc_provider_xa_recover(GdaServerProvider * provider,GdaConnection * cnc,G_GNUC_UNUSED GError ** error)1893 gda_jdbc_provider_xa_recover (GdaServerProvider *provider, GdaConnection *cnc,
1894 G_GNUC_UNUSED GError **error)
1895 {
1896 JdbcConnectionData *cdata;
1897
1898 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
1899 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
1900
1901 cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data_error (cnc, error);
1902 if (!cdata)
1903 return NULL;
1904
1905 TO_IMPLEMENT;
1906 return NULL;
1907 }
1908
1909 /*
1910 * Free connection's specific data
1911 */
1912 static void
gda_jdbc_free_cnc_data(JdbcConnectionData * cdata)1913 gda_jdbc_free_cnc_data (JdbcConnectionData *cdata)
1914 {
1915 if (!cdata)
1916 return;
1917
1918 g_free (cdata->server_version);
1919
1920 if (cdata->jcnc_obj) {
1921 /* force the connection to be closed */
1922 JNIEnv *jenv = NULL;
1923 gboolean jni_detach;
1924 GError *error = NULL;
1925
1926 jenv = _gda_jdbc_get_jenv (&jni_detach, &error);
1927 if (!jenv) {
1928 g_warning ("%s", error->message);
1929 g_error_free (error);
1930 }
1931 else {
1932 GValue *res;
1933 res = jni_wrapper_method_call (jenv, GdaJConnection__close,
1934 cdata->jcnc_obj, NULL, NULL, &error);
1935 if (res) {
1936 #ifdef GDA_DEBUG
1937 g_print ("Connection closed!\n");
1938 #endif
1939 gda_value_free (res);
1940 }
1941 else {
1942 g_warning ("Could not propertly close JDBC connection (will be done by the garbage collector): %s",
1943 error && error->message ? error->message : "No detail");
1944 if (error)
1945 g_error_free (error);
1946 }
1947 _gda_jdbc_release_jenv (jni_detach);
1948 }
1949 gda_value_free (cdata->jcnc_obj);
1950 cdata->jcnc_obj = NULL;
1951 }
1952
1953 if (cdata->jmeta_obj)
1954 gda_value_free (cdata->jmeta_obj);
1955
1956 g_free (cdata);
1957 }
1958
1959 /**
1960 * gda_jdbc_provider_new
1961 * @jdbc_driver: the JDBC driver to use (such as "sun.jdbc.odbc.JdbcOdbcDriver")
1962 * @error: a place to store errors, or %NULL
1963 *
1964 * Returns: a new #GdaServerProvider for that JDBC driver, or %NULL if an error occurred
1965 */
1966 GdaServerProvider *
gda_jdbc_provider_new(const gchar * jdbc_driver,GError ** error)1967 gda_jdbc_provider_new (const gchar *jdbc_driver, GError **error)
1968 {
1969 GdaServerProvider *prov;
1970 g_return_val_if_fail (jdbc_driver, NULL);
1971
1972 if (!_jdbc_provider_java_vm) {
1973 g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_INTERNAL_ERROR,
1974 "%s", "No JVM runtime identified (this should not happen at this point)!");
1975 return NULL;
1976 }
1977
1978 /* create a JAVA's GdaJProvider object */
1979 JNIEnv *env;
1980 GValue *obj_value;
1981 jstring jstr;
1982 gboolean detach_jni;
1983
1984 env = _gda_jdbc_get_jenv (&detach_jni, error);
1985 if (!env)
1986 return NULL;
1987
1988 jstr = (*env)->NewStringUTF(env, jdbc_driver);
1989 obj_value = jni_wrapper_instantiate_object (env, GdaJProvider_class, "(Ljava/lang/String;)V", error, jstr);
1990 (*env)->DeleteLocalRef(env, jstr);
1991 if (!obj_value) {
1992 _gda_jdbc_release_jenv (detach_jni);
1993 return NULL;
1994 }
1995
1996 prov = (GdaServerProvider*) g_object_new (GDA_TYPE_JDBC_PROVIDER, NULL);
1997 GDA_JDBC_PROVIDER (prov)->jprov_obj = obj_value;
1998 _gda_jdbc_release_jenv (detach_jni);
1999
2000 GDA_JDBC_PROVIDER (prov)->jdbc_driver = g_strdup (jdbc_driver);
2001
2002 return prov;
2003 }
2004