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 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 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 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 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 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 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, ERR_load_ASN1_strings(void)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 * 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 * 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 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 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 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 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 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 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