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