firebird_statement.c 20 KB

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