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