firebird_statement.c 22 KB

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