1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2013 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Ard Biesheuvel <abies@php.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 /* $Id$ */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "php.h"
26 #include "php_ini.h"
27 #include "ext/standard/info.h"
28 #include "pdo/php_pdo.h"
29 #include "pdo/php_pdo_driver.h"
30 #include "php_pdo_firebird.h"
31 #include "php_pdo_firebird_int.h"
32
33 #include <time.h>
34
35 #define RECORD_ERROR(stmt) _firebird_error(NULL, stmt, __FILE__, __LINE__ TSRMLS_CC)
36
37 /* free the allocated space for passing field values to the db and back */
free_sqlda(XSQLDA const * sqlda)38 static void free_sqlda(XSQLDA const *sqlda) /* {{{ */
39 {
40 int i;
41
42 for (i = 0; i < sqlda->sqld; ++i) {
43 XSQLVAR const *var = &sqlda->sqlvar[i];
44
45 if (var->sqlind) {
46 efree(var->sqlind);
47 }
48 }
49 }
50 /* }}} */
51
52 /* called by PDO to clean up a statement handle */
firebird_stmt_dtor(pdo_stmt_t * stmt TSRMLS_DC)53 static int firebird_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
54 {
55 pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data;
56 int result = 1, i;
57
58 /* release the statement */
59 if (isc_dsql_free_statement(S->H->isc_status, &S->stmt, DSQL_drop)) {
60 RECORD_ERROR(stmt);
61 result = 0;
62 }
63
64 /* clean up the fetch buffers if they have been used */
65 for (i = 0; i < S->out_sqlda.sqld; ++i) {
66 if (S->fetch_buf[i]) {
67 efree(S->fetch_buf[i]);
68 }
69 }
70 efree(S->fetch_buf);
71
72 zend_hash_destroy(S->named_params);
73 FREE_HASHTABLE(S->named_params);
74
75 /* clean up the input descriptor */
76 if (S->in_sqlda) {
77 free_sqlda(S->in_sqlda);
78 efree(S->in_sqlda);
79 }
80
81 free_sqlda(&S->out_sqlda);
82 efree(S);
83
84 return result;
85 }
86 /* }}} */
87
88 /* called by PDO to execute a prepared query */
firebird_stmt_execute(pdo_stmt_t * stmt TSRMLS_DC)89 static int firebird_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
90 {
91 pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data;
92 pdo_firebird_db_handle *H = S->H;
93 unsigned long affected_rows = 0;
94 static char info_count[] = {isc_info_sql_records};
95 char result[64];
96
97 do {
98 /* named or open cursors should be closed first */
99 if ((*S->name || S->cursor_open) && isc_dsql_free_statement(H->isc_status, &S->stmt, DSQL_close)) {
100 break;
101 }
102 S->cursor_open = 0;
103 /* assume all params have been bound */
104
105 if (isc_dsql_execute(H->isc_status, &H->tr, &S->stmt, PDO_FB_SQLDA_VERSION, S->in_sqlda)) {
106 break;
107 }
108
109 /* Determine how many rows have changed. In this case we are
110 * only interested in rows changed, not rows retrieved. That
111 * should be handled by the client when fetching. */
112 stmt->row_count = affected_rows;
113
114 switch (S->statement_type) {
115 case isc_info_sql_stmt_insert:
116 case isc_info_sql_stmt_update:
117 case isc_info_sql_stmt_delete:
118 case isc_info_sql_stmt_exec_procedure:
119 if (isc_dsql_sql_info(H->isc_status, &S->stmt, sizeof ( info_count),
120 info_count, sizeof(result), result)) {
121 break;
122 }
123 if (result[0] == isc_info_sql_records) {
124 unsigned i = 3, result_size = isc_vax_integer(&result[1], 2);
125 while (result[i] != isc_info_end && i < result_size) {
126 short len = (short) isc_vax_integer(&result[i + 1], 2);
127 if (result[i] != isc_info_req_select_count) {
128 affected_rows += isc_vax_integer(&result[i + 3], len);
129 }
130 i += len + 3;
131 }
132 stmt->row_count = affected_rows;
133 }
134 default:
135 ;
136 }
137
138 /* commit? */
139 if (stmt->dbh->auto_commit && isc_commit_retaining(H->isc_status, &H->tr)) {
140 break;
141 }
142
143 *S->name = 0;
144 S->cursor_open = (S->out_sqlda.sqln > 0); /* A cursor is opened, when more than zero columns returned */
145 S->exhausted = !S->cursor_open;
146
147 return 1;
148 } while (0);
149
150 RECORD_ERROR(stmt);
151
152 return 0;
153 }
154 /* }}} */
155
156 /* called by PDO to fetch the next row from a statement */
firebird_stmt_fetch(pdo_stmt_t * stmt,enum pdo_fetch_orientation ori,long offset TSRMLS_DC)157 static int firebird_stmt_fetch(pdo_stmt_t *stmt, /* {{{ */
158 enum pdo_fetch_orientation ori, long offset TSRMLS_DC)
159 {
160 pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data;
161 pdo_firebird_db_handle *H = S->H;
162
163 if (!stmt->executed) {
164 strcpy(stmt->error_code, "HY000");
165 H->last_app_error = "Cannot fetch from a closed cursor";
166 } else if (!S->exhausted) {
167 if (isc_dsql_fetch(H->isc_status, &S->stmt, PDO_FB_SQLDA_VERSION, &S->out_sqlda)) {
168 if (H->isc_status[0] && H->isc_status[1]) {
169 RECORD_ERROR(stmt);
170 }
171 S->exhausted = 1;
172 return 0;
173 }
174 if (S->statement_type == isc_info_sql_stmt_exec_procedure) {
175 S->exhausted = 1;
176 }
177 stmt->row_count++;
178 return 1;
179 }
180 return 0;
181 }
182 /* }}} */
183
184 /* called by PDO to retrieve information about the fields being returned */
firebird_stmt_describe(pdo_stmt_t * stmt,int colno TSRMLS_DC)185 static int firebird_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC) /* {{{ */
186 {
187 pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data;
188 struct pdo_column_data *col = &stmt->columns[colno];
189 XSQLVAR *var = &S->out_sqlda.sqlvar[colno];
190 int colname_len;
191 char *cp;
192
193 /* allocate storage for the column */
194 var->sqlind = (void*)ecalloc(1, var->sqllen + 2*sizeof(short));
195 var->sqldata = &((char*)var->sqlind)[sizeof(short)];
196
197 colname_len = (S->H->fetch_table_names && var->relname_length)
198 ? (var->aliasname_length + var->relname_length + 1)
199 : (var->aliasname_length);
200 col->precision = -var->sqlscale;
201 col->maxlen = var->sqllen;
202 col->namelen = colname_len;
203 col->name = cp = emalloc(colname_len + 1);
204 if (colname_len > var->aliasname_length) {
205 memmove(cp, var->relname, var->relname_length);
206 cp += var->relname_length;
207 *cp++ = '.';
208 }
209 memmove(cp, var->aliasname, var->aliasname_length);
210 *(cp+var->aliasname_length) = '\0';
211 col->param_type = PDO_PARAM_STR;
212
213 return 1;
214 }
215 /* }}} */
216
217 #define FETCH_BUF(buf,type,len,lenvar) ((buf) = (buf) ? (buf) : \
218 emalloc((len) ? (len * sizeof(type)) : ((*(unsigned long*)lenvar) = sizeof(type))))
219
220 #define CHAR_BUF_LEN 24
221
222 /* fetch a blob into a fetch buffer */
firebird_fetch_blob(pdo_stmt_t * stmt,int colno,char ** ptr,unsigned long * len,ISC_QUAD * blob_id TSRMLS_DC)223 static int firebird_fetch_blob(pdo_stmt_t *stmt, int colno, char **ptr, /* {{{ */
224 unsigned long *len, ISC_QUAD *blob_id TSRMLS_DC)
225 {
226 pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data;
227 pdo_firebird_db_handle *H = S->H;
228 isc_blob_handle blobh = NULL;
229 char const bl_item = isc_info_blob_total_length;
230 char bl_info[20];
231 unsigned short i;
232 int result = *len = 0;
233
234 if (isc_open_blob(H->isc_status, &H->db, &H->tr, &blobh, blob_id)) {
235 RECORD_ERROR(stmt);
236 return 0;
237 }
238
239 if (isc_blob_info(H->isc_status, &blobh, 1, const_cast(&bl_item),
240 sizeof(bl_info), bl_info)) {
241 RECORD_ERROR(stmt);
242 goto fetch_blob_end;
243 }
244
245 /* find total length of blob's data */
246 for (i = 0; i < sizeof(bl_info); ) {
247 unsigned short item_len;
248 char item = bl_info[i++];
249
250 if (item == isc_info_end || item == isc_info_truncated || item == isc_info_error
251 || i >= sizeof(bl_info)) {
252 H->last_app_error = "Couldn't determine BLOB size";
253 goto fetch_blob_end;
254 }
255
256 item_len = (unsigned short) isc_vax_integer(&bl_info[i], 2);
257
258 if (item == isc_info_blob_total_length) {
259 *len = isc_vax_integer(&bl_info[i+2], item_len);
260 break;
261 }
262 i += item_len+2;
263 }
264
265 /* we've found the blob's length, now fetch! */
266
267 if (*len) {
268 unsigned long cur_len;
269 unsigned short seg_len;
270 ISC_STATUS stat;
271
272 *ptr = S->fetch_buf[colno] = erealloc(*ptr, *len+1);
273
274 for (cur_len = stat = 0; (!stat || stat == isc_segment) && cur_len < *len; cur_len += seg_len) {
275
276 unsigned short chunk_size = (*len-cur_len) > USHRT_MAX ? USHRT_MAX
277 : (unsigned short)(*len-cur_len);
278
279 stat = isc_get_segment(H->isc_status, &blobh, &seg_len, chunk_size, &(*ptr)[cur_len]);
280 }
281
282 (*ptr)[*len++] = '\0';
283
284 if (H->isc_status[0] == 1 && (stat != 0 && stat != isc_segstr_eof && stat != isc_segment)) {
285 H->last_app_error = "Error reading from BLOB";
286 goto fetch_blob_end;
287 }
288 }
289 result = 1;
290
291 fetch_blob_end:
292 if (isc_close_blob(H->isc_status, &blobh)) {
293 RECORD_ERROR(stmt);
294 return 0;
295 }
296 return result;
297 }
298 /* }}} */
299
firebird_stmt_get_col(pdo_stmt_t * stmt,int colno,char ** ptr,unsigned long * len,int * caller_frees TSRMLS_DC)300 static int firebird_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, /* {{{ */
301 unsigned long *len, int *caller_frees TSRMLS_DC)
302 {
303 pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data;
304 XSQLVAR const *var = &S->out_sqlda.sqlvar[colno];
305
306 if (*var->sqlind == -1) {
307 /* A NULL value */
308 *ptr = NULL;
309 *len = 0;
310 } else {
311 if (var->sqlscale < 0) {
312 static ISC_INT64 const scales[] = { 1, 10, 100, 1000,
313 10000,
314 100000,
315 1000000,
316 10000000,
317 100000000,
318 1000000000,
319 LL_LIT(10000000000),
320 LL_LIT(100000000000),
321 LL_LIT(1000000000000),
322 LL_LIT(10000000000000),
323 LL_LIT(100000000000000),
324 LL_LIT(1000000000000000),
325 LL_LIT(10000000000000000),
326 LL_LIT(100000000000000000),
327 LL_LIT(1000000000000000000)
328 };
329 ISC_INT64 n, f = scales[-var->sqlscale];
330
331 switch (var->sqltype & ~1) {
332 case SQL_SHORT:
333 n = *(short*)var->sqldata;
334 break;
335 case SQL_LONG:
336 n = *(ISC_LONG*)var->sqldata;
337 break;
338 case SQL_INT64:
339 n = *(ISC_INT64*)var->sqldata;
340 }
341
342 *ptr = FETCH_BUF(S->fetch_buf[colno], char, CHAR_BUF_LEN, NULL);
343
344 if (n >= 0) {
345 *len = slprintf(*ptr, CHAR_BUF_LEN, "%" LL_MASK "d.%0*" LL_MASK "d",
346 n / f, -var->sqlscale, n % f);
347 } else if (n <= -f) {
348 *len = slprintf(*ptr, CHAR_BUF_LEN, "%" LL_MASK "d.%0*" LL_MASK "d",
349 n / f, -var->sqlscale, -n % f);
350 } else {
351 *len = slprintf(*ptr, CHAR_BUF_LEN, "-0.%0*" LL_MASK "d", -var->sqlscale, -n % f);
352 }
353 } else {
354 switch (var->sqltype & ~1) {
355 struct tm t;
356 char *fmt;
357
358 case SQL_VARYING:
359 *ptr = &var->sqldata[2];
360 *len = *(short*)var->sqldata;
361 break;
362 case SQL_TEXT:
363 *ptr = var->sqldata;
364 *len = var->sqllen;
365 break;
366 case SQL_SHORT:
367 *ptr = FETCH_BUF(S->fetch_buf[colno], char, CHAR_BUF_LEN, NULL);
368 *len = slprintf(*ptr, CHAR_BUF_LEN, "%d", *(short*)var->sqldata);
369 break;
370 case SQL_LONG:
371 *ptr = FETCH_BUF(S->fetch_buf[colno], char, CHAR_BUF_LEN, NULL);
372 *len = slprintf(*ptr, CHAR_BUF_LEN, "%ld", *(ISC_LONG*)var->sqldata);
373 break;
374 case SQL_INT64:
375 *ptr = FETCH_BUF(S->fetch_buf[colno], char, CHAR_BUF_LEN, NULL);
376 *len = slprintf(*ptr, CHAR_BUF_LEN, "%" LL_MASK "d", *(ISC_INT64*)var->sqldata);
377 break;
378 case SQL_FLOAT:
379 *ptr = FETCH_BUF(S->fetch_buf[colno], char, CHAR_BUF_LEN, NULL);
380 *len = slprintf(*ptr, CHAR_BUF_LEN, "%F", *(float*)var->sqldata);
381 break;
382 case SQL_DOUBLE:
383 *ptr = FETCH_BUF(S->fetch_buf[colno], char, CHAR_BUF_LEN, NULL);
384 *len = slprintf(*ptr, CHAR_BUF_LEN, "%F" , *(double*)var->sqldata);
385 break;
386 case SQL_TYPE_DATE:
387 isc_decode_sql_date((ISC_DATE*)var->sqldata, &t);
388 fmt = S->H->date_format ? S->H->date_format : PDO_FB_DEF_DATE_FMT;
389 if (0) {
390 case SQL_TYPE_TIME:
391 isc_decode_sql_time((ISC_TIME*)var->sqldata, &t);
392 fmt = S->H->time_format ? S->H->time_format : PDO_FB_DEF_TIME_FMT;
393 } else if (0) {
394 case SQL_TIMESTAMP:
395 isc_decode_timestamp((ISC_TIMESTAMP*)var->sqldata, &t);
396 fmt = S->H->timestamp_format ? S->H->timestamp_format : PDO_FB_DEF_TIMESTAMP_FMT;
397 }
398 /* convert the timestamp into a string */
399 *len = 80;
400 *ptr = FETCH_BUF(S->fetch_buf[colno], char, *len, NULL);
401 *len = strftime(*ptr, *len, fmt, &t);
402 break;
403 case SQL_BLOB:
404 return firebird_fetch_blob(stmt,colno,ptr,len,
405 (ISC_QUAD*)var->sqldata TSRMLS_CC);
406 }
407 }
408 }
409 return 1;
410 }
411 /* }}} */
412
firebird_bind_blob(pdo_stmt_t * stmt,ISC_QUAD * blob_id,zval * param TSRMLS_DC)413 static int firebird_bind_blob(pdo_stmt_t *stmt, ISC_QUAD *blob_id, zval *param TSRMLS_DC)
414 {
415 pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data;
416 pdo_firebird_db_handle *H = S->H;
417 isc_blob_handle h = NULL;
418 unsigned long put_cnt = 0, rem_cnt;
419 unsigned short chunk_size;
420 int result = 1;
421
422 if (isc_create_blob(H->isc_status, &H->db, &H->tr, &h, blob_id)) {
423 RECORD_ERROR(stmt);
424 return 0;
425 }
426
427 SEPARATE_ZVAL(¶m);
428
429 convert_to_string_ex(¶m);
430
431 for (rem_cnt = Z_STRLEN_P(param); rem_cnt > 0; rem_cnt -= chunk_size) {
432
433 chunk_size = rem_cnt > USHRT_MAX ? USHRT_MAX : (unsigned short)rem_cnt;
434
435 if (isc_put_segment(H->isc_status, &h, chunk_size, &Z_STRVAL_P(param)[put_cnt])) {
436 RECORD_ERROR(stmt);
437 result = 0;
438 break;
439 }
440 put_cnt += chunk_size;
441 }
442
443 zval_dtor(param);
444
445 if (isc_close_blob(H->isc_status, &h)) {
446 RECORD_ERROR(stmt);
447 return 0;
448 }
449 return result;
450 }
451
firebird_stmt_param_hook(pdo_stmt_t * stmt,struct pdo_bound_param_data * param,enum pdo_param_event event_type TSRMLS_DC)452 static int firebird_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param, /* {{{ */
453 enum pdo_param_event event_type TSRMLS_DC)
454 {
455 pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data;
456 XSQLDA *sqlda = param->is_param ? S->in_sqlda : &S->out_sqlda;
457 XSQLVAR *var;
458
459 if (event_type == PDO_PARAM_EVT_FREE) { /* not used */
460 return 1;
461 }
462
463 if (!sqlda || param->paramno >= sqlda->sqld) {
464 strcpy(stmt->error_code, "HY093");
465 S->H->last_app_error = "Invalid parameter index";
466 return 0;
467 }
468 if (param->is_param && param->paramno == -1) {
469 long *index;
470
471 /* try to determine the index by looking in the named_params hash */
472 if (SUCCESS == zend_hash_find(S->named_params, param->name, param->namelen+1, (void*)&index)) {
473 param->paramno = *index;
474 } else {
475 /* ... or by looking in the input descriptor */
476 int i;
477
478 for (i = 0; i < sqlda->sqld; ++i) {
479 XSQLVAR *var = &sqlda->sqlvar[i];
480
481 if ((var->aliasname_length && !strncasecmp(param->name, var->aliasname,
482 min(param->namelen, var->aliasname_length)))
483 || (var->sqlname_length && !strncasecmp(param->name, var->sqlname,
484 min(param->namelen, var->sqlname_length)))) {
485 param->paramno = i;
486 break;
487 }
488 }
489 if (i >= sqlda->sqld) {
490 strcpy(stmt->error_code, "HY093");
491 S->H->last_app_error = "Invalid parameter name";
492 return 0;
493 }
494 }
495 }
496
497 var = &sqlda->sqlvar[param->paramno];
498
499 switch (event_type) {
500 char *value;
501 unsigned long value_len;
502 int caller_frees;
503
504 case PDO_PARAM_EVT_ALLOC:
505 if (param->is_param) {
506 /* allocate the parameter */
507 if (var->sqlind) {
508 efree(var->sqlind);
509 }
510 var->sqlind = (void*)emalloc(var->sqllen + 2*sizeof(short));
511 var->sqldata = &((char*)var->sqlind)[sizeof(short)];
512 }
513 break;
514
515 case PDO_PARAM_EVT_EXEC_PRE:
516 if (!param->is_param) {
517 break;
518 }
519
520 *var->sqlind = 0;
521
522 switch (var->sqltype & ~1) {
523 case SQL_ARRAY:
524 strcpy(stmt->error_code, "HY000");
525 S->H->last_app_error = "Cannot bind to array field";
526 return 0;
527
528 case SQL_BLOB:
529 return firebird_bind_blob(stmt, (ISC_QUAD*)var->sqldata,
530 param->parameter TSRMLS_CC);
531 }
532
533 /* check if a NULL should be inserted */
534 switch (Z_TYPE_P(param->parameter)) {
535 int force_null;
536
537 case IS_LONG:
538 /* keep the allow-NULL flag */
539 var->sqltype = (sizeof(long) == 8 ? SQL_INT64 : SQL_LONG) | (var->sqltype & 1);
540 var->sqldata = (void*)&Z_LVAL_P(param->parameter);
541 var->sqllen = sizeof(long);
542 break;
543 case IS_DOUBLE:
544 /* keep the allow-NULL flag */
545 var->sqltype = SQL_DOUBLE | (var->sqltype & 1);
546 var->sqldata = (void*)&Z_DVAL_P(param->parameter);
547 var->sqllen = sizeof(double);
548 break;
549 case IS_STRING:
550 force_null = 0;
551
552 /* for these types, an empty string can be handled like a NULL value */
553 switch (var->sqltype & ~1) {
554 case SQL_SHORT:
555 case SQL_LONG:
556 case SQL_INT64:
557 case SQL_FLOAT:
558 case SQL_DOUBLE:
559 case SQL_TIMESTAMP:
560 case SQL_TYPE_DATE:
561 case SQL_TYPE_TIME:
562 force_null = (Z_STRLEN_P(param->parameter) == 0);
563 }
564 if (!force_null) {
565 /* keep the allow-NULL flag */
566 var->sqltype = SQL_TEXT | (var->sqltype & 1);
567 var->sqldata = Z_STRVAL_P(param->parameter);
568 var->sqllen = Z_STRLEN_P(param->parameter);
569 break;
570 }
571 case IS_NULL:
572 /* complain if this field doesn't allow NULL values */
573 if (~var->sqltype & 1) {
574 strcpy(stmt->error_code, "HY105");
575 S->H->last_app_error = "Parameter requires non-null value";
576 return 0;
577 }
578 *var->sqlind = -1;
579 break;
580 default:
581 strcpy(stmt->error_code, "HY105");
582 S->H->last_app_error = "Binding arrays/objects is not supported";
583 return 0;
584 }
585 break;
586
587 case PDO_PARAM_EVT_FETCH_POST:
588 if (param->paramno == -1) {
589 return 0;
590 }
591 if (param->is_param) {
592 break;
593 }
594 value = NULL;
595 value_len = 0;
596 caller_frees = 0;
597
598 if (firebird_stmt_get_col(stmt, param->paramno, &value, &value_len, &caller_frees TSRMLS_CC)) {
599 switch (PDO_PARAM_TYPE(param->param_type)) {
600 case PDO_PARAM_STR:
601 if (value) {
602 ZVAL_STRINGL(param->parameter, value, value_len, 1);
603 break;
604 }
605 case PDO_PARAM_INT:
606 if (value) {
607 ZVAL_LONG(param->parameter, *(long*)value);
608 break;
609 }
610 case PDO_PARAM_EVT_NORMALIZE:
611 if (!param->is_param) {
612 char *s = param->name;
613 while (*s != '\0') {
614 *s = toupper(*s);
615 s++;
616 }
617 }
618 break;
619 default:
620 ZVAL_NULL(param->parameter);
621 }
622 if (value && caller_frees) {
623 efree(value);
624 }
625 return 1;
626 }
627 return 0;
628 default:
629 ;
630 }
631 return 1;
632 }
633 /* }}} */
634
firebird_stmt_set_attribute(pdo_stmt_t * stmt,long attr,zval * val TSRMLS_DC)635 static int firebird_stmt_set_attribute(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC) /* {{{ */
636 {
637 pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data;
638
639 switch (attr) {
640 default:
641 return 0;
642 case PDO_ATTR_CURSOR_NAME:
643 convert_to_string(val);
644
645 if (isc_dsql_set_cursor_name(S->H->isc_status, &S->stmt, Z_STRVAL_P(val),0)) {
646 RECORD_ERROR(stmt);
647 return 0;
648 }
649 strlcpy(S->name, Z_STRVAL_P(val), sizeof(S->name));
650 break;
651 }
652 return 1;
653 }
654 /* }}} */
655
firebird_stmt_get_attribute(pdo_stmt_t * stmt,long attr,zval * val TSRMLS_DC)656 static int firebird_stmt_get_attribute(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC) /* {{{ */
657 {
658 pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data;
659
660 switch (attr) {
661 default:
662 return 0;
663 case PDO_ATTR_CURSOR_NAME:
664 if (*S->name) {
665 ZVAL_STRING(val,S->name,1);
666 } else {
667 ZVAL_NULL(val);
668 }
669 break;
670 }
671 return 1;
672 }
673 /* }}} */
674
firebird_stmt_cursor_closer(pdo_stmt_t * stmt TSRMLS_DC)675 static int firebird_stmt_cursor_closer(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
676 {
677 pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data;
678
679 /* close the statement handle */
680 if ((*S->name || S->cursor_open) && isc_dsql_free_statement(S->H->isc_status, &S->stmt, DSQL_close)) {
681 RECORD_ERROR(stmt);
682 return 0;
683 }
684 *S->name = 0;
685 S->cursor_open = 0;
686 return 1;
687 }
688 /* }}} */
689
690
691 struct pdo_stmt_methods firebird_stmt_methods = { /* {{{ */
692 firebird_stmt_dtor,
693 firebird_stmt_execute,
694 firebird_stmt_fetch,
695 firebird_stmt_describe,
696 firebird_stmt_get_col,
697 firebird_stmt_param_hook,
698 firebird_stmt_set_attribute,
699 firebird_stmt_get_attribute,
700 NULL, /* get_column_meta_func */
701 NULL, /* next_rowset_func */
702 firebird_stmt_cursor_closer
703 };
704 /* }}} */
705
706 /*
707 * Local variables:
708 * tab-width: 4
709 * c-basic-offset: 4
710 * End:
711 * vim600: noet sw=4 ts=4 fdm=marker
712 * vim<600: noet sw=4 ts=4
713 */
714