1 /* Copyright (C) 2000-2015 Lavtech.com corp. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2 of the License, or
6 (at your option) any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18 #include "udm_config.h"
19 #if HAVE_IBASE
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/types.h>
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27
28 #include "udm_common.h"
29 #include "udm_sqldbms.h"
30 #include "udm_utils.h"
31 #include "udm_vars.h"
32
33 #include "udm_xmalloc.h"
34 #ifdef WIN32
35 #include <process.h>
36 #endif
37
38 #include <ibase.h>
39
40 #define SQL_VARCHAR(len) struct {short vary_length; char vary_string[(len)+1];}
41 typedef struct
42 {
43 short len;
44 char str[1];
45 } UDM_IBASE_VARY;
46
47 #define UDM_IBASE_MAX_BIND_PARAM UDM_SQL_MAX_BIND_PARAM
48
49 typedef struct
50 {
51 isc_stmt_handle query_handle; /* query handle */
52 long query_type; /* SELECT or UPDATE, etc */
53 XSQLDA in_sqlda;
54 XSQLVAR dummy_vars[UDM_IBASE_MAX_BIND_PARAM]; /* Must be after in_sqlda */
55 size_t long_data_lengths[UDM_IBASE_MAX_BIND_PARAM]; /* For data >64K */
56 } UDM_IB_STMT;
57
58
59 typedef struct
60 {
61 isc_db_handle DBH; /* database handle */
62 ISC_STATUS status[20]; /* status vector */
63 isc_tr_handle tr_handle; /* transaction handle */
64 int autocommit;
65 UDM_IB_STMT stmt;
66 } UDM_IB;
67
68
69 static UDM_IB *
UdmIB(UDM_SQL * db)70 UdmIB(UDM_SQL *db)
71 {
72 return (UDM_IB*) db->specific;
73 }
74
75
76 static void
UdmSetErrorCode(UDM_SQL * db,int errcode)77 UdmSetErrorCode(UDM_SQL *db, int errcode)
78 {
79 db->errcode= errcode;
80 }
81
82 static udm_rc_t
UdmIBStmtFreeInternal(UDM_SQL * db,UDM_IB_STMT * stmt)83 UdmIBStmtFreeInternal(UDM_SQL *db, UDM_IB_STMT *stmt)
84 {
85 UDM_IB *ib= UdmIB(db);
86 if (isc_dsql_free_statement(ib->status, &stmt->query_handle, DSQL_drop))
87 {
88 UdmSetErrorCode(db, 1);
89 return UDM_ERROR;
90 }
91 return UDM_OK;
92 }
93
94
95 #ifndef FB_API_VER
96 #pragma GCC diagnostic push
97 #pragma GCC diagnostic ignored "-Wcast-qual"
98 ISC_LONG ISC_EXPORT
fb_interpret(ISC_SCHAR * dst,unsigned int dstlen,const ISC_STATUS ** st)99 fb_interpret(ISC_SCHAR *dst, unsigned int dstlen, const ISC_STATUS **st)
100 {
101 return isc_interprete(dst, (ISC_STATUS **) st);
102 }
103 #pragma GCC diagnostic pop
104 #endif
105
106
107 static void
UdmIBaseDisplayError(UDM_SQL * db,const char * fname)108 UdmIBaseDisplayError(UDM_SQL *db, const char *fname)
109 {
110 size_t slen;
111 char *s= db->errstr;
112 UDM_IB *ib= UdmIB(db);
113 const ISC_STATUS *ibstatus= ib->status;
114 ISC_LONG len;
115
116 s+= udm_snprintf(s, sizeof(db->errstr), "%s: ", fname);
117 slen= sizeof(db->errstr) - (s - db->errstr) - 1;
118 for( ; (len= fb_interpret(s , slen, &ibstatus)); )
119 {
120 s+= len;
121 *s++= ' ';
122 *s= '\0';
123 slen= sizeof(db->errstr) - (s - db->errstr) - 1;
124 }
125 }
126
127 static udm_rc_t
UdmIBaseConnect(UDM_SQL * db)128 UdmIBaseConnect(UDM_SQL *db)
129 {
130 char dpb_buffer[256], *dpb, *e;
131 const char *p;
132 int dpb_length, len;
133 char connect_string[256];
134 const char* DBUser= UdmVarListFindStr(&db->Vars,"DBUser",NULL);
135 const char* DBPass= UdmVarListFindStr(&db->Vars,"DBPass",NULL);
136 const char* DBHost= UdmVarListFindStr(&db->Vars, "DBHost", "localhost");
137 const char* DBName= UdmVarListFindStr(&db->Vars, "DBName", "");
138 UDM_IB *ib= (UDM_IB*) malloc(sizeof(UDM_IB));
139 bzero(ib, sizeof(*ib));
140 db->specific= (void*) ib;
141
142 ib->autocommit= 1;
143 dpb = dpb_buffer;
144 *dpb++ = isc_dpb_version1;
145
146 if (DBUser != NULL && (len = strlen(DBUser)))
147 {
148 *dpb++ = isc_dpb_user_name;
149 *dpb++ = len;
150 for (p = DBUser; *p;)
151 *dpb++ = *p++;
152 }
153 if (DBPass != NULL && (len = strlen(DBPass)))
154 {
155 *dpb++ = isc_dpb_password;
156 *dpb++ = len;
157 for (p = DBPass; *p;)
158 *dpb++ = *p++;
159 }
160 /*
161 if (charset != NULL && (len = strlen(charset))) {
162 *dpb++ = isc_dpb_lc_ctype;
163 *dpb++ = strlen(charset);
164 for (p = charset; *p;) {
165 *dpb++ = *p++;
166 }
167 }
168 #ifdef isc_dpb_sql_role_name
169 if (role != NULL && (len = strlen(role))) {
170 *dpb++ = isc_dpb_sql_role_name;
171 *dpb++ = strlen(role);
172 for (p = role; *p;) {
173 *dpb++ = *p++;
174 }
175 }
176 #endif
177 */
178
179 dpb_length = dpb - dpb_buffer;
180
181 if(strcmp(DBHost,"localhost"))
182 udm_snprintf(connect_string,sizeof(connect_string)-1,"%s:%s",DBHost, DBName);
183 else
184 udm_snprintf(connect_string,sizeof(connect_string)-1,"%s", DBName);
185
186 /* Remove possible trailing slash */
187 e= connect_string+strlen(connect_string);
188 if (e>connect_string && e[-1]=='/')
189 e[-1]='\0';
190
191 #ifdef DEBUG_SQL
192 fprintf(stderr, "SQL Connect to: '%s'\n",connect_string);
193 #endif
194 if(isc_attach_database(ib->status, strlen(connect_string), connect_string,
195 &(ib->DBH), dpb_length, dpb_buffer))
196 {
197 UdmSetErrorCode(db, 1);
198 return UDM_ERROR;
199 }
200
201 /*
202 http://www.firebirdfaq.org/faq223/
203 To obtain the server version, use isc_info_svc_server_version() API func.
204 It does not work for Firebird Classic 1.0, so if you don't get an answer
205 you'll know it's Firebird Classic 1.0 or InterBase Classic 6.0.
206 Otherwise it returns a string like this:
207 LI-V2.0.0.12748 Firebird 2.0
208 or...
209 LI-V1.5.3.4870 Firebird 1.5
210
211 If you use Firebird 2.1 (and higher), you can also use:
212 SELECT rdb$get_context('SYSTEM', 'ENGINE_VERSION')
213 from rdb$database;
214 */
215 return UDM_OK;
216 }
217
218
219 static udm_rc_t
UdmIBaseClose(UDM_SQL * db)220 UdmIBaseClose(UDM_SQL *db)
221 {
222 UDM_IB *ib= UdmIB(db);
223 if (db->connected)
224 {
225 if (isc_detach_database(ib->status, &(ib->DBH)))
226 UdmSetErrorCode(db, 1);
227 UDM_FREE(db->specific);
228 }
229 return UDM_OK;
230 }
231
232
233 static udm_rc_t
UdmIBPrepareInternal(UDM_SQL * db,UDM_IB_STMT * stmt,const char * query)234 UdmIBPrepareInternal(UDM_SQL *db, UDM_IB_STMT *stmt, const char *query)
235 {
236 UDM_IB *ib= UdmIB(db);
237 char query_info[] = { isc_info_sql_stmt_type };
238 char info_buffer[18];
239 udm_bool_t tr_started= UDM_FALSE;
240
241 stmt->query_handle= 0;
242 stmt->in_sqlda.sqln= 0;
243 stmt->in_sqlda.sqld= 0;
244 stmt->in_sqlda.version= SQLDA_VERSION1;
245
246 if(!ib->tr_handle)
247 {
248 if (isc_start_transaction(ib->status, &ib->tr_handle, 1,
249 &ib->DBH, 0, NULL))
250 {
251 UdmIBaseDisplayError(db, "isc_start_transaction");
252 goto err;
253 }
254 tr_started= UDM_TRUE;
255 ib->autocommit=1;
256 }
257 else
258 {
259 ib->autocommit=0;
260 }
261
262
263 if (isc_dsql_allocate_statement(ib->status, &ib->DBH, &stmt->query_handle))
264 {
265 UdmIBaseDisplayError(db, "isc_dsql_allocate_statement");
266 goto err;
267 }
268 if (isc_dsql_prepare(ib->status, &ib->tr_handle, &stmt->query_handle,
269 0, query, 1, NULL))
270 {
271 UdmIBaseDisplayError(db, "isc_dsql_prepare");
272 goto err;
273 }
274 if (!isc_dsql_sql_info(ib->status, &stmt->query_handle,
275 sizeof(query_info), query_info,
276 sizeof(info_buffer), info_buffer))
277 {
278 short l;
279 l= (short) isc_vax_integer((char ISC_FAR *) info_buffer + 1, 2);
280 stmt->query_type= isc_vax_integer((char ISC_FAR *) info_buffer + 3, l);
281 }
282
283 return UDM_OK;
284
285 err:
286 if (tr_started)
287 {
288 ISC_STATUS status[20]; /* Not to override db->status */
289 isc_rollback_transaction(status, &ib->tr_handle);
290 ib->tr_handle= 0;
291 }
292 UdmSetErrorCode(db, 1);
293 return UDM_ERROR;
294 }
295
296
297 static udm_bool_t
is_duplicate_error(UDM_SQL * db)298 is_duplicate_error(UDM_SQL *db)
299 {
300 if (strstr(db->errstr,"uplicat") ||
301 strstr(db->errstr,"UNIQUE"))
302 return UDM_TRUE;
303 return UDM_FALSE;
304 }
305
306 static udm_rc_t
UdmIBExecInternal(UDM_SQL * db,UDM_SQLRES * res,UDM_IB_STMT * stmt,int free_stmt)307 UdmIBExecInternal(UDM_SQL *db, UDM_SQLRES *res, UDM_IB_STMT *stmt, int free_stmt)
308 {
309 UDM_IB *ib= UdmIB(db);
310 ISC_STATUS status[20]; /* To not override db->status */
311
312 /* Find out what kind of query is to be executed */
313 if (stmt->query_type == isc_info_sql_stmt_select ||
314 stmt->query_type == isc_info_sql_stmt_select_for_upd)
315 {
316 XSQLDA *osqlda=NULL;
317 long fetch_stat;
318 int i;
319 short sqlind_array[128];
320
321 /* Select, need to allocate output sqlda and and prepare it for use */
322 osqlda = (XSQLDA *) UdmXmalloc(XSQLDA_LENGTH(0));
323 osqlda->sqln = 0;
324 osqlda->version = SQLDA_VERSION1;
325
326 /* Fetch column information */
327 if (isc_dsql_describe(ib->status, &stmt->query_handle, 1, osqlda))
328 {
329 UDM_FREE(osqlda);
330 UdmSetErrorCode(db, 1);
331 isc_rollback_transaction(status, &ib->tr_handle);
332 return UDM_ERROR;
333 }
334
335 if (osqlda->sqld)
336 {
337 osqlda = (XSQLDA *) UdmXrealloc(osqlda, XSQLDA_LENGTH(osqlda->sqld));
338 osqlda->sqln = osqlda->sqld;
339 osqlda->version = SQLDA_VERSION1;
340 if (isc_dsql_describe(ib->status, &stmt->query_handle, 1, osqlda))
341 {
342 UDM_FREE(osqlda);
343 UdmSetErrorCode(db, 1);
344 isc_rollback_transaction(status, &ib->tr_handle);
345 return UDM_ERROR;
346 }
347 }
348
349 if (!res)
350 {
351 UdmSetErrorCode(db, 1);
352 udm_snprintf(db->errstr, sizeof(db->errstr)-1,
353 "ibase_query with empty 'res' returned rows");
354 return UDM_ERROR;
355 }
356
357 res->nCols = osqlda->sqld;
358 res->Fields= (UDM_SQLFIELD*)UdmXmalloc(res->nCols*sizeof(UDM_SQLFIELD));
359
360 for (i = 0; i < osqlda->sqld; i++)
361 {
362 XSQLVAR *var= &osqlda->sqlvar[i];
363 int coltype= osqlda->sqlvar[i].sqltype & ~1;
364
365 var->sqlind= &sqlind_array[i];
366 var->sqlind[0]= 0;
367 res->Fields[i].sqlname= (char*)UdmStrdup(var->aliasname[0] ? var->aliasname : var->sqlname);
368 res->Fields[i].sqllen= var->sqllen;
369
370 switch(coltype)
371 {
372 case SQL_SHORT:
373 var->sqldata = (char*)UdmMalloc(sizeof(short));
374 break;
375 case SQL_LONG:
376 var->sqldata = (char*)UdmMalloc(sizeof(ISC_LONG));
377 break;
378 case SQL_FLOAT:
379 var->sqldata = (char*)UdmMalloc(sizeof(float));
380 break;
381 case SQL_DOUBLE:
382 var->sqldata = (char*)UdmMalloc(sizeof(double));
383 break;
384 case SQL_DATE:
385 case SQL_BLOB:
386 case SQL_ARRAY:
387 var->sqldata = (char*)UdmMalloc(sizeof(ISC_QUAD));
388 break;
389 case SQL_TEXT:
390 var->sqldata = (char*)UdmMalloc((size_t)(osqlda->sqlvar[i].sqllen));
391 break;
392 case SQL_VARYING:
393 osqlda->sqlvar[i].sqldata = (char*)UdmMalloc((size_t)(osqlda->sqlvar[i].sqllen+sizeof(short)));
394 break;
395 }
396 }
397
398 if (isc_dsql_execute(ib->status, &ib->tr_handle, &stmt->query_handle, 1, NULL))
399 {
400 UDM_FREE(osqlda);
401 UdmSetErrorCode(db, 1);
402 isc_rollback_transaction(status, &ib->tr_handle);
403 return UDM_ERROR;
404 }
405
406 while ((fetch_stat= isc_dsql_fetch(ib->status, &stmt->query_handle, 1, osqlda)) == 0)
407 {
408 res->Items= (UDM_STR *)UdmRealloc(res->Items,(res->nRows+1)*(res->nCols)*sizeof(UDM_STR));
409
410 for(i=0;i<osqlda->sqld; i++)
411 {
412 UDM_IBASE_VARY *vary;
413 char shortdata[64];
414 XSQLVAR *var=osqlda->sqlvar+i;
415 char *p=NULL;
416 size_t len;
417
418 if(*var->sqlind==-1) /* NULL data */
419 {
420 p= (char*)UdmStrdup("");
421 len= 0;
422 }
423 else
424 switch(var->sqltype & ~1)
425 {
426 case SQL_TEXT:
427 p=(char*)UdmMalloc((size_t)(var->sqllen+1));
428 strncpy(p,(char*)var->sqldata,(size_t)(var->sqllen));
429 p[var->sqllen]='\0';
430 len= var->sqllen;
431 break;
432 case SQL_VARYING:
433 vary=(UDM_IBASE_VARY*)var->sqldata;
434 p=(char*)UdmMalloc((size_t)(vary->len+1));
435 strncpy(p,vary->str,(size_t)(vary->len));
436 p[vary->len]='\0';
437 len= vary->len;
438 break;
439 case SQL_LONG:
440 /* SQL_LONG is in fact int4 on both x86 and x86_64 */
441 len= sprintf(shortdata,"%d", (int) (*(ISC_LONG*) (var->sqldata)));
442 p = (char*)UdmStrdup(shortdata);
443 break;
444 case SQL_SHORT:
445 len= sprintf(shortdata,"%d",*(short*)(var->sqldata));
446 p = (char*)UdmStrdup(shortdata);
447 break;
448 case SQL_FLOAT:
449 len= sprintf(shortdata,"%f",*(float*)(var->sqldata));
450 p = (char*)UdmStrdup(shortdata);
451 break;
452 case SQL_DOUBLE:
453 len= sprintf(shortdata,"%f",*(double*)(var->sqldata));
454 p = (char*)UdmStrdup(shortdata);
455 break;
456 case SQL_BLOB:
457 {
458 isc_blob_handle blob_handle= 0;
459 unsigned short blob_seg_len, blob_segment_size= 32*1024;
460 char blob_items[]= {isc_info_blob_total_length };
461 char res_buffer[20], *res_buffer_ptr;
462 size_t blob_length= 0;
463
464 len= 0;
465 p= NULL;
466
467 /* Open the blob with the fetched blob_id. */
468 if (isc_open_blob(status, &ib->DBH, &ib->tr_handle,
469 &blob_handle, (ISC_QUAD*)var->sqldata))
470 {
471 /* isc_print_status(status); */
472 len= sprintf(shortdata, "<isc_open_blob failed>");
473 p= (char*) UdmStrdup(shortdata);
474 break;
475 }
476
477 /* Get blob info */
478 isc_blob_info(status, &blob_handle,
479 sizeof(blob_items), blob_items,
480 sizeof(res_buffer), res_buffer);
481 if (status[0] == 1 && status[1])
482 {
483 /* isc_print_status(status);*/
484 len= sprintf(shortdata, "<isc_blob_info failed>");
485 p= (char*) UdmStrdup(shortdata);
486 goto blob_close;
487 }
488
489 /* Parse blob info data */
490 for (res_buffer_ptr= res_buffer; *res_buffer_ptr != isc_info_end; )
491 {
492 char item= *res_buffer_ptr++;
493 if (item == isc_info_blob_total_length)
494 {
495 int length= isc_vax_integer(res_buffer_ptr, 2);
496 res_buffer_ptr+= 2;
497 blob_length= isc_vax_integer(res_buffer_ptr, length);
498 res_buffer_ptr+= length;
499 }
500 }
501
502 p= (char*) UdmMalloc(blob_length + 1);
503
504 while (isc_get_segment(status, &blob_handle, &blob_seg_len,
505 blob_segment_size, p + len) == 0 ||
506 status[1] == isc_segment)
507 {
508 len+= blob_seg_len;
509 }
510
511 p[len]= '\0';
512
513 if (status[1] != isc_segstr_eof)
514 {
515 len= sprintf(shortdata, "<isc_get_segment failed>");
516 p= (char*) UdmStrdup(shortdata);
517 break;
518 }
519 blob_close:
520 if (isc_close_blob(status, &blob_handle))
521 {
522 len= sprintf(shortdata, "<isc_close_blob failed>");
523 p= (char*) UdmStrdup(shortdata);
524 break;
525 }
526 }
527 break;
528 default:
529 len= sprintf(shortdata,"Unknown SQL type %d", var->sqltype & ~1);
530 p= (char*)UdmStrdup(shortdata);
531 break;
532 }
533 /*UdmRTrim(p," ");*/
534 res->Items[res->nRows*res->nCols+i].str= p;
535 res->Items[res->nRows*res->nCols+i].length= len;
536 }
537 res->nRows++;
538 if (db->res_limit && res->nRows >= db->res_limit)
539 {
540 fetch_stat = 100L;
541 break;
542 }
543 }
544
545 db->res_limit= 0;
546
547 /* Free fetch buffers */
548 for (i = 0; i < osqlda->sqld; i++)
549 UDM_FREE(osqlda->sqlvar[i].sqldata);
550
551 UDM_FREE(osqlda);
552
553 if (fetch_stat != 100L)
554 {
555 UdmSetErrorCode(db, 1);
556 isc_rollback_transaction(status, &ib->tr_handle);
557 return UDM_ERROR;
558 }
559 }
560 else
561 {
562 /* Not select */
563 if (isc_dsql_execute(ib->status, &ib->tr_handle, &stmt->query_handle, 1,
564 &stmt->in_sqlda))
565 {
566 UdmIBaseDisplayError(db, "isc_dsql_execute");
567 if (!is_duplicate_error(db))
568 {
569 ib->autocommit= 1;
570 UdmSetErrorCode(db, 1);
571 isc_rollback_transaction(status, &ib->tr_handle);
572 if (free_stmt)
573 UdmIBStmtFreeInternal(db, stmt);
574 return UDM_ERROR;
575 }
576 }
577 }
578
579 if (free_stmt && UDM_OK != UdmIBStmtFreeInternal(db, stmt))
580 {
581 UdmSetErrorCode(db, 1);
582 isc_rollback_transaction(status, &ib->tr_handle);
583 return UDM_ERROR;
584 }
585
586 if(ib->autocommit)
587 {
588 if (isc_commit_transaction(ib->status, &ib->tr_handle))
589 {
590 UdmSetErrorCode(db, 1);
591 ib->tr_handle= 0;
592 return UDM_ERROR;
593 }
594 ib->tr_handle= 0;
595 }
596
597 return UDM_OK;
598 }
599
600
601 /*
602 Create a BLOB, write data to it, and return BLOB id
603 */
604 static udm_rc_t
UdmIBCreateBlob(UDM_IB * ib,const char * blob_data,size_t blob_length,ISC_QUAD * blob_id)605 UdmIBCreateBlob(UDM_IB *ib, const char *blob_data, size_t blob_length,
606 ISC_QUAD *blob_id)
607 {
608 isc_blob_handle blob_handle= 0;
609 unsigned short seg_max_length = 32*1024;
610
611 if (isc_create_blob(ib->status, &ib->DBH, &ib->tr_handle, &blob_handle, blob_id))
612 return UDM_ERROR;
613
614 while (blob_length)
615 {
616 unsigned short blob_seg_length= blob_length > seg_max_length ?
617 seg_max_length : blob_length;
618 if (isc_put_segment(ib->status, &blob_handle, blob_seg_length, blob_data))
619 return UDM_ERROR;
620 blob_data+= blob_seg_length;
621 blob_length-= blob_seg_length;
622 }
623
624 if (isc_close_blob(ib->status, &blob_handle))
625 return UDM_ERROR;
626
627 return UDM_OK;
628 }
629
630
631 static udm_rc_t
UdmIBExec(UDM_SQL * db)632 UdmIBExec(UDM_SQL *db)
633 {
634 UDM_IB *ib= UdmIB(db);
635 UDM_IB_STMT *stmt= &ib->stmt;
636 ISC_QUAD blob_ids[UDM_IBASE_MAX_BIND_PARAM];
637 ISC_SHORT i;
638 for (i= 0; i < stmt->in_sqlda.sqln; i++)
639 {
640 XSQLVAR *var= &stmt->in_sqlda.sqlvar[i];
641 if ((var->sqltype & ~1) == SQL_BLOB)
642 {
643 size_t blob_length= stmt->long_data_lengths[i];
644 if (UDM_OK != UdmIBCreateBlob(ib, var->sqldata, blob_length, &blob_ids[i]))
645 {
646 UdmIBaseDisplayError(db, "UdmIBCreateBlob");
647 UdmSetErrorCode(db, 1);
648 return UDM_ERROR;
649 }
650 var->sqldata= (char*) &blob_ids[i];
651 var->sqllen= sizeof(ISC_QUAD);
652 }
653 }
654
655 return UdmIBExecInternal(db, NULL, &ib->stmt, 0);
656 }
657
658
659 static udm_rc_t
sql_ibase_query(UDM_SQL * db,UDM_SQLRES * res,const char * query)660 sql_ibase_query(UDM_SQL *db, UDM_SQLRES *res, const char *query)
661 {
662 udm_rc_t rc= UDM_OK;
663 UDM_IB *ib;
664 UDM_IB_STMT stmt;
665
666 if (!db->connected)
667 {
668 UdmIBaseConnect(db);
669 if(db->errcode)
670 {
671 UdmIBaseDisplayError(db, "UdmIBaseConnect");
672 UdmSetErrorCode(db, 1);
673 return UDM_ERROR;
674 }
675 else
676 {
677 db->connected= UDM_TRUE;
678 }
679 }
680
681 ib= UdmIB(db);
682
683 if(!strcmp(query,"BEGIN"))
684 {
685 if(!ib->tr_handle)
686 {
687 if (isc_start_transaction(ib->status, &ib->tr_handle, 1,
688 &(ib->DBH), 0, NULL))
689 {
690 UdmSetErrorCode(db, 1);
691 UdmIBaseDisplayError(db, "isc_start_transaction");
692 rc= UDM_ERROR;
693 }
694 ib->autocommit= 0;
695 }
696 else
697 {
698 ib->autocommit= 1;
699 UdmSetErrorCode(db, 1);
700 udm_snprintf(db->errstr,sizeof(db->errstr),"Wrong call order: begin");
701 rc= UDM_ERROR;
702 }
703 return rc;
704 }
705
706 if(!strcmp(query,"COMMIT"))
707 {
708 if(ib->tr_handle)
709 {
710 if (isc_commit_transaction(ib->status, &ib->tr_handle))
711 {
712 UdmSetErrorCode(db, 1);
713 UdmIBaseDisplayError(db, "isc_commit_transaction");
714 rc= UDM_ERROR;
715 }
716 ib->tr_handle= 0;
717 ib->autocommit= 1;
718 }
719 else
720 {
721 ib->autocommit= 1;
722 UdmSetErrorCode(db, 1);
723 udm_snprintf(db->errstr,sizeof(db->errstr),"Wrong call order: commit");
724 rc= UDM_ERROR;
725 }
726 return rc;
727 }
728
729 if (UdmIBPrepareInternal(db, &stmt, query))
730 return UDM_ERROR;
731
732 if (UdmIBExecInternal(db, res, &stmt, 1))
733 return UDM_ERROR;
734
735 return rc;
736 }
737
738
739 static udm_rc_t
UdmIBaseQuery(UDM_SQL * db,UDM_SQLRES * res,const char * query)740 UdmIBaseQuery(UDM_SQL *db, UDM_SQLRES *res, const char *query)
741 {
742 udm_rc_t rc;
743 UdmSetErrorCode(db, 0);
744
745 if (res)
746 {
747 bzero((void*) res, sizeof(UDM_SQLRES));
748 res->db= db;
749 }
750
751 if(UDM_OK != (rc= sql_ibase_query(db,res,query)))
752 {
753 if (is_duplicate_error(db))
754 {
755 UdmSetErrorCode(db, 0);
756 rc= UDM_OK;
757 }
758 else
759 {
760 /*strcat(db->errstr," ");
761 strcat(db->errstr,query);*/
762 }
763 return rc;
764 }
765 return rc;
766 }
767
768
769 static udm_rc_t
UdmIBBegin(UDM_SQL * db)770 UdmIBBegin(UDM_SQL *db)
771 {
772 return UdmIBaseQuery(db,NULL,"BEGIN");
773 }
774
775
776 static udm_rc_t
UdmIBCommit(UDM_SQL * db)777 UdmIBCommit(UDM_SQL *db)
778 {
779 return UdmIBaseQuery(db,NULL,"COMMIT");
780 }
781
782
783 static int
UdmSQLType2IBType(udm_sqltype_t udm_type)784 UdmSQLType2IBType(udm_sqltype_t udm_type)
785 {
786 switch (udm_type)
787 {
788 case UDM_SQLTYPE_INT32: return SQL_LONG;
789 case UDM_SQLTYPE_LONGVARBINARY: return SQL_BLOB;
790 case UDM_SQLTYPE_LONGVARCHAR: return SQL_TEXT;
791 case UDM_SQLTYPE_VARCHAR: return SQL_TEXT;
792 case UDM_SQLTYPE_UNKNOWN: break;
793 }
794 return SQL_TEXT;
795 }
796
797
798 static int short flag0= 0;
799
800
801 static udm_rc_t
UdmIBPrepare(UDM_SQL * db,const char * query)802 UdmIBPrepare(UDM_SQL *db, const char *query)
803 {
804 UDM_IB *ib= UdmIB(db);
805 return UdmIBPrepareInternal(db, &ib->stmt, query);
806 }
807
808 static udm_rc_t
UdmIBBind(UDM_SQL * db,int position,const void * data,int size,udm_sqltype_t type)809 UdmIBBind(UDM_SQL *db, int position, const void *data, int size, udm_sqltype_t type)
810 {
811 UDM_IB *ib= UdmIB(db);
812 UDM_IB_STMT *stmt= &ib->stmt;
813 XSQLVAR *var= &stmt->in_sqlda.sqlvar[position - 1];
814 if (stmt->in_sqlda.sqln < position)
815 {
816 stmt->in_sqlda.sqln= position;
817 stmt->in_sqlda.sqld= position;
818 }
819 #ifdef HAVE_GCC_PRAGMA_PUSH
820 #pragma GCC diagnostic push
821 #pragma GCC diagnostic ignored "-Wcast-qual"
822 #endif
823 var->sqldata= (char*) data;
824 #ifdef HAVE_GCC_PRAGMA_PUSH
825 #pragma GCC diagnostic pop
826 #endif
827 var->sqllen= size;
828 var->sqltype= UdmSQLType2IBType(type) + 1;
829 var->sqlind= &flag0;
830 stmt->long_data_lengths[position - 1]= (size_t) size;
831 return UDM_OK;
832 }
833
834
835 static udm_rc_t
UdmIBStmtFree(UDM_SQL * db)836 UdmIBStmtFree(UDM_SQL *db)
837 {
838 UDM_IB *ib= UdmIB(db);
839 return UdmIBStmtFreeInternal(db, &ib->stmt);
840 }
841
842
843 const UDM_SQLDB_HANDLER udm_sqldb_ibase_handler =
844 {
845 UdmSQLEscStrGeneric,
846 UdmIBaseQuery,
847 UdmIBaseConnect,
848 UdmIBaseClose,
849 UdmIBBegin,
850 UdmIBCommit,
851 UdmIBPrepare,
852 UdmIBBind,
853 UdmIBExec,
854 UdmIBStmtFree,
855 UdmSQLFetchRowSimple,
856 UdmSQLStoreResultSimple,
857 UdmSQLFreeResultSimple,
858 UdmIBaseQuery,
859 NULL, /* RenameTable */
860 NULL, /* CopyStrucuture */
861 UdmSQLLockOrBeginGeneric,
862 UdmSQLUnlockOrCommitGeneric,
863 };
864
865 #endif
866