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