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