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