1 /*
2 * Copyright (C) 2001 - 2002 Gonzalo Paniagua Javier <gonzalo@gnome-db.org>
3 * Copyright (C) 2001 - 2004 Rodrigo Moya <rodrigo@gnome-db.org>
4 * Copyright (C) 2004 Jeronimo Albi <jeronimoalbi@yahoo.com.ar>
5 * Copyright (C) 2004 - 2012 Vivien Malerba <malerba@gnome-db.org>
6 * Copyright (C) 2005 Christopher Taylor <christophth@tiscali.it>
7 * Copyright (C) 2005 Álvaro Peña <alvaropg@telefonica.net>
8 * Copyright (C) 2009 Bas Driessen <bas.driessen@xobas.com>
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
25
26 #include <stdarg.h>
27 #include <string.h>
28 #include <glib/gi18n-lib.h>
29 #include <libgda/gda-util.h>
30 #include <libgda/gda-connection-private.h>
31 #include "gda-firebird.h"
32 #include "gda-firebird-recordset.h"
33 #include "gda-firebird-provider.h"
34 #include <libgda/libgda-global-variables.h>
35 #include <libgda/gda-debug-macros.h>
36
37 #define _GDA_PSTMT(x) ((GdaPStmt*)(x))
38
39 #ifndef ISC_INT64_FORMAT
40
41 /* Define a format string for printf. Printing of 64-bit integers
42 is not standard between platforms */
43
44 #if (defined(_MSC_VER) && defined(WIN32))
45 #define ISC_INT64_FORMAT "I64"
46 #else
47 #define ISC_INT64_FORMAT "ll"
48 #endif
49 #endif
50
51 typedef PARAMVARY VARY2;
52
53 static void gda_firebird_recordset_class_init (GdaFirebirdRecordsetClass *klass);
54 static void gda_firebird_recordset_init (GdaFirebirdRecordset *recset,
55 GdaFirebirdRecordsetClass *klass);
56 static void gda_firebird_recordset_dispose (GObject *object);
57
58 /* virtual methods */
59 static gint gda_firebird_recordset_fetch_nb_rows (GdaDataSelect *model);
60 static gboolean gda_firebird_recordset_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error);
61 static gboolean gda_firebird_recordset_fetch_next (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error);
62 static gboolean gda_firebird_recordset_fetch_prev (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error);
63 static gboolean gda_firebird_recordset_fetch_at (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error);
64
65
66 struct _GdaFirebirdRecordsetPrivate {
67
68 gint n_columns;
69 };
70 static GObjectClass *parent_class = NULL;
71
72
73 /*
74 * Object init and finalize
75 */
76 static void
gda_firebird_recordset_init(GdaFirebirdRecordset * recset,GdaFirebirdRecordsetClass * klass)77 gda_firebird_recordset_init (GdaFirebirdRecordset *recset,
78 GdaFirebirdRecordsetClass *klass)
79 {
80 //WHERE_AM_I;
81 g_return_if_fail (GDA_IS_FIREBIRD_RECORDSET (recset));
82
83 recset->priv = g_new0 (GdaFirebirdRecordsetPrivate, 1);
84
85
86 /* initialize specific information */
87 //TO_IMPLEMENT;
88
89 }
90
91 static void
gda_firebird_recordset_class_init(GdaFirebirdRecordsetClass * klass)92 gda_firebird_recordset_class_init (GdaFirebirdRecordsetClass *klass)
93 {
94 //WHERE_AM_I;
95 GObjectClass *object_class = G_OBJECT_CLASS (klass);
96 GdaDataSelectClass *pmodel_class = GDA_DATA_SELECT_CLASS (klass);
97
98 parent_class = g_type_class_peek_parent (klass);
99
100 object_class->dispose = gda_firebird_recordset_dispose;
101 pmodel_class->fetch_nb_rows = gda_firebird_recordset_fetch_nb_rows;
102 pmodel_class->fetch_random = gda_firebird_recordset_fetch_random;
103
104 pmodel_class->fetch_next = gda_firebird_recordset_fetch_next;
105 pmodel_class->fetch_prev = gda_firebird_recordset_fetch_prev;
106 pmodel_class->fetch_at = gda_firebird_recordset_fetch_at;
107 }
108
109 static void
gda_firebird_recordset_dispose(GObject * object)110 gda_firebird_recordset_dispose (GObject *object)
111 {
112 GdaFirebirdRecordset *recset = (GdaFirebirdRecordset *) object;
113 //WHERE_AM_I;
114 g_return_if_fail (GDA_IS_FIREBIRD_RECORDSET (recset));
115
116 if (recset->priv) {
117 //if (recset->priv->cnc)
118 // g_object_unref (recset->priv->cnc);
119
120 /* free specific information */
121 //TO_IMPLEMENT;
122
123 g_free (recset->priv);
124 recset->priv = NULL;
125 }
126
127 parent_class->dispose (object);
128 }
129
130 /*
131 * Public functions
132 */
133
134 GType
gda_firebird_recordset_get_type(void)135 gda_firebird_recordset_get_type (void)
136 {
137 static GType type = 0;
138
139 if (G_UNLIKELY (type == 0)) {
140 static GMutex registering;
141 static const GTypeInfo info = {
142 sizeof (GdaFirebirdRecordsetClass),
143 (GBaseInitFunc) NULL,
144 (GBaseFinalizeFunc) NULL,
145 (GClassInitFunc) gda_firebird_recordset_class_init,
146 NULL,
147 NULL,
148 sizeof (GdaFirebirdRecordset),
149 0,
150 (GInstanceInitFunc) gda_firebird_recordset_init,
151 0
152 };
153 g_mutex_lock (®istering);
154 if (type == 0) {
155 #ifdef FIREBIRD_EMBED
156 type = g_type_register_static (GDA_TYPE_DATA_SELECT, "GdaFirebirdRecordsetEmbed", &info, 0);
157 #else
158 type = g_type_register_static (GDA_TYPE_DATA_SELECT, "GdaFirebirdRecordset", &info, 0);
159 #endif
160 }
161 g_mutex_unlock (®istering);
162 }
163
164 return type;
165 }
166
167 static GType
_gda_firebird_type_to_gda(XSQLVAR * var)168 _gda_firebird_type_to_gda (XSQLVAR *var){
169 short dtype;
170 GType gtype;
171 dtype = var->sqltype & ~1;
172 /*
173 if ((var->sqltype & 1) && (*var->sqlind < 0)){
174 return GDA_TYPE_NULL;
175 }
176 */
177 switch (dtype){
178 case SQL_TEXT:
179 case SQL_VARYING:
180 gtype = G_TYPE_STRING;
181 //g_print("SQL_TEXT\n");
182 break;
183 case SQL_LONG:
184 gtype = G_TYPE_ULONG;
185 //g_print("SQL_TYPE_LONG\n");
186 break;
187 case SQL_SHORT:
188 case SQL_INT64:
189 gtype = G_TYPE_INT;
190 //g_print("SQL_TYPE_INT\n");
191 break;
192 case SQL_FLOAT:
193 gtype = G_TYPE_FLOAT;
194 //g_print("SQL_TYPE_FLOAT\n");
195 break;
196 case SQL_DOUBLE:
197 gtype = G_TYPE_DOUBLE;
198 //g_print("SQL_TYPE_DOUBLE\n");
199 break;
200 case SQL_TIMESTAMP:
201 //gtype = G_TYPE_DATE_TIME;
202 gtype = GDA_TYPE_TIMESTAMP;
203 //g_print("SQL_TIMESTAMP\n");
204 break;
205 case SQL_TYPE_DATE:
206 gtype = G_TYPE_DATE;
207 //g_print("SQL_TYPE_DATE\n");
208 break;
209 case SQL_TYPE_TIME:
210 gtype = GDA_TYPE_TIME;
211 //g_print("SQL_TYPE_TIME\n");
212 break;
213 case SQL_BLOB:
214 case SQL_ARRAY:
215 default:
216 gtype = GDA_TYPE_BLOB;
217 //g_print("SQL_BLOB\n");
218 break;
219 }
220
221 return gtype;
222 }
223
224 /*
225 * Print column's data.
226 */
227 void
_fb_set_row_data(XSQLVAR * var,GValue * value,GdaRow * row,GType req_col_type)228 _fb_set_row_data (XSQLVAR *var, GValue *value, GdaRow *row, GType req_col_type){
229 short dtype;
230 char data[2048], *p;
231 char blob_s[20], date_s[25];
232 VARY2 *vary2;
233 short len;
234 struct tm times;
235 ISC_QUAD bid;
236
237 dtype = var->sqltype & ~1;
238 p = data;
239
240 /* Null handling. If the column is nullable and null */
241 if ((var->sqltype & 1) && (*var->sqlind < 0))
242 {
243 switch (dtype)
244 {
245 case SQL_TEXT:
246 case SQL_VARYING:
247 len = var->sqllen;
248 break;
249 case SQL_SHORT:
250 len = 6;
251 if (var->sqlscale > 0) len += var->sqlscale;
252 break;
253 case SQL_LONG:
254 len = 11;
255 if (var->sqlscale > 0) len += var->sqlscale;
256 break;
257 case SQL_INT64:
258 len = 21;
259 if (var->sqlscale > 0) len += var->sqlscale;
260 break;
261 case SQL_FLOAT:
262 len = 15;
263 break;
264 case SQL_DOUBLE:
265 len = 24;
266 break;
267 case SQL_TIMESTAMP:
268 len = 24;
269 break;
270 case SQL_TYPE_DATE:
271 len = 10;
272 break;
273 case SQL_TYPE_TIME:
274 len = 13;
275 break;
276 case SQL_BLOB:
277 case SQL_ARRAY:
278 default:
279 len = 17;
280 break;
281 }
282 //if (req_col_type != G_TYPE_BOOLEAN)
283 // g_value_set_string (value, "NULL");
284 //else
285 // g_value_set_boolean(value, FALSE);
286 }
287 else
288 {
289 switch (dtype)
290 {
291 case SQL_TEXT:
292 sprintf (p, "%.*s", var->sqllen, var->sqldata);
293 if (req_col_type != G_TYPE_BOOLEAN)
294 g_value_set_string (value, p);
295 else
296 g_value_set_boolean(value, g_ascii_strcasecmp("1", p) == 0 ? TRUE : FALSE);
297 break;
298 case SQL_VARYING:
299 vary2 = (VARY2*) var->sqldata;
300 vary2->vary_string[vary2->vary_length] = '\0';
301 g_value_set_string (value, (char *)vary2->vary_string);
302 break;
303
304 case SQL_SHORT:
305 case SQL_LONG:
306 case SQL_INT64: {
307 ISC_INT64 fb_value;
308 short field_width;
309 short dscale;
310 switch (dtype) {
311 case SQL_SHORT:
312 fb_value = (ISC_INT64)*(short *) var->sqldata;
313 field_width = 6;
314 break;
315 case SQL_LONG:
316 fb_value = (ISC_INT64)*(int *) var->sqldata;
317 field_width = 11;
318 break;
319 case SQL_INT64:
320 fb_value = (ISC_INT64)*(ISC_INT64 *) var->sqldata;
321 field_width = 21;
322 break;
323 default:
324 field_width = 11;
325 fb_value = 0;
326 break;
327 }
328
329 dscale = var->sqlscale;
330 if (dscale < 0) {
331 ISC_INT64 tens;
332 short i;
333
334 tens = 1;
335 for (i = 0; i > dscale; i--)
336 tens *= 10;
337
338 if (fb_value >= 0)
339 sprintf (p, "%*" ISC_INT64_FORMAT "d.%0*" ISC_INT64_FORMAT "d",
340 field_width - 1 + dscale,
341 (ISC_INT64) fb_value / tens,
342 -dscale,
343 (ISC_INT64) fb_value % tens);
344 else if ((fb_value / tens) != 0)
345 sprintf (p, "%*" ISC_INT64_FORMAT "d.%0*" ISC_INT64_FORMAT "d",
346 field_width - 1 + dscale,
347 (ISC_INT64) (fb_value / tens),
348 -dscale,
349 (ISC_INT64) -(fb_value % tens));
350 else
351 sprintf (p, "%*s.%0*" ISC_INT64_FORMAT "d",
352 field_width - 1 + dscale,
353 "-0",
354 -dscale,
355 (ISC_INT64) -(fb_value % tens));
356 }
357 else if (dscale){
358 sprintf (p, "%*" ISC_INT64_FORMAT "d%0*d",
359 field_width,
360 (ISC_INT64) fb_value,
361 dscale, 0);
362 }
363 else{
364 sprintf (p, "%*" ISC_INT64_FORMAT "d",
365 field_width,
366 (ISC_INT64) fb_value);
367 }
368
369 if (req_col_type != G_TYPE_BOOLEAN){
370 switch (req_col_type) {
371 case G_TYPE_INT:
372 g_value_set_int (value, atoi (p));
373 break;
374 case G_TYPE_UINT:
375 g_value_set_uint (value, atoi (p));
376 break;
377 case G_TYPE_INT64:
378 g_value_set_int64(value, atoll(p));
379 break;
380 case G_TYPE_UINT64:
381 g_value_set_uint64(value, atoll(p));
382 break;
383 case G_TYPE_LONG:
384 g_value_set_long (value, atoll (p));
385 break;
386 case G_TYPE_ULONG:
387 g_value_set_ulong (value, atoll (p));
388 break;
389 default:
390 g_print("Oh flip....did not cater for this\n");
391 g_value_set_int64 (value, atoll (p));
392 break;
393 }
394 /*switch (dtype) {
395 case SQL_SHORT:
396 gda_value_set_short (value, atoi (p));
397 break;
398 case SQL_LONG:
399 g_value_set_ulong (value, atoll (p));
400 break;
401 case SQL_INT64:
402 default:
403 g_value_set_int64 (value, atoll (p));
404 break;
405 }*/
406 }
407 else
408 g_value_set_boolean(value, atoll(p) == 1 ? TRUE : FALSE);
409 }
410 break;
411
412 case SQL_FLOAT:
413 g_value_set_float (value, *(float *) (var->sqldata));
414 break;
415
416 case SQL_DOUBLE:
417 g_value_set_double (value, *(double *) (var->sqldata));
418 break;
419
420 case SQL_TIMESTAMP:
421 isc_decode_timestamp((ISC_TIMESTAMP *)var->sqldata, ×);
422 sprintf(date_s, "%04d-%02d-%02d %02d:%02d:%02d",
423 times.tm_year + 1900,
424 times.tm_mon+1,
425 times.tm_mday,
426 times.tm_hour,
427 times.tm_min,
428 times.tm_sec);
429 sprintf(p, "%*s", 22, date_s);
430 //g_value_set_string (value, p);
431
432 GdaTimestamp timestamp;
433 if (! gda_parse_iso8601_timestamp (×tamp, date_s)) {
434 g_print("****ERROR CONVERTING TO TIMESTAMP: %s\n", date_s);
435
436 //gda_row_invalidate_value (row, value);
437 /*
438 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
439 GDA_SERVER_PROVIDER_DATA_ERROR,
440 _("Invalid timestamp '%s' (format should be YYYY-MM-DD HH:MM:SS[.ms])"),
441 p);
442 */
443 }
444 else
445 gda_value_set_timestamp (value, ×tamp);
446 break;
447
448 case SQL_TYPE_DATE:
449 isc_decode_sql_date((ISC_DATE *)var->sqldata, ×);
450 sprintf(date_s, "%04d-%02d-%02d",
451 times.tm_year + 1900,
452 times.tm_mon+1,
453 times.tm_mday);
454 sprintf(p, "%*s ", 10, date_s);
455 GDate date;
456 if (!gda_parse_iso8601_date (&date, date_s)) {
457 //gda_row_invalidate_value (row, value);
458 /*
459 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
460 GDA_SERVER_PROVIDER_DATA_ERROR,
461 _("Invalid date '%s' (date format should be YYYY-MM-DD)"), p);
462 */
463 }
464 else
465 g_value_set_boxed (value, &date);
466 break;
467
468 case SQL_TYPE_TIME:
469 isc_decode_sql_time((ISC_TIME *)var->sqldata, ×);
470 sprintf(date_s, "%02d:%02d:%02d",
471 times.tm_hour,
472 times.tm_min,
473 times.tm_sec);
474 sprintf(p, "%*s ", 11, date_s);
475 GdaTime timegda;
476 if (!gda_parse_iso8601_time (&timegda, date_s)) {
477 //gda_row_invalidate_value (row, value);
478 /*
479 g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
480 GDA_SERVER_PROVIDER_DATA_ERROR,
481 _("Invalid time '%s' (time format should be HH:MM:SS[.ms])"), p);
482 */
483 }
484 else
485 gda_value_set_time (value, &timegda);
486 break;
487
488 case SQL_BLOB:
489 case SQL_ARRAY:
490 /* Print the blob id on blobs or arrays */
491 bid = *(ISC_QUAD *) var->sqldata;
492 sprintf(blob_s, "%08x:%08x", (unsigned int)bid.gds_quad_high, (unsigned int)bid.gds_quad_low);
493 sprintf(p, "%17s ", blob_s);
494 g_value_set_string (value, p);
495 break;
496
497 default:
498 g_value_set_string(value, "TYPE NOT FOUND");
499 break;
500 }
501
502 //g_print("\t\t%s\n", p);
503 }
504 }
505
506 static GdaRow *
new_row_from_firebird_stmt(GdaFirebirdRecordset * imodel,G_GNUC_UNUSED gint rownum,GType * col_types,GError ** error)507 new_row_from_firebird_stmt (GdaFirebirdRecordset *imodel, G_GNUC_UNUSED gint rownum, GType *col_types, GError **error)
508 {
509 gint i;
510 gint fetch_stat;
511 ISC_STATUS status[20];
512 GdaRow* row = NULL;
513 GdaFirebirdPStmt* ps = (GdaFirebirdPStmt *) ((GdaDataSelect *) imodel)->prep_stmt;
514 //WHERE_AM_I;
515 if ((fetch_stat = isc_dsql_fetch(status, &(ps->stmt_h), SQL_DIALECT_V6, ps->sqlda)) == 0) {
516 row = gda_row_new (ps->sqlda->sqld);
517 for (i = 0; i < ps->sqlda->sqld; i++) {
518 GValue *value = gda_row_get_value (row, i);
519 GType type = _gda_firebird_type_to_gda((XSQLVAR *) &(ps->sqlda->sqlvar[i]));
520
521 //IF COLUMN TYPES IS NOT EXPLICITLY SPECIFIED THEN WE
522 //SET THE COLUMN TYPES TO WHAT FIREBIRD RETURNS
523 if (col_types)
524 type = col_types[i];
525 //g_print("col#: %d\n", i);
526 gda_value_reset_with_type (value, type);
527 _fb_set_row_data ((XSQLVAR *) &(ps->sqlda->sqlvar[i]), value, row, type);
528 }
529 rownum++;
530 }
531
532 return row;
533 }
534
535 /*
536 * the @ps struct is modified and transferred to the new data model created in
537 * this function
538 */
539 GdaDataModel *
gda_firebird_recordset_new(GdaConnection * cnc,GdaFirebirdPStmt * ps,GdaSet * exec_params,GdaDataModelAccessFlags flags,GType * col_types)540 gda_firebird_recordset_new (GdaConnection *cnc,
541 GdaFirebirdPStmt *ps,
542 GdaSet *exec_params,
543 GdaDataModelAccessFlags flags,
544 GType *col_types)
545
546 //(GdaConnection *cnc, GdaFirebirdPStmt *ps, GdaDataModelAccessFlags flags, GType *col_types)
547 {
548 GdaFirebirdRecordset *model;
549 FirebirdConnectionData *cdata;
550 gint i;
551 GdaDataModelAccessFlags rflags;
552 //WHERE_AM_I;
553 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
554 g_return_val_if_fail (ps, NULL);
555
556 cdata = (FirebirdConnectionData*) gda_connection_internal_get_provider_data (cnc);
557 if (!cdata)
558 return NULL;
559
560 //g_print("RST-SQL>> %s\n", _GDA_PSTMT (ps)->sql);
561
562 if (ps->sqlda == NULL){
563 g_print("ERROR: ps->sqlda seems to be NULL\n");
564 }
565 /* make sure @ps reports the correct number of columns using the API*/
566 //if (_GDA_PSTMT (ps)->ncols < 0)
567 /*_GDA_PSTMT (ps)->ncols = ...;*/
568 //TO_IMPLEMENT;
569
570 /* completing @ps if not yet done */
571 if (_GDA_PSTMT (ps)->ncols < 0)
572 _GDA_PSTMT (ps)->ncols = ps->sqlda->sqld;
573
574 /* completing @ps if not yet done */
575 if (!_GDA_PSTMT (ps)->types && (_GDA_PSTMT (ps)->ncols > 0)) {
576 /* create prepared statement's columns */
577 GSList *list;
578 for (i = 0; i < _GDA_PSTMT (ps)->ncols; i++)
579 _GDA_PSTMT (ps)->tmpl_columns = g_slist_prepend (_GDA_PSTMT (ps)->tmpl_columns,
580 gda_column_new ());
581 _GDA_PSTMT (ps)->tmpl_columns = g_slist_reverse (_GDA_PSTMT (ps)->tmpl_columns);
582
583 /* create prepared statement's types, all types are initialized to GDA_TYPE_NULL */
584 _GDA_PSTMT (ps)->types = g_new (GType, _GDA_PSTMT (ps)->ncols);
585 for (i = 0; i < _GDA_PSTMT (ps)->ncols; i++)
586 _GDA_PSTMT (ps)->types [i] = GDA_TYPE_NULL;
587
588 if (col_types) {
589 for (i = 0; ; i++) {
590 if (col_types [i] > 0) {
591 if (col_types [i] == G_TYPE_NONE)
592 break;
593 if (i >= _GDA_PSTMT (ps)->ncols)
594 g_warning (_("Column %d out of range (0-%d), ignoring its specified type"), i,
595 _GDA_PSTMT (ps)->ncols - 1);
596 else
597 _GDA_PSTMT (ps)->types [i] = col_types [i];
598 }
599 }
600 }
601
602 /* fill GdaColumn's data */
603 g_print("FB reported %d columns. Gda col-cnt: %d\n", ps->sqlda->sqld, GDA_PSTMT (ps)->ncols);
604 for (i=0, list = _GDA_PSTMT (ps)->tmpl_columns;
605 i < GDA_PSTMT (ps)->ncols;
606 i++, list = list->next) {
607 GdaColumn* column;
608 GType gtype;
609 XSQLVAR* var;
610 /*
611 g_print("\t\tField:%d/%d (fb-cnt=d)\n\t\tSQL-NAME:%s\n\t\tREL-NAME: %s\n\t\tOWN-NAME: %s\n\t\tALIAS: %s\n**************************\n\n"
612 , i
613 , GDA_PSTMT (ps)->ncols
614 //, ps->sqlda->sqld
615 , var->sqlname
616 , var->relname
617 , var->ownname
618 , var->aliasname);
619 */
620 var = (XSQLVAR *) &(ps->sqlda->sqlvar[i]);
621 column = GDA_COLUMN (list->data);
622 /* use C API to set columns' information using gda_column_set_*() */
623 gtype = _gda_firebird_type_to_gda(var);
624 _GDA_PSTMT (ps)->types [i] = gtype;
625 if (col_types)
626 gda_column_set_g_type (column, col_types[i]);
627 else
628 gda_column_set_g_type (column, gtype);
629
630 gda_column_set_name (column, var->aliasname);
631 gda_column_set_description (column, var->aliasname);
632 }
633 }
634
635
636 if (ps->input_sqlda != NULL){
637 g_print("\n\nPRINTING THE INPUT PARAMETERS\n--------------------------\n");
638 for(i =0; i < ps->input_sqlda->sqld; i++){
639 g_print("input-paramater #%d: %s\n", i, (ps->input_sqlda->sqlvar[i].sqldata));
640 g_print("input-len #%d: %d\n", i, ps->input_sqlda->sqlvar[i].sqllen);
641 }
642 }
643
644 //RUN ISC_DSQL_DESCRIBE TO GET OUTPUT FIELDS
645 //isc_dsql_describe(cdata->status, cdata->ftr, &(ps->stmt_h), ps->sqlda);
646
647
648 g_print("isc_dsql_execute\n");
649 /* post init specific code */
650 //if (isc_dsql_execute (cdata->status, cdata->ftr, &(ps->stmt_h), SQL_DIALECT_V6, NULL)) {
651 if (isc_dsql_execute2 (cdata->status, cdata->ftr, &(ps->stmt_h), SQL_DIALECT_V6, ps->input_sqlda, NULL)) {
652 g_print("\nisc error occured: \n");
653 isc_print_status(cdata->status);
654 g_print("\n");
655 }
656
657 isc_dsql_set_cursor_name(cdata->status, &(ps->stmt_h), "dyn_cursor", NULL);
658
659 /* determine access mode: RANDOM or CURSOR FORWARD are the only supported */
660 if (flags & GDA_DATA_MODEL_ACCESS_RANDOM){
661 rflags = GDA_DATA_MODEL_ACCESS_RANDOM;
662 g_print("\nRANDOM ACCESS\n");
663 }
664 else{
665 rflags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD;
666 g_print("CURSOR FORWARD ACCESS\n");
667 }
668 /* create data model */
669 g_print("Creating the data-model\n");
670 model = g_object_new (GDA_TYPE_FIREBIRD_RECORDSET
671 , "connection", cnc
672 , "prepared-stmt", ps
673 , "model-usage", rflags
674 , "exec-params", exec_params
675 , NULL);
676 g_print("point to the connection\n");
677 //model->priv->cnc = cnc;
678 g_print("set the number of columns\n");
679 //model->priv->n_columns = ps->sqlda->sqld;
680 g_print("add reference to connection\n");
681 //g_object_ref (model->priv->cnc);
682 gda_data_select_set_columns (GDA_DATA_SELECT (model), _GDA_PSTMT (ps)->tmpl_columns);
683
684 gint rownum = 0;
685 g_print("populate the model\n");
686 GdaRow *row = NULL;
687 while ((row = new_row_from_firebird_stmt (model, rownum, col_types, NULL)) != NULL) {
688 gda_data_select_take_row ((GdaDataSelect*) model, row, rownum);
689 rownum++;
690 }
691
692 isc_dsql_free_statement(cdata->status, &(ps->stmt_h), DSQL_close);
693
694 g_print("SQL-ROWS >> %d\n", rownum);
695 ((GdaDataSelect *) model)->advertized_nrows = rownum;
696 /*
697 g_print("\n\ncreating a dump of the table\n\n");
698 g_print("%s", gda_data_model_dump_as_string(GDA_DATA_MODEL (model)));
699 g_print("\n\nreturning the data model\n\n");
700 */
701 return GDA_DATA_MODEL (model);
702 }
703
704
705 /*
706 * Get the number of rows in @model, if possible
707 */
708 static gint
gda_firebird_recordset_fetch_nb_rows(GdaDataSelect * model)709 gda_firebird_recordset_fetch_nb_rows (GdaDataSelect *model)
710 {
711 //GdaFirebirdRecordset *imodel;
712 //WHERE_AM_I;
713 //imodel = GDA_FIREBIRD_RECORDSET (model);
714 if (model->advertized_nrows >= 0)
715 return model->advertized_nrows;
716
717 /* use C API to determine number of rows,if possible */
718 TO_IMPLEMENT;
719
720 return model->advertized_nrows;
721 }
722
723 /*
724 * Create a new filled #GdaRow object for the row at position @rownum, and put it into *prow.
725 *
726 * NOTES:
727 * - @prow will NOT be NULL, but *prow WILL be NULL.
728 * - a new #GdaRow object has to be created, corresponding to the @rownum row
729 * - memory management for that new GdaRow object is left to the implementation, which
730 * can use gda_data_select_take_row() to "give" the GdaRow to @model (in this case
731 * this method won't be called anymore for the same @rownum), or may decide to
732 * keep a cache of GdaRow object and "recycle" them.
733 * - implementing this method is MANDATORY if the data model supports random access
734 * - this method is only called when data model is used in random access mode
735 */
736 static gboolean
gda_firebird_recordset_fetch_random(GdaDataSelect * model,GdaRow ** prow,gint rownum,GError ** error)737 gda_firebird_recordset_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
738 {
739 gboolean result = FALSE;
740 GdaFirebirdRecordset* imodel;
741 //WHERE_AM_I;
742 imodel = GDA_FIREBIRD_RECORDSET (model);
743
744 if ((*prow = new_row_from_firebird_stmt (imodel, rownum, NULL, NULL)) != NULL) {
745 result = TRUE;
746 gda_data_select_take_row (model, *prow, rownum);
747 }
748
749 return result;
750 }
751
752 /*
753 * Create and "give" filled #GdaRow object for all the rows in the model
754 */
755 static gboolean
gda_firebird_recordset_store_all(GdaDataSelect * model,GError ** error)756 gda_firebird_recordset_store_all (GdaDataSelect *model, GError **error)
757 {
758 //GdaFirebirdRecordset *imodel;
759 gint i;
760 //WHERE_AM_I;
761 //imodel = GDA_FIREBIRD_RECORDSET (model);
762
763 /* default implementation */
764 for (i = 0; i < model->advertized_nrows; i++) {
765 GdaRow *prow;
766 if (! gda_firebird_recordset_fetch_random (model, &prow, i, error))
767 return FALSE;
768 }
769 return TRUE;
770 }
771
772 /*
773 * Create a new filled #GdaRow object for the next cursor row, and put it into *prow.
774 *
775 * NOTES:
776 * - @prow will NOT be NULL, but *prow WILL be NULL.
777 * - a new #GdaRow object has to be created, corresponding to the @rownum row
778 * - memory management for that new GdaRow object is left to the implementation, which
779 * can use gda_data_select_take_row() to "give" the GdaRow to @model (in this case
780 * this method won't be called anymore for the same @rownum), or may decide to
781 * keep a cache of GdaRow object and "recycle" them.
782 * - implementing this method is MANDATORY
783 * - this method is only called when data model is used in cursor access mode
784 */
785 static gboolean
gda_firebird_recordset_fetch_next(GdaDataSelect * model,GdaRow ** prow,gint rownum,GError ** error)786 gda_firebird_recordset_fetch_next (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
787 {
788 gboolean result = FALSE;
789 GdaFirebirdRecordset* imodel;
790 //WHERE_AM_I;
791 imodel = GDA_FIREBIRD_RECORDSET (model);
792
793 if ((*prow = new_row_from_firebird_stmt (imodel, rownum, NULL, NULL)) != NULL) {
794 result = TRUE;
795 gda_data_select_take_row (model, *prow, rownum);
796 }
797
798 return result;
799 }
800
801 /*
802 * Create a new filled #GdaRow object for the previous cursor row, and put it into *prow.
803 *
804 * NOTES:
805 * - @prow will NOT be NULL, but *prow WILL be NULL.
806 * - a new #GdaRow object has to be created, corresponding to the @rownum row
807 * - memory management for that new GdaRow object is left to the implementation, which
808 * can use gda_data_select_take_row() to "give" the GdaRow to @model (in this case
809 * this method won't be called anymore for the same @rownum), or may decide to
810 * keep a cache of GdaRow object and "recycle" them.
811 * - implementing this method is OPTIONAL (in this case the data model is assumed not to
812 * support moving iterators backward)
813 * - this method is only called when data model is used in cursor access mode
814 */
815 static gboolean
gda_firebird_recordset_fetch_prev(GdaDataSelect * model,GdaRow ** prow,gint rownum,GError ** error)816 gda_firebird_recordset_fetch_prev (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
817 {
818 gboolean result = FALSE;
819 GdaFirebirdRecordset* imodel;
820 //WHERE_AM_I;
821 imodel = GDA_FIREBIRD_RECORDSET (model);
822
823 if ((*prow = new_row_from_firebird_stmt (imodel, rownum, NULL, NULL)) != NULL) {
824 result = TRUE;
825 gda_data_select_take_row (model, *prow, rownum);
826 }
827
828 return result;
829
830 }
831
832 /*
833 * Create a new filled #GdaRow object for the cursor row at position @rownum, and put it into *prow.
834 *
835 * NOTES:
836 * - @prow will NOT be NULL, but *prow WILL be NULL.
837 * - a new #GdaRow object has to be created, corresponding to the @rownum row
838 * - memory management for that new GdaRow object is left to the implementation, which
839 * can use gda_data_select_take_row() to "give" the GdaRow to @model (in this case
840 * this method won't be called anymore for the same @rownum), or may decide to
841 * keep a cache of GdaRow object and "recycle" them.
842 * - implementing this method is OPTIONAL and usefull only if there is a method quicker
843 * than iterating one step at a time to the correct position.
844 * - this method is only called when data model is used in cursor access mode
845 */
846 static gboolean
gda_firebird_recordset_fetch_at(GdaDataSelect * model,GdaRow ** prow,gint rownum,GError ** error)847 gda_firebird_recordset_fetch_at (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
848 {
849 gboolean result = FALSE;
850 GdaFirebirdRecordset* imodel;
851 //WHERE_AM_I;
852 imodel = GDA_FIREBIRD_RECORDSET (model);
853
854 if ((*prow = new_row_from_firebird_stmt (imodel, rownum, NULL, NULL)) != NULL) {
855 result = TRUE;
856 gda_data_select_take_row (model, *prow, rownum);
857 }
858
859 return result;
860
861 }
862
863