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