PageRenderTime 58ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/ext/interbase/ibase_query.c

http://github.com/infusion/PHP
C | 2107 lines | 1619 code | 315 blank | 173 comment | 397 complexity | 9d08e89be8e8e666f12a31bddea3dcb0 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2011 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. | Authors: Ard Biesheuvel <a.k.biesheuvel@its.tudelft.nl> |
  16. +----------------------------------------------------------------------+
  17. */
  18. /* $Id: ibase_query.c 306939 2011-01-01 02:19:59Z felipe $ */
  19. #ifdef HAVE_CONFIG_H
  20. #include "config.h"
  21. #endif
  22. #include "php.h"
  23. #include "php_ini.h"
  24. #if HAVE_IBASE
  25. #include "ext/standard/php_standard.h"
  26. #include "php_interbase.h"
  27. #include "php_ibase_includes.h"
  28. #define ISC_LONG_MIN INT_MIN
  29. #define ISC_LONG_MAX INT_MAX
  30. #define QUERY_RESULT 1
  31. #define EXECUTE_RESULT 2
  32. #define FETCH_ROW 1
  33. #define FETCH_ARRAY 2
  34. typedef struct {
  35. ISC_ARRAY_DESC ar_desc;
  36. ISC_LONG ar_size; /* size of entire array in bytes */
  37. unsigned short el_type, el_size;
  38. } ibase_array;
  39. typedef struct {
  40. ibase_db_link *link;
  41. ibase_trans *trans;
  42. struct _ib_query *query;
  43. isc_stmt_handle stmt;
  44. unsigned short type;
  45. unsigned char has_more_rows, statement_type;
  46. XSQLDA *out_sqlda;
  47. ibase_array out_array[1]; /* last member */
  48. } ibase_result;
  49. typedef struct _ib_query {
  50. ibase_db_link *link;
  51. ibase_trans *trans;
  52. ibase_result *result;
  53. int result_res_id;
  54. isc_stmt_handle stmt;
  55. XSQLDA *in_sqlda, *out_sqlda;
  56. ibase_array *in_array, *out_array;
  57. unsigned short in_array_cnt, out_array_cnt;
  58. unsigned short dialect;
  59. char statement_type;
  60. char *query;
  61. long trans_res_id;
  62. } ibase_query;
  63. typedef struct {
  64. unsigned short vary_length;
  65. char vary_string[1];
  66. } IBVARY;
  67. /* sql variables union
  68. * used for convert and binding input variables
  69. */
  70. typedef struct {
  71. union {
  72. short sval;
  73. float fval;
  74. ISC_LONG lval;
  75. ISC_QUAD qval;
  76. ISC_TIMESTAMP tsval;
  77. ISC_DATE dtval;
  78. ISC_TIME tmval;
  79. } val;
  80. short sqlind;
  81. } BIND_BUF;
  82. static int le_result, le_query;
  83. #define LE_RESULT "Firebird/InterBase result"
  84. #define LE_QUERY "Firebird/InterBase query"
  85. static void _php_ibase_free_xsqlda(XSQLDA *sqlda) /* {{{ */
  86. {
  87. int i;
  88. XSQLVAR *var;
  89. IBDEBUG("Free XSQLDA?");
  90. if (sqlda) {
  91. IBDEBUG("Freeing XSQLDA...");
  92. var = sqlda->sqlvar;
  93. for (i = 0; i < sqlda->sqld; i++, var++) {
  94. efree(var->sqldata);
  95. if (var->sqlind) {
  96. efree(var->sqlind);
  97. }
  98. }
  99. efree(sqlda);
  100. }
  101. }
  102. /* }}} */
  103. static void _php_ibase_free_stmt_handle(ibase_db_link *link, isc_stmt_handle stmt TSRMLS_DC) /* {{{ */
  104. {
  105. static char info[] = { isc_info_base_level, isc_info_end };
  106. if (stmt) {
  107. char res_buf[8];
  108. IBDEBUG("Dropping statement handle (free_stmt_handle)...");
  109. /* Only free statement if db-connection is still open */
  110. if (SUCCESS == isc_database_info(IB_STATUS, &link->handle,
  111. sizeof(info), info, sizeof(res_buf), res_buf)) {
  112. if (isc_dsql_free_statement(IB_STATUS, &stmt, DSQL_drop)) {
  113. _php_ibase_error(TSRMLS_C);
  114. }
  115. }
  116. }
  117. }
  118. /* }}} */
  119. static void _php_ibase_free_result(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
  120. {
  121. ibase_result *ib_result = (ibase_result *) rsrc->ptr;
  122. IBDEBUG("Freeing result by dtor...");
  123. if (ib_result) {
  124. _php_ibase_free_xsqlda(ib_result->out_sqlda);
  125. if (ib_result->query != NULL) {
  126. IBDEBUG("query still valid; don't drop statement handle");
  127. ib_result->query->result = NULL; /* Indicate to query, that result is released */
  128. } else {
  129. _php_ibase_free_stmt_handle(ib_result->link, ib_result->stmt TSRMLS_CC);
  130. }
  131. efree(ib_result);
  132. }
  133. }
  134. /* }}} */
  135. static void _php_ibase_free_query(ibase_query *ib_query TSRMLS_DC) /* {{{ */
  136. {
  137. IBDEBUG("Freeing query...");
  138. if (ib_query->in_sqlda) {
  139. efree(ib_query->in_sqlda);
  140. }
  141. if (ib_query->out_sqlda) {
  142. efree(ib_query->out_sqlda);
  143. }
  144. if (ib_query->result != NULL) {
  145. IBDEBUG("result still valid; don't drop statement handle");
  146. ib_query->result->query = NULL; /* Indicate to result, that query is released */
  147. } else {
  148. _php_ibase_free_stmt_handle(ib_query->link, ib_query->stmt TSRMLS_CC);
  149. }
  150. if (ib_query->in_array) {
  151. efree(ib_query->in_array);
  152. }
  153. if (ib_query->out_array) {
  154. efree(ib_query->out_array);
  155. }
  156. if (ib_query->query) {
  157. efree(ib_query->query);
  158. }
  159. }
  160. /* }}} */
  161. static void php_ibase_free_query_rsrc(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
  162. {
  163. ibase_query *ib_query = (ibase_query *)rsrc->ptr;
  164. if (ib_query != NULL) {
  165. IBDEBUG("Preparing to free query by dtor...");
  166. _php_ibase_free_query(ib_query TSRMLS_CC);
  167. efree(ib_query);
  168. }
  169. }
  170. /* }}} */
  171. void php_ibase_query_minit(INIT_FUNC_ARGS) /* {{{ */
  172. {
  173. le_result = zend_register_list_destructors_ex(_php_ibase_free_result, NULL,
  174. "interbase result", module_number);
  175. le_query = zend_register_list_destructors_ex(php_ibase_free_query_rsrc, NULL,
  176. "interbase query", module_number);
  177. }
  178. /* }}} */
  179. static int _php_ibase_alloc_array(ibase_array **ib_arrayp, XSQLDA *sqlda, /* {{{ */
  180. isc_db_handle link, isc_tr_handle trans, unsigned short *array_cnt TSRMLS_DC)
  181. {
  182. unsigned short i, n;
  183. ibase_array *ar;
  184. /* first check if we have any arrays at all */
  185. for (i = *array_cnt = 0; i < sqlda->sqld; ++i) {
  186. if ((sqlda->sqlvar[i].sqltype & ~1) == SQL_ARRAY) {
  187. ++*array_cnt;
  188. }
  189. }
  190. if (! *array_cnt) return SUCCESS;
  191. ar = safe_emalloc(sizeof(ibase_array), *array_cnt, 0);
  192. for (i = n = 0; i < sqlda->sqld; ++i) {
  193. unsigned short dim;
  194. unsigned long ar_size = 1;
  195. XSQLVAR *var = &sqlda->sqlvar[i];
  196. if ((var->sqltype & ~1) == SQL_ARRAY) {
  197. ibase_array *a = &ar[n++];
  198. ISC_ARRAY_DESC *ar_desc = &a->ar_desc;
  199. if (isc_array_lookup_bounds(IB_STATUS, &link, &trans, var->relname,
  200. var->sqlname, ar_desc)) {
  201. _php_ibase_error(TSRMLS_C);
  202. efree(ar);
  203. return FAILURE;
  204. }
  205. switch (ar_desc->array_desc_dtype) {
  206. case blr_text:
  207. case blr_text2:
  208. a->el_type = SQL_TEXT;
  209. a->el_size = ar_desc->array_desc_length;
  210. break;
  211. case blr_short:
  212. a->el_type = SQL_SHORT;
  213. a->el_size = sizeof(short);
  214. break;
  215. case blr_long:
  216. a->el_type = SQL_LONG;
  217. a->el_size = sizeof(ISC_LONG);
  218. break;
  219. case blr_float:
  220. a->el_type = SQL_FLOAT;
  221. a->el_size = sizeof(float);
  222. break;
  223. case blr_double:
  224. a->el_type = SQL_DOUBLE;
  225. a->el_size = sizeof(double);
  226. break;
  227. case blr_int64:
  228. a->el_type = SQL_INT64;
  229. a->el_size = sizeof(ISC_INT64);
  230. break;
  231. case blr_timestamp:
  232. a->el_type = SQL_TIMESTAMP;
  233. a->el_size = sizeof(ISC_TIMESTAMP);
  234. break;
  235. case blr_sql_date:
  236. a->el_type = SQL_TYPE_DATE;
  237. a->el_size = sizeof(ISC_DATE);
  238. break;
  239. case blr_sql_time:
  240. a->el_type = SQL_TYPE_TIME;
  241. a->el_size = sizeof(ISC_TIME);
  242. break;
  243. case blr_varying:
  244. case blr_varying2:
  245. /**
  246. * IB has a strange way of handling VARCHAR arrays. It doesn't store
  247. * the length in the first short, as with VARCHAR fields. It does,
  248. * however, expect the extra short to be allocated for each element.
  249. */
  250. a->el_type = SQL_TEXT;
  251. a->el_size = ar_desc->array_desc_length + sizeof(short);
  252. break;
  253. case blr_quad:
  254. case blr_blob_id:
  255. case blr_cstring:
  256. case blr_cstring2:
  257. /**
  258. * These types are mentioned as array types in the manual, but I
  259. * wouldn't know how to create an array field with any of these
  260. * types. I assume these types are not applicable to arrays, and
  261. * were mentioned erroneously.
  262. */
  263. default:
  264. _php_ibase_module_error("Unsupported array type %d in relation '%s' column '%s'"
  265. TSRMLS_CC, ar_desc->array_desc_dtype, var->relname, var->sqlname);
  266. efree(ar);
  267. return FAILURE;
  268. } /* switch array_desc_type */
  269. /* calculate elements count */
  270. for (dim = 0; dim < ar_desc->array_desc_dimensions; dim++) {
  271. ar_size *= 1 + ar_desc->array_desc_bounds[dim].array_bound_upper
  272. -ar_desc->array_desc_bounds[dim].array_bound_lower;
  273. }
  274. a->ar_size = a->el_size * ar_size;
  275. } /* if SQL_ARRAY */
  276. } /* for column */
  277. *ib_arrayp = ar;
  278. return SUCCESS;
  279. }
  280. /* }}} */
  281. /* allocate and prepare query */
  282. static int _php_ibase_alloc_query(ibase_query *ib_query, ibase_db_link *link, /* {{{ */
  283. ibase_trans *trans, char *query, unsigned short dialect, int trans_res_id TSRMLS_DC)
  284. {
  285. static char info_type[] = {isc_info_sql_stmt_type};
  286. char result[8];
  287. /* Return FAILURE, if querystring is empty */
  288. if (*query == '\0') {
  289. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Querystring empty.");
  290. return FAILURE;
  291. }
  292. ib_query->link = link;
  293. ib_query->trans = trans;
  294. ib_query->result_res_id = 0;
  295. ib_query->result = NULL;
  296. ib_query->stmt = NULL;
  297. ib_query->in_array = NULL;
  298. ib_query->out_array = NULL;
  299. ib_query->dialect = dialect;
  300. ib_query->query = estrdup(query);
  301. ib_query->trans_res_id = trans_res_id;
  302. ib_query->out_sqlda = NULL;
  303. ib_query->in_sqlda = NULL;
  304. if (isc_dsql_allocate_statement(IB_STATUS, &link->handle, &ib_query->stmt)) {
  305. _php_ibase_error(TSRMLS_C);
  306. goto _php_ibase_alloc_query_error;
  307. }
  308. ib_query->out_sqlda = (XSQLDA *) emalloc(XSQLDA_LENGTH(1));
  309. ib_query->out_sqlda->sqln = 1;
  310. ib_query->out_sqlda->version = SQLDA_CURRENT_VERSION;
  311. if (isc_dsql_prepare(IB_STATUS, &ib_query->trans->handle, &ib_query->stmt,
  312. 0, query, dialect, ib_query->out_sqlda)) {
  313. _php_ibase_error(TSRMLS_C);
  314. goto _php_ibase_alloc_query_error;
  315. }
  316. /* find out what kind of statement was prepared */
  317. if (isc_dsql_sql_info(IB_STATUS, &ib_query->stmt, sizeof(info_type),
  318. info_type, sizeof(result), result)) {
  319. _php_ibase_error(TSRMLS_C);
  320. goto _php_ibase_alloc_query_error;
  321. }
  322. ib_query->statement_type = result[3];
  323. /* not enough output variables ? */
  324. if (ib_query->out_sqlda->sqld > ib_query->out_sqlda->sqln) {
  325. ib_query->out_sqlda = erealloc(ib_query->out_sqlda, XSQLDA_LENGTH(ib_query->out_sqlda->sqld));
  326. ib_query->out_sqlda->sqln = ib_query->out_sqlda->sqld;
  327. ib_query->out_sqlda->version = SQLDA_CURRENT_VERSION;
  328. if (isc_dsql_describe(IB_STATUS, &ib_query->stmt, SQLDA_CURRENT_VERSION, ib_query->out_sqlda)) {
  329. _php_ibase_error(TSRMLS_C);
  330. goto _php_ibase_alloc_query_error;
  331. }
  332. }
  333. /* maybe have input placeholders? */
  334. ib_query->in_sqlda = emalloc(XSQLDA_LENGTH(1));
  335. ib_query->in_sqlda->sqln = 1;
  336. ib_query->in_sqlda->version = SQLDA_CURRENT_VERSION;
  337. if (isc_dsql_describe_bind(IB_STATUS, &ib_query->stmt, SQLDA_CURRENT_VERSION, ib_query->in_sqlda)) {
  338. _php_ibase_error(TSRMLS_C);
  339. goto _php_ibase_alloc_query_error;
  340. }
  341. /* not enough input variables ? */
  342. if (ib_query->in_sqlda->sqln < ib_query->in_sqlda->sqld) {
  343. ib_query->in_sqlda = erealloc(ib_query->in_sqlda, XSQLDA_LENGTH(ib_query->in_sqlda->sqld));
  344. ib_query->in_sqlda->sqln = ib_query->in_sqlda->sqld;
  345. ib_query->in_sqlda->version = SQLDA_CURRENT_VERSION;
  346. if (isc_dsql_describe_bind(IB_STATUS, &ib_query->stmt,
  347. SQLDA_CURRENT_VERSION, ib_query->in_sqlda)) {
  348. _php_ibase_error(TSRMLS_C);
  349. goto _php_ibase_alloc_query_error;
  350. }
  351. }
  352. /* no, haven't placeholders at all */
  353. if (ib_query->in_sqlda->sqld == 0) {
  354. efree(ib_query->in_sqlda);
  355. ib_query->in_sqlda = NULL;
  356. } else if (FAILURE == _php_ibase_alloc_array(&ib_query->in_array, ib_query->in_sqlda,
  357. link->handle, trans->handle, &ib_query->in_array_cnt TSRMLS_CC)) {
  358. goto _php_ibase_alloc_query_error;
  359. }
  360. if (ib_query->out_sqlda->sqld == 0) {
  361. efree(ib_query->out_sqlda);
  362. ib_query->out_sqlda = NULL;
  363. } else if (FAILURE == _php_ibase_alloc_array(&ib_query->out_array, ib_query->out_sqlda,
  364. link->handle, trans->handle, &ib_query->out_array_cnt TSRMLS_CC)) {
  365. goto _php_ibase_alloc_query_error;
  366. }
  367. return SUCCESS;
  368. _php_ibase_alloc_query_error:
  369. if (ib_query->out_sqlda) {
  370. efree(ib_query->out_sqlda);
  371. }
  372. if (ib_query->in_sqlda) {
  373. efree(ib_query->in_sqlda);
  374. }
  375. if (ib_query->out_array) {
  376. efree(ib_query->out_array);
  377. }
  378. if (ib_query->query) {
  379. efree(ib_query->query);
  380. }
  381. return FAILURE;
  382. }
  383. /* }}} */
  384. static int _php_ibase_bind_array(zval *val, char *buf, unsigned long buf_size, /* {{{ */
  385. ibase_array *array, int dim TSRMLS_DC)
  386. {
  387. zval null_val, *pnull_val = &null_val;
  388. int u_bound = array->ar_desc.array_desc_bounds[dim].array_bound_upper,
  389. l_bound = array->ar_desc.array_desc_bounds[dim].array_bound_lower,
  390. dim_len = 1 + u_bound - l_bound;
  391. ZVAL_NULL(pnull_val);
  392. if (dim < array->ar_desc.array_desc_dimensions) {
  393. unsigned long slice_size = buf_size / dim_len;
  394. unsigned short i;
  395. zval **subval = &val;
  396. if (Z_TYPE_P(val) == IS_ARRAY) {
  397. zend_hash_internal_pointer_reset(Z_ARRVAL_P(val));
  398. }
  399. for (i = 0; i < dim_len; ++i) {
  400. if (Z_TYPE_P(val) == IS_ARRAY &&
  401. zend_hash_get_current_data(Z_ARRVAL_P(val), (void *) &subval) == FAILURE)
  402. {
  403. subval = &pnull_val;
  404. }
  405. if (_php_ibase_bind_array(*subval, buf, slice_size, array, dim+1 TSRMLS_CC) == FAILURE)
  406. {
  407. return FAILURE;
  408. }
  409. buf += slice_size;
  410. if (Z_TYPE_P(val) == IS_ARRAY) {
  411. zend_hash_move_forward(Z_ARRVAL_P(val));
  412. }
  413. }
  414. if (Z_TYPE_P(val) == IS_ARRAY) {
  415. zend_hash_internal_pointer_reset(Z_ARRVAL_P(val));
  416. }
  417. } else {
  418. /* expect a single value */
  419. if (Z_TYPE_P(val) == IS_NULL) {
  420. memset(buf, 0, buf_size);
  421. } else if (array->ar_desc.array_desc_scale < 0) {
  422. /* no coercion for array types */
  423. double l;
  424. convert_to_double(val);
  425. if (Z_DVAL_P(val) > 0) {
  426. l = Z_DVAL_P(val) * pow(10, -array->ar_desc.array_desc_scale) + .5;
  427. } else {
  428. l = Z_DVAL_P(val) * pow(10, -array->ar_desc.array_desc_scale) - .5;
  429. }
  430. switch (array->el_type) {
  431. case SQL_SHORT:
  432. if (l > SHRT_MAX || l < SHRT_MIN) {
  433. _php_ibase_module_error("Array parameter exceeds field width" TSRMLS_CC);
  434. return FAILURE;
  435. }
  436. *(short*) buf = (short) l;
  437. break;
  438. case SQL_LONG:
  439. if (l > ISC_LONG_MAX || l < ISC_LONG_MIN) {
  440. _php_ibase_module_error("Array parameter exceeds field width" TSRMLS_CC);
  441. return FAILURE;
  442. }
  443. *(ISC_LONG*) buf = (ISC_LONG) l;
  444. break;
  445. case SQL_INT64:
  446. {
  447. long double l;
  448. convert_to_string(val);
  449. if (!sscanf(Z_STRVAL_P(val), "%Lf", &l)) {
  450. _php_ibase_module_error("Cannot convert '%s' to long double"
  451. TSRMLS_CC, Z_STRVAL_P(val));
  452. return FAILURE;
  453. }
  454. if (l > 0) {
  455. *(ISC_INT64 *) buf = (ISC_INT64) (l * pow(10,
  456. -array->ar_desc.array_desc_scale) + .5);
  457. } else {
  458. *(ISC_INT64 *) buf = (ISC_INT64) (l * pow(10,
  459. -array->ar_desc.array_desc_scale) - .5);
  460. }
  461. }
  462. break;
  463. }
  464. } else {
  465. struct tm t = { 0, 0, 0, 0, 0, 0 };
  466. switch (array->el_type) {
  467. unsigned short n;
  468. ISC_INT64 l;
  469. case SQL_SHORT:
  470. convert_to_long(val);
  471. if (Z_LVAL_P(val) > SHRT_MAX || Z_LVAL_P(val) < SHRT_MIN) {
  472. _php_ibase_module_error("Array parameter exceeds field width" TSRMLS_CC);
  473. return FAILURE;
  474. }
  475. *(short *) buf = (short) Z_LVAL_P(val);
  476. break;
  477. case SQL_LONG:
  478. convert_to_long(val);
  479. #if (SIZEOF_LONG > 4)
  480. if (Z_LVAL_P(val) > ISC_LONG_MAX || Z_LVAL_P(val) < ISC_LONG_MIN) {
  481. _php_ibase_module_error("Array parameter exceeds field width" TSRMLS_CC);
  482. return FAILURE;
  483. }
  484. #endif
  485. *(ISC_LONG *) buf = (ISC_LONG) Z_LVAL_P(val);
  486. break;
  487. case SQL_INT64:
  488. #if (SIZEOF_LONG >= 8)
  489. convert_to_long(val);
  490. *(long *) buf = Z_LVAL_P(val);
  491. #else
  492. convert_to_string(val);
  493. if (!sscanf(Z_STRVAL_P(val), "%" LL_MASK "d", &l)) {
  494. _php_ibase_module_error("Cannot convert '%s' to long integer"
  495. TSRMLS_CC, Z_STRVAL_P(val));
  496. return FAILURE;
  497. } else {
  498. *(ISC_INT64 *) buf = l;
  499. }
  500. #endif
  501. break;
  502. case SQL_FLOAT:
  503. convert_to_double(val);
  504. *(float*) buf = (float) Z_DVAL_P(val);
  505. break;
  506. case SQL_DOUBLE:
  507. convert_to_double(val);
  508. *(double*) buf = Z_DVAL_P(val);
  509. break;
  510. case SQL_TIMESTAMP:
  511. convert_to_string(val);
  512. #ifdef HAVE_STRPTIME
  513. strptime(Z_STRVAL_P(val), INI_STR("ibase.timestampformat"), &t);
  514. #else
  515. n = sscanf(Z_STRVAL_P(val), "%d%*[/]%d%*[/]%d %d%*[:]%d%*[:]%d",
  516. &t.tm_mon, &t.tm_mday, &t.tm_year, &t.tm_hour, &t.tm_min, &t.tm_sec);
  517. if (n != 3 && n != 6) {
  518. _php_ibase_module_error("Invalid date/time format (expected 3 or 6 fields, got %d."
  519. " Use format 'm/d/Y H:i:s'. You gave '%s')" TSRMLS_CC, n, Z_STRVAL_P(val));
  520. return FAILURE;
  521. }
  522. t.tm_year -= 1900;
  523. t.tm_mon--;
  524. #endif
  525. isc_encode_timestamp(&t, (ISC_TIMESTAMP * ) buf);
  526. break;
  527. case SQL_TYPE_DATE:
  528. convert_to_string(val);
  529. #ifdef HAVE_STRPTIME
  530. strptime(Z_STRVAL_P(val), INI_STR("ibase.dateformat"), &t);
  531. #else
  532. n = sscanf(Z_STRVAL_P(val), "%d%*[/]%d%*[/]%d", &t.tm_mon, &t.tm_mday, &t.tm_year);
  533. if (n != 3) {
  534. _php_ibase_module_error("Invalid date format (expected 3 fields, got %d. "
  535. "Use format 'm/d/Y' You gave '%s')" TSRMLS_CC, n, Z_STRVAL_P(val));
  536. return FAILURE;
  537. }
  538. t.tm_year -= 1900;
  539. t.tm_mon--;
  540. #endif
  541. isc_encode_sql_date(&t, (ISC_DATE *) buf);
  542. break;
  543. case SQL_TYPE_TIME:
  544. convert_to_string(val);
  545. #ifdef HAVE_STRPTIME
  546. strptime(Z_STRVAL_P(val), INI_STR("ibase.timeformat"), &t);
  547. #else
  548. n = sscanf(Z_STRVAL_P(val), "%d%*[:]%d%*[:]%d", &t.tm_hour, &t.tm_min, &t.tm_sec);
  549. if (n != 3) {
  550. _php_ibase_module_error("Invalid time format (expected 3 fields, got %d. "
  551. "Use format 'H:i:s'. You gave '%s')" TSRMLS_CC, n, Z_STRVAL_P(val));
  552. return FAILURE;
  553. }
  554. #endif
  555. isc_encode_sql_time(&t, (ISC_TIME *) buf);
  556. break;
  557. default:
  558. convert_to_string(val);
  559. strlcpy(buf, Z_STRVAL_P(val), buf_size);
  560. }
  561. }
  562. }
  563. return SUCCESS;
  564. }
  565. /* }}} */
  566. static int _php_ibase_bind(XSQLDA *sqlda, zval ***b_vars, BIND_BUF *buf, /* {{{ */
  567. ibase_query *ib_query TSRMLS_DC)
  568. {
  569. int i, array_cnt = 0, rv = SUCCESS;
  570. for (i = 0; i < sqlda->sqld; ++i) { /* bound vars */
  571. zval *b_var = *b_vars[i];
  572. XSQLVAR *var = &sqlda->sqlvar[i];
  573. var->sqlind = &buf[i].sqlind;
  574. /* check if a NULL should be inserted */
  575. switch (Z_TYPE_P(b_var)) {
  576. int force_null;
  577. case IS_STRING:
  578. force_null = 0;
  579. /* for these types, an empty string can be handled like a NULL value */
  580. switch (var->sqltype & ~1) {
  581. case SQL_SHORT:
  582. case SQL_LONG:
  583. case SQL_INT64:
  584. case SQL_FLOAT:
  585. case SQL_DOUBLE:
  586. case SQL_TIMESTAMP:
  587. case SQL_TYPE_DATE:
  588. case SQL_TYPE_TIME:
  589. force_null = (Z_STRLEN_P(b_var) == 0);
  590. }
  591. if (! force_null) break;
  592. case IS_NULL:
  593. /* complain if this field doesn't allow NULL values */
  594. if (! (var->sqltype & 1)) {
  595. _php_ibase_module_error("Parameter %d: non-empty value required" TSRMLS_CC, i+1);
  596. rv = FAILURE;
  597. } else {
  598. buf[i].sqlind = -1;
  599. }
  600. if (var->sqltype & SQL_ARRAY) ++array_cnt;
  601. continue;
  602. }
  603. /* if we make it to this point, we must provide a value for the parameter */
  604. buf[i].sqlind = 0;
  605. var->sqldata = (void*)&buf[i].val;
  606. switch (var->sqltype & ~1) {
  607. struct tm t;
  608. case SQL_TIMESTAMP:
  609. case SQL_TYPE_DATE:
  610. case SQL_TYPE_TIME:
  611. if (Z_TYPE_P(b_var) == IS_LONG) {
  612. struct tm *res;
  613. res = php_gmtime_r(&Z_LVAL_P(b_var), &t);
  614. if (!res) {
  615. return FAILURE;
  616. }
  617. } else {
  618. #ifdef HAVE_STRPTIME
  619. char *format = INI_STR("ibase.timestampformat");
  620. convert_to_string(b_var);
  621. switch (var->sqltype & ~1) {
  622. case SQL_TYPE_DATE:
  623. format = INI_STR("ibase.dateformat");
  624. break;
  625. case SQL_TYPE_TIME:
  626. format = INI_STR("ibase.timeformat");
  627. }
  628. if (!strptime(Z_STRVAL_P(b_var), format, &t)) {
  629. /* strptime() cannot handle it, so let IB have a try */
  630. break;
  631. }
  632. #else /* ifndef HAVE_STRPTIME */
  633. break; /* let IB parse it as a string */
  634. #endif
  635. }
  636. switch (var->sqltype & ~1) {
  637. default: /* == case SQL_TIMESTAMP */
  638. isc_encode_timestamp(&t, &buf[i].val.tsval);
  639. break;
  640. case SQL_TYPE_DATE:
  641. isc_encode_sql_date(&t, &buf[i].val.dtval);
  642. break;
  643. case SQL_TYPE_TIME:
  644. isc_encode_sql_time(&t, &buf[i].val.tmval);
  645. break;
  646. }
  647. continue;
  648. case SQL_BLOB:
  649. convert_to_string(b_var);
  650. if (Z_STRLEN_P(b_var) != BLOB_ID_LEN ||
  651. !_php_ibase_string_to_quad(Z_STRVAL_P(b_var), &buf[i].val.qval)) {
  652. ibase_blob ib_blob = { NULL, BLOB_INPUT };
  653. if (isc_create_blob(IB_STATUS, &ib_query->link->handle,
  654. &ib_query->trans->handle, &ib_blob.bl_handle, &ib_blob.bl_qd)) {
  655. _php_ibase_error(TSRMLS_C);
  656. return FAILURE;
  657. }
  658. if (_php_ibase_blob_add(&b_var, &ib_blob TSRMLS_CC) != SUCCESS) {
  659. return FAILURE;
  660. }
  661. if (isc_close_blob(IB_STATUS, &ib_blob.bl_handle)) {
  662. _php_ibase_error(TSRMLS_C);
  663. return FAILURE;
  664. }
  665. buf[i].val.qval = ib_blob.bl_qd;
  666. }
  667. continue;
  668. case SQL_ARRAY:
  669. if (Z_TYPE_P(b_var) != IS_ARRAY) {
  670. convert_to_string(b_var);
  671. if (Z_STRLEN_P(b_var) != BLOB_ID_LEN ||
  672. !_php_ibase_string_to_quad(Z_STRVAL_P(b_var), &buf[i].val.qval)) {
  673. _php_ibase_module_error("Parameter %d: invalid array ID" TSRMLS_CC,i+1);
  674. rv = FAILURE;
  675. }
  676. } else {
  677. /* convert the array data into something IB can understand */
  678. ibase_array *ar = &ib_query->in_array[array_cnt];
  679. void *array_data = emalloc(ar->ar_size);
  680. ISC_QUAD array_id = { 0, 0 };
  681. if (FAILURE == _php_ibase_bind_array(b_var, array_data, ar->ar_size,
  682. ar, 0 TSRMLS_CC)) {
  683. _php_ibase_module_error("Parameter %d: failed to bind array argument"
  684. TSRMLS_CC,i+1);
  685. efree(array_data);
  686. rv = FAILURE;
  687. continue;
  688. }
  689. if (isc_array_put_slice(IB_STATUS, &ib_query->link->handle, &ib_query->trans->handle,
  690. &array_id, &ar->ar_desc, array_data, &ar->ar_size)) {
  691. _php_ibase_error(TSRMLS_C);
  692. efree(array_data);
  693. return FAILURE;
  694. }
  695. buf[i].val.qval = array_id;
  696. efree(array_data);
  697. }
  698. ++array_cnt;
  699. continue;
  700. } /* switch */
  701. /* we end up here if none of the switch cases handled the field */
  702. convert_to_string(b_var);
  703. var->sqldata = Z_STRVAL_P(b_var);
  704. var->sqllen = Z_STRLEN_P(b_var);
  705. var->sqltype = SQL_TEXT;
  706. } /* for */
  707. return rv;
  708. }
  709. /* }}} */
  710. static void _php_ibase_alloc_xsqlda(XSQLDA *sqlda) /* {{{ */
  711. {
  712. int i;
  713. for (i = 0; i < sqlda->sqld; i++) {
  714. XSQLVAR *var = &sqlda->sqlvar[i];
  715. switch (var->sqltype & ~1) {
  716. case SQL_TEXT:
  717. var->sqldata = safe_emalloc(sizeof(char), var->sqllen, 0);
  718. break;
  719. case SQL_VARYING:
  720. var->sqldata = safe_emalloc(sizeof(char), var->sqllen + sizeof(short), 0);
  721. break;
  722. case SQL_SHORT:
  723. var->sqldata = emalloc(sizeof(short));
  724. break;
  725. case SQL_LONG:
  726. var->sqldata = emalloc(sizeof(ISC_LONG));
  727. break;
  728. case SQL_FLOAT:
  729. var->sqldata = emalloc(sizeof(float));
  730. break;
  731. case SQL_DOUBLE:
  732. var->sqldata = emalloc(sizeof(double));
  733. break;
  734. case SQL_INT64:
  735. var->sqldata = emalloc(sizeof(ISC_INT64));
  736. break;
  737. case SQL_TIMESTAMP:
  738. var->sqldata = emalloc(sizeof(ISC_TIMESTAMP));
  739. break;
  740. case SQL_TYPE_DATE:
  741. var->sqldata = emalloc(sizeof(ISC_DATE));
  742. break;
  743. case SQL_TYPE_TIME:
  744. var->sqldata = emalloc(sizeof(ISC_TIME));
  745. break;
  746. case SQL_BLOB:
  747. case SQL_ARRAY:
  748. var->sqldata = emalloc(sizeof(ISC_QUAD));
  749. break;
  750. } /* switch */
  751. if (var->sqltype & 1) { /* sql NULL flag */
  752. var->sqlind = emalloc(sizeof(short));
  753. } else {
  754. var->sqlind = NULL;
  755. }
  756. } /* for */
  757. }
  758. /* }}} */
  759. static int _php_ibase_exec(INTERNAL_FUNCTION_PARAMETERS, ibase_result **ib_resultp, /* {{{ */
  760. ibase_query *ib_query, zval ***args)
  761. {
  762. XSQLDA *in_sqlda = NULL, *out_sqlda = NULL;
  763. BIND_BUF *bind_buf = NULL;
  764. int i, rv = FAILURE;
  765. static char info_count[] = { isc_info_sql_records };
  766. char result[64];
  767. ISC_STATUS isc_result;
  768. int argc = ib_query->in_sqlda ? ib_query->in_sqlda->sqld : 0;
  769. RESET_ERRMSG;
  770. for (i = 0; i < argc; ++i) {
  771. SEPARATE_ZVAL(args[i]);
  772. }
  773. switch (ib_query->statement_type) {
  774. isc_tr_handle tr;
  775. ibase_tr_list **l;
  776. ibase_trans *trans;
  777. case isc_info_sql_stmt_start_trans:
  778. /* a SET TRANSACTION statement should be executed with a NULL trans handle */
  779. tr = NULL;
  780. if (isc_dsql_execute_immediate(IB_STATUS, &ib_query->link->handle, &tr, 0,
  781. ib_query->query, ib_query->dialect, NULL)) {
  782. _php_ibase_error(TSRMLS_C);
  783. goto _php_ibase_exec_error;
  784. }
  785. trans = (ibase_trans *) emalloc(sizeof(ibase_trans));
  786. trans->handle = tr;
  787. trans->link_cnt = 1;
  788. trans->affected_rows = 0;
  789. trans->db_link[0] = ib_query->link;
  790. if (ib_query->link->tr_list == NULL) {
  791. ib_query->link->tr_list = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list));
  792. ib_query->link->tr_list->trans = NULL;
  793. ib_query->link->tr_list->next = NULL;
  794. }
  795. /* link the transaction into the connection-transaction list */
  796. for (l = &ib_query->link->tr_list; *l != NULL; l = &(*l)->next);
  797. *l = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list));
  798. (*l)->trans = trans;
  799. (*l)->next = NULL;
  800. ZEND_REGISTER_RESOURCE(return_value, trans, le_trans);
  801. return SUCCESS;
  802. case isc_info_sql_stmt_commit:
  803. case isc_info_sql_stmt_rollback:
  804. if (isc_dsql_execute_immediate(IB_STATUS, &ib_query->link->handle,
  805. &ib_query->trans->handle, 0, ib_query->query, ib_query->dialect, NULL)) {
  806. _php_ibase_error(TSRMLS_C);
  807. goto _php_ibase_exec_error;
  808. }
  809. if (ib_query->trans->handle == NULL && ib_query->trans_res_id != 0) {
  810. /* transaction was released by the query and was a registered resource,
  811. so we have to release it */
  812. zend_list_delete(ib_query->trans_res_id);
  813. }
  814. RETVAL_TRUE;
  815. return SUCCESS;
  816. default:
  817. RETVAL_FALSE;
  818. }
  819. /* allocate sqlda and output buffers */
  820. if (ib_query->out_sqlda) { /* output variables in select, select for update */
  821. ibase_result *res;
  822. IBDEBUG("Query wants XSQLDA for output");
  823. res = emalloc(sizeof(ibase_result)+sizeof(ibase_array)*max(0,ib_query->out_array_cnt-1));
  824. res->link = ib_query->link;
  825. res->trans = ib_query->trans;
  826. res->stmt = ib_query->stmt;
  827. /* ib_result and ib_query point at each other to handle release of statement handle properly */
  828. res->query = ib_query;
  829. ib_query->result = res;
  830. res->statement_type = ib_query->statement_type;
  831. res->has_more_rows = 1;
  832. out_sqlda = res->out_sqlda = emalloc(XSQLDA_LENGTH(ib_query->out_sqlda->sqld));
  833. memcpy(out_sqlda, ib_query->out_sqlda, XSQLDA_LENGTH(ib_query->out_sqlda->sqld));
  834. _php_ibase_alloc_xsqlda(out_sqlda);
  835. if (ib_query->out_array) {
  836. memcpy(&res->out_array, ib_query->out_array, sizeof(ibase_array)*ib_query->out_array_cnt);
  837. }
  838. *ib_resultp = res;
  839. }
  840. if (ib_query->in_sqlda) { /* has placeholders */
  841. IBDEBUG("Query wants XSQLDA for input");
  842. in_sqlda = emalloc(XSQLDA_LENGTH(ib_query->in_sqlda->sqld));
  843. memcpy(in_sqlda, ib_query->in_sqlda, XSQLDA_LENGTH(ib_query->in_sqlda->sqld));
  844. bind_buf = safe_emalloc(sizeof(BIND_BUF), ib_query->in_sqlda->sqld, 0);
  845. if (_php_ibase_bind(in_sqlda, args, bind_buf, ib_query TSRMLS_CC) == FAILURE) {
  846. IBDEBUG("Could not bind input XSQLDA");
  847. goto _php_ibase_exec_error;
  848. }
  849. }
  850. if (ib_query->statement_type == isc_info_sql_stmt_exec_procedure) {
  851. isc_result = isc_dsql_execute2(IB_STATUS, &ib_query->trans->handle,
  852. &ib_query->stmt, SQLDA_CURRENT_VERSION, in_sqlda, out_sqlda);
  853. } else {
  854. isc_result = isc_dsql_execute(IB_STATUS, &ib_query->trans->handle,
  855. &ib_query->stmt, SQLDA_CURRENT_VERSION, in_sqlda);
  856. }
  857. if (isc_result) {
  858. IBDEBUG("Could not execute query");
  859. _php_ibase_error(TSRMLS_C);
  860. goto _php_ibase_exec_error;
  861. }
  862. ib_query->trans->affected_rows = 0;
  863. switch (ib_query->statement_type) {
  864. unsigned long affected_rows;
  865. case isc_info_sql_stmt_insert:
  866. case isc_info_sql_stmt_update:
  867. case isc_info_sql_stmt_delete:
  868. case isc_info_sql_stmt_exec_procedure:
  869. if (isc_dsql_sql_info(IB_STATUS, &ib_query->stmt, sizeof(info_count),
  870. info_count, sizeof(result), result)) {
  871. _php_ibase_error(TSRMLS_C);
  872. goto _php_ibase_exec_error;
  873. }
  874. affected_rows = 0;
  875. if (result[0] == isc_info_sql_records) {
  876. unsigned i = 3, result_size = isc_vax_integer(&result[1],2);
  877. while (result[i] != isc_info_end && i < result_size) {
  878. short len = (short)isc_vax_integer(&result[i+1],2);
  879. if (result[i] != isc_info_req_select_count) {
  880. affected_rows += isc_vax_integer(&result[i+3],len);
  881. }
  882. i += len+3;
  883. }
  884. }
  885. ib_query->trans->affected_rows = affected_rows;
  886. if (!ib_query->out_sqlda) { /* no result set is being returned */
  887. if (affected_rows) {
  888. RETVAL_LONG(affected_rows);
  889. } else {
  890. RETVAL_TRUE;
  891. }
  892. break;
  893. }
  894. default:
  895. RETVAL_TRUE;
  896. }
  897. rv = SUCCESS;
  898. _php_ibase_exec_error:
  899. if (in_sqlda) {
  900. efree(in_sqlda);
  901. }
  902. if (bind_buf)
  903. efree(bind_buf);
  904. if (rv == FAILURE) {
  905. if (*ib_resultp) {
  906. efree(*ib_resultp);
  907. *ib_resultp = NULL;
  908. }
  909. if (out_sqlda) {
  910. _php_ibase_free_xsqlda(out_sqlda);
  911. }
  912. }
  913. return rv;
  914. }
  915. /* }}} */
  916. /* {{{ proto mixed ibase_query([resource link_identifier, [ resource link_identifier, ]] string query [, mixed bind_arg [, mixed bind_arg [, ...]]])
  917. Execute a query */
  918. PHP_FUNCTION(ibase_query)
  919. {
  920. zval *zlink, *ztrans, ***bind_args = NULL;
  921. char *query;
  922. int bind_i, query_len, bind_num;
  923. long trans_res_id = 0;
  924. ibase_db_link *ib_link = NULL;
  925. ibase_trans *trans = NULL;
  926. ibase_query ib_query = { NULL, NULL, 0, 0 };
  927. ibase_result *result = NULL;
  928. RESET_ERRMSG;
  929. RETVAL_FALSE;
  930. switch (ZEND_NUM_ARGS()) {
  931. long l;
  932. default:
  933. if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 3 TSRMLS_CC, "rrs",
  934. &zlink, &ztrans, &query, &query_len)) {
  935. ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link*, &zlink, -1, LE_LINK, le_link, le_plink);
  936. ZEND_FETCH_RESOURCE(trans, ibase_trans*, &ztrans, -1, LE_TRANS, le_trans);
  937. trans_res_id = Z_LVAL_P(ztrans);
  938. bind_i = 3;
  939. break;
  940. }
  941. case 2:
  942. if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 2 TSRMLS_CC, "rs",
  943. &zlink, &query, &query_len)) {
  944. _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, &zlink, &ib_link, &trans);
  945. if (trans != NULL) {
  946. trans_res_id = Z_LVAL_P(zlink);
  947. }
  948. bind_i = 2;
  949. break;
  950. }
  951. /* the statement is 'CREATE DATABASE ...' if the link argument is IBASE_CREATE */
  952. if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS()
  953. TSRMLS_CC, "ls", &l, &query, &query_len) && l == PHP_IBASE_CREATE) {
  954. isc_db_handle db = NULL;
  955. isc_tr_handle trans = NULL;
  956. if (((l = INI_INT("ibase.max_links")) != -1) && (IBG(num_links) >= l)) {
  957. _php_ibase_module_error("CREATE DATABASE is not allowed: maximum link count "
  958. "(%ld) reached" TSRMLS_CC, l);
  959. } else if (isc_dsql_execute_immediate(IB_STATUS, &db, &trans, (short)query_len,
  960. query, SQL_DIALECT_CURRENT, NULL)) {
  961. _php_ibase_error(TSRMLS_C);
  962. } else if (!db) {
  963. _php_ibase_module_error("Connection to created database could not be "
  964. "established" TSRMLS_CC);
  965. } else {
  966. /* register the link as a resource; unfortunately, we cannot register
  967. it in the hash table, because we don't know the connection params */
  968. ib_link = (ibase_db_link *) emalloc(sizeof(ibase_db_link));
  969. ib_link->handle = db;
  970. ib_link->dialect = SQL_DIALECT_CURRENT;
  971. ib_link->tr_list = NULL;
  972. ib_link->event_head = NULL;
  973. ZEND_REGISTER_RESOURCE(return_value, ib_link, le_link);
  974. zend_list_addref(Z_LVAL_P(return_value));
  975. IBG(default_link) = Z_LVAL_P(return_value);
  976. ++IBG(num_links);
  977. }
  978. return;
  979. }
  980. case 1:
  981. case 0:
  982. if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() ? 1 : 0 TSRMLS_CC, "s", &query,
  983. &query_len)) {
  984. ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, IBG(default_link), LE_LINK,
  985. le_link, le_plink);
  986. bind_i = 1;
  987. break;
  988. }
  989. return;
  990. }
  991. /* open default transaction */
  992. if (ib_link == NULL || FAILURE == _php_ibase_def_trans(ib_link, &trans TSRMLS_CC)
  993. || FAILURE == _php_ibase_alloc_query(&ib_query, ib_link, trans, query, ib_link->dialect,
  994. trans_res_id TSRMLS_CC)) {
  995. return;
  996. }
  997. do {
  998. int bind_n = ZEND_NUM_ARGS() - bind_i,
  999. expected_n = ib_query.in_sqlda ? ib_query.in_sqlda->sqld : 0;
  1000. if (bind_n != expected_n) {
  1001. php_error_docref(NULL TSRMLS_CC, (bind_n < expected_n) ? E_WARNING : E_NOTICE,
  1002. "Statement expects %d arguments, %d given", expected_n, bind_n);
  1003. if (bind_n < expected_n) {
  1004. break;
  1005. }
  1006. } else if (bind_n > 0) {
  1007. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &bind_args, &bind_num) == FAILURE) {
  1008. return;
  1009. }
  1010. }
  1011. if (FAILURE == _php_ibase_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, &result, &ib_query,
  1012. &bind_args[bind_i])) {
  1013. break;
  1014. }
  1015. if (result != NULL) { /* statement returns a result */
  1016. result->type = QUERY_RESULT;
  1017. /* EXECUTE PROCEDURE returns only one row => statement can be released immediately */
  1018. if (ib_query.statement_type != isc_info_sql_stmt_exec_procedure) {
  1019. ib_query.stmt = NULL; /* keep stmt when free query */
  1020. }
  1021. ZEND_REGISTER_RESOURCE(return_value, result, le_result);
  1022. }
  1023. } while (0);
  1024. _php_ibase_free_query(&ib_query TSRMLS_CC);
  1025. if (bind_args) {
  1026. efree(bind_args);
  1027. }
  1028. }
  1029. /* }}} */
  1030. /* {{{ proto int ibase_affected_rows( [ resource link_identifier ] )
  1031. Returns the number of rows affected by the previous INSERT, UPDATE or DELETE statement */
  1032. PHP_FUNCTION(ibase_affected_rows)
  1033. {
  1034. ibase_trans *trans = NULL;
  1035. ibase_db_link *ib_link;
  1036. zval *arg = NULL;
  1037. RESET_ERRMSG;
  1038. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &arg) == FAILURE) {
  1039. return;
  1040. }
  1041. if (!arg) {
  1042. ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, IBG(default_link), LE_LINK, le_link, le_plink);
  1043. if (ib_link->tr_list == NULL || ib_link->tr_list->trans == NULL) {
  1044. RETURN_FALSE;
  1045. }
  1046. trans = ib_link->tr_list->trans;
  1047. } else {
  1048. /* one id was passed, could be db or trans id */
  1049. _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, &arg, &ib_link, &trans);
  1050. if (trans == NULL) {
  1051. ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, &arg, -1, LE_LINK, le_link, le_plink);
  1052. if (ib_link->tr_list == NULL || ib_link->tr_list->trans == NULL) {
  1053. RETURN_FALSE;
  1054. }
  1055. trans = ib_link->tr_list->trans;
  1056. }
  1057. }
  1058. RETURN_LONG(trans->affected_rows);
  1059. }
  1060. /* }}} */
  1061. /* {{{ proto int ibase_num_rows( resource result_identifier )
  1062. Return the number of rows that are available in a result */
  1063. #if abies_0
  1064. PHP_FUNCTION(ibase_num_rows)
  1065. {
  1066. /**
  1067. * As this function relies on the InterBase API function isc_dsql_sql_info()
  1068. * which has a couple of limitations (which I hope will be fixed in future
  1069. * releases of Firebird), this function is fairly useless. I'm leaving it
  1070. * in place for people who can live with the limitations, which I only
  1071. * found out about after I had implemented it anyway.
  1072. *
  1073. * Currently, there's no way to determine how many rows can be fetched from
  1074. * a cursor. The only number that _can_ be determined is the number of rows
  1075. * that have already been pre-fetched by the client library.
  1076. * This implies the following:
  1077. * - num_rows() always returns zero before the first fetch;
  1078. * - num_rows() for SELECT ... FOR UPDATE is broken -> never returns a
  1079. * higher number than the number of records fetched so far (no pre-fetch);
  1080. * - the result of num_rows() for other statements is merely a lower bound
  1081. * on the number of records => calling ibase_num_rows() again after a couple
  1082. * of fetches will most likely return a new (higher) figure for large result
  1083. * sets.
  1084. */
  1085. zval *result_arg;
  1086. ibase_result *ib_result;
  1087. static char info_count[] = {isc_info_sql_records};
  1088. char result[64];
  1089. RESET_ERRMSG;
  1090. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result_arg) == FAILURE) {
  1091. return;
  1092. }
  1093. ZEND_FETCH_RESOURCE(ib_result, ibase_result *, &result_arg, -1, LE_RESULT, le_result);
  1094. if (isc_dsql_sql_info(IB_STATUS, &ib_result->stmt, sizeof(info_count), info_count, sizeof(result), result)) {
  1095. _php_ibase_error(TSRMLS_C);
  1096. RETURN_FALSE;
  1097. }
  1098. if (result[0] == isc_info_sql_records) {
  1099. unsigned i = 3, result_size = isc_vax_integer(&result[1],2);
  1100. while (result[i] != isc_info_end && i < result_size) {
  1101. short len = (short)isc_vax_integer(&result[i+1],2);
  1102. if (result[i] == isc_info_req_select_count) {
  1103. RETURN_LONG(isc_vax_integer(&result[i+3],len));
  1104. }
  1105. i += len+3;
  1106. }
  1107. }
  1108. }
  1109. #endif
  1110. /* }}} */
  1111. static int _php_ibase_var_zval(zval *val, void *data, int type, int len, /* {{{ */
  1112. int scale, int flag TSRMLS_DC)
  1113. {
  1114. static ISC_INT64 const scales[] = { 1, 10, 100, 1000,
  1115. 10000,
  1116. 100000,
  1117. 1000000,
  1118. 10000000,
  1119. 100000000,
  1120. 1000000000,
  1121. LL_LIT(10000000000),
  1122. LL_LIT(100000000000),
  1123. LL_LIT(1000000000000),
  1124. LL_LIT(10000000000000),
  1125. LL_LIT(100000000000000),
  1126. LL_LIT(1000000000000000),
  1127. LL_LIT(10000000000000000),
  1128. LL_LIT(100000000000000000),
  1129. LL_LIT(1000000000000000000)
  1130. };
  1131. switch (type & ~1) {
  1132. unsigned short l;
  1133. long n;
  1134. char string_data[255];
  1135. struct tm t;
  1136. char *format;
  1137. case SQL_VARYING:
  1138. len = ((IBVARY *) data)->vary_length;
  1139. data = ((IBVARY *) data)->vary_string;
  1140. /* no break */
  1141. case SQL_TEXT:
  1142. {
  1143. ZVAL_STRINGL(val,(char *) data,len,1);
  1144. }
  1145. break;
  1146. case SQL_SHORT:
  1147. n = *(short *) data;
  1148. goto _sql_long;
  1149. case SQL_INT64:
  1150. #if (SIZEOF_LONG >= 8)
  1151. n = *(long *) data;
  1152. goto _sql_long;
  1153. #else
  1154. if (scale == 0) {
  1155. l = slprintf(string_data, sizeof(string_data), "%" LL_MASK "d", *(ISC_INT64 *) data);
  1156. ZVAL_STRINGL(val,string_data,l,1);
  1157. } else {
  1158. ISC_INT64 n = *(ISC_INT64 *) data, f = scales[-scale];
  1159. if (n >= 0) {
  1160. l = slprintf(string_data, sizeof(string_data), "%" LL_MASK "d.%0*" LL_MASK "d", n / f, -scale, n % f);
  1161. } else if (n <= -f) {
  1162. l = slprintf(string_data, sizeof(string_data), "%" LL_MASK "d.%0*" LL_MASK "d", n / f, -scale, -n % f);
  1163. } else {
  1164. l = slprintf(string_data, sizeof(string_data), "-0.%0*" LL_MASK "d", -scale, -n % f);
  1165. }
  1166. ZVAL_STRINGL(val,string_data,l,1);
  1167. }
  1168. break;
  1169. #endif
  1170. case SQL_LONG:
  1171. n = *(ISC_LONG *) data;
  1172. _sql_long:
  1173. if (scale == 0) {
  1174. ZVAL_LONG(val,n);
  1175. } else {
  1176. long f = (long) scales[-scale];
  1177. if (n >= 0) {
  1178. l = slprintf(string_data, sizeof(string_data), "%ld.%0*ld", n / f, -scale, n % f);
  1179. } else if (n <= -f) {
  1180. l = slprintf(string_data, sizeof(string_data), "%ld.%0*ld", n / f, -scale, -n % f);
  1181. } else {
  1182. l = slprintf(string_data, sizeof(string_data), "-0.%0*ld", -scale, -n % f);
  1183. }
  1184. ZVAL_STRINGL(val,string_data,l,1);
  1185. }
  1186. break;
  1187. case SQL_FLOAT:
  1188. ZVAL_DOUBLE(val, *(float *) data);
  1189. break;
  1190. case SQL_DOUBLE:
  1191. ZVAL_DOUBLE(val, *(double *) data);
  1192. break;
  1193. case SQL_DATE: /* == case SQL_TIMESTAMP: */
  1194. format = INI_STR("ibase.timestampformat");
  1195. isc_decode_timestamp((ISC_TIMESTAMP *) data, &t);
  1196. goto format_date_time;
  1197. case SQL_TYPE_DATE:
  1198. format = INI_STR("ibase.dateformat");
  1199. isc_decode_sql_date((ISC_DATE *) data, &t);
  1200. goto format_date_time;
  1201. case SQL_TYPE_TIME:
  1202. format = INI_STR("ibase.timeformat");
  1203. isc_decode_sql_time((ISC_TIME *) data, &t);
  1204. format_date_time:
  1205. /*
  1206. XXX - Might have to remove this later - seems that isc_decode_date()
  1207. always sets tm_isdst to 0, sometimes incorrectly (InterBase 6 bug?)
  1208. */
  1209. t.tm_isdst = -1;
  1210. #if HAVE_TM_ZONE
  1211. t.tm_zone = tzname[0];
  1212. #endif
  1213. if (flag & PHP_IBASE_UNIXTIME) {
  1214. ZVAL_LONG(val, mktime(&t));
  1215. } else {
  1216. #if HAVE_STRFTIME
  1217. l = strftime(string_data, sizeof(string_data), format, &t);
  1218. #else
  1219. switch (type & ~1) {
  1220. default:
  1221. l = slprintf(string_data, sizeof(string_data), "%02d/%02d/%4d %02d:%02d:%02d", t.tm_mon+1, t.tm_mday,
  1222. t.tm_year + 1900, t.tm_hour, t.tm_min, t.tm_sec);
  1223. break;
  1224. case SQL_TYPE_DATE:
  1225. l = slprintf(string_data, sizeof(string_data), "%02d/%02d/%4d", t.tm_mon + 1, t.tm_mday, t.tm_year+1900);
  1226. break;
  1227. case SQL_TYPE_TIME:
  1228. l = slprintf(string_data, sizeof(string_data), "%02d:%02d:%02d", t.tm_hour, t.tm_min, t.tm_sec);
  1229. break;
  1230. }
  1231. #endif
  1232. ZVAL_STRINGL(val,string_data,l,1);
  1233. break;
  1234. }
  1235. } /* switch (type) */
  1236. return SUCCESS;
  1237. }
  1238. /* }}} */
  1239. static int _php_ibase_arr_zval(zval *ar_zval, char *data, unsigned long data_size, /* {{{ */
  1240. ibase_array *ib_array, int dim, int flag TSRMLS_DC)
  1241. {
  1242. /**
  1243. * Create multidimension array - recursion function
  1244. */
  1245. int
  1246. u_bound = ib_array->ar_desc.array_desc_bounds[dim].array_bound_upper,
  1247. l_bound = ib_array->ar_desc.array_desc_bounds[dim].array_bound_lower,
  1248. dim_len = 1 + u_bound - l_bound;
  1249. unsigned short i;
  1250. if (dim < ib_array->ar_desc.array_desc_dimensions) { /* array again */
  1251. unsigned long slice_size = data_size / dim_len;
  1252. array_init(ar_zval);
  1253. for (i = 0; i < dim_len; ++i) {
  1254. zval *slice_zval;
  1255. ALLOC_INIT_ZVAL(slice_zval);
  1256. /* recursion here */
  1257. if (FAILURE == _php_ibase_arr_zval(slice_zval, data, slice_size, ib_array, dim + 1,
  1258. flag TSRMLS_CC)) {
  1259. return FAILURE;
  1260. }
  1261. data += slice_size;
  1262. add_index_zval(ar_zval,l_bound+i,slice_zval);
  1263. }
  1264. } else { /* data at last */
  1265. if (FAILURE == _php_ibase_var_zval(ar_zval, data, ib_array->el_type,
  1266. ib_array->ar_desc.array_desc_length, ib_array->ar_desc.array_desc_scale, flag TSRMLS_CC)) {
  1267. return FAILURE;
  1268. }
  1269. /* fix for peculiar handling of VARCHAR arrays;
  1270. truncate the field to the cstring length */
  1271. if (ib_array->ar_desc.array_desc_dtype == blr_varying ||
  1272. ib_array->ar_desc.array_desc_dtype == blr_varying2) {
  1273. Z_STRLEN_P(ar_zval) = strlen(Z_STRVAL_P(ar_zval));
  1274. }
  1275. }
  1276. return SUCCESS;
  1277. }
  1278. /* }}} */
  1279. static void _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int fetch_type) /* {{{ */
  1280. {
  1281. zval *result_arg;
  1282. long i, array_cnt = 0, flag = 0;
  1283. ibase_result *ib_result;
  1284. RESET_ERRMSG;
  1285. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &result_arg, &flag)) {
  1286. return;
  1287. }
  1288. ZEND_FETCH_RESOURCE(ib_result, ibase_result *, &result_arg, -1, LE_RESULT, le_result);
  1289. if (ib_result->out_sqlda == NULL || !ib_result->has_more_rows) {
  1290. RETURN_FALSE;
  1291. }
  1292. if (ib_result->statement_type != isc_info_sql_stmt_exec_procedure) {
  1293. if (isc_dsql_fetch(IB_STATUS, &ib_result->stmt, 1, ib_result->out_sqlda)) {
  1294. ib_result->has_more_rows = 0;
  1295. if (IB_STATUS[0] && IB_STATUS[1]) { /* error in fetch */
  1296. _php_ibase_error(TSRMLS_C);
  1297. }
  1298. RETURN_FALSE;
  1299. }
  1300. } else {
  1301. ib_result->has_more_rows = 0;
  1302. }
  1303. array_init(return_value);
  1304. for (i = 0; i < ib_result->out_sqlda->sqld; ++i) {
  1305. XSQLVAR *var = &ib_result->out_sqlda->sqlvar[i];
  1306. char buf[METADATALENGTH+4], *alias = var->aliasname;
  1307. if (! (fetch_type & FETCH_ROW)) {
  1308. int i = 0;
  1309. char const *base = "FIELD"; /* use 'FIELD' if name is empty */
  1310. /**
  1311. * Ensure no two columns have identical names:
  1312. * keep generating new names until we find one that is unique.
  1313. */
  1314. switch (*alias) {
  1315. void *p;
  1316. default:
  1317. i = 1;
  1318. base = alias;
  1319. while (SUCCESS == zend_symtable_find(
  1320. Z_ARRVAL_P(return_value),alias,strlen(alias)+1,&p)) {
  1321. case '\0':
  1322. snprintf(alias = buf, sizeof(buf), "%s_%02d", base, i++);
  1323. }
  1324. }
  1325. }
  1326. if (((var->sqltype & 1) == 0) || *var->sqlind != -1) {
  1327. zval *result;
  1328. ALLOC_INIT_ZVAL(result);
  1329. switch (var->sqltype & ~1) {
  1330. default:
  1331. _php_ibase_var_zval(result, var->sqldata, var->sqltype, var->sqllen,
  1332. var->sqlscale, flag TSRMLS_CC);
  1333. break;
  1334. case SQL_BLOB:
  1335. if (flag & PHP_IBASE_FETCH_BLOBS) { /* fetch blob contents into hash */
  1336. ibase_blob blob_handle;
  1337. unsigned long max_len = 0;
  1338. static char bl_items[] = {isc_info_blob_total_length};
  1339. char bl_info[20];
  1340. unsigned short i;
  1341. blob_handle.bl_handle = NULL;
  1342. blob_handle.bl_qd = *(ISC_QUAD *) var->sqldata;
  1343. if (isc_open_blob(IB_STATUS, &ib_result->link->handle, &ib_result->trans->handle,
  1344. &blob_handle.bl_handle, &blob_handle.bl_qd)) {
  1345. _php_ibase_error(TSRMLS_C);
  1346. goto _php_ibase_fetch_error;
  1347. }
  1348. if (isc_blob_info(IB_STATUS, &blob_handle.bl_handle, sizeof(bl_items),
  1349. bl_items, sizeof(bl_info), bl_info)) {
  1350. _php_ibase_error(TSRMLS_C);
  1351. goto _php_ibase_fetch_error;
  1352. }
  1353. /* find total length of blob's data */
  1354. for (i = 0; i < sizeof(bl_info); ) {
  1355. unsigned short item_len;
  1356. char item = bl_info[i++];
  1357. if (item == isc_info_end || item == isc_info_truncated ||
  1358. item == isc_info_error || i >= sizeof(bl_info)) {
  1359. _php_ibase_module_error("Could not determine BLOB size (internal error)"
  1360. TSRMLS_CC);
  1361. goto _php_ibase_fetch_error;
  1362. }
  1363. item_len = (unsigned short) isc_vax_integer(&bl_info[i], 2);
  1364. if (item == isc_info_blob_total_length) {
  1365. max_len = isc_vax_integer(&bl_info[i+2], item_len);
  1366. break;
  1367. }
  1368. i += item_len+2;
  1369. }
  1370. if (max_len == 0) {
  1371. ZVAL_STRING(result, "", 1);
  1372. } else if (SUCCESS != _php_ibase_blob_get(result, &blob_handle,
  1373. max_len TSRMLS_CC)) {
  1374. goto _php_ibase_fetch_error;
  1375. }
  1376. if (isc_close_blob(IB_STATUS, &blob_handle.bl_handle)) {
  1377. _php_ibase_error(TSRMLS_C);
  1378. goto _php_ibase_fetch_error;
  1379. }
  1380. } else { /* blob id only */
  1381. ISC_QUAD bl_qd = *(ISC_QUAD *) var->sqldata;
  1382. ZVAL_STRINGL(result,_php_ibase_quad_to_string(bl_qd), BLOB_ID_LEN, 0);
  1383. }
  1384. break;
  1385. case SQL_ARRAY:
  1386. if (flag & PHP_IBASE_FETCH_ARRAYS) { /* array can be *huge* so only fetch if asked */
  1387. ISC_QUAD ar_qd = *(ISC_QUAD *) var->sqldata;
  1388. ibase_array *ib_array = &ib_result->out_array[array_cnt++];
  1389. void *ar_data = emalloc(ib_array->ar_size);
  1390. if (isc_array_get_slice(IB_STATUS, &ib_result->link->handle,
  1391. &ib_result->trans->handle, &ar_qd, &ib_array->ar_desc,
  1392. ar_data, &ib_array->ar_size)) {
  1393. _php_ibase_error(TSRMLS_C);
  1394. efree(ar_data);
  1395. goto _php_ibase_fetch_error;
  1396. }
  1397. if (FAILURE == _php_ibase_arr_zval(result, ar_data, ib_array->ar_size, ib_array,
  1398. 0, flag TSRMLS_CC)) {
  1399. efree(ar_data);
  1400. goto _php_ibase_fetch_error;
  1401. }
  1402. efree(ar_data);
  1403. } else { /* blob id only */
  1404. ISC_QUAD ar_qd = *(ISC_QUAD *) var->sqldata;
  1405. ZVAL_STRINGL(result,_php_ibase_quad_to_string(ar_qd), BLOB_ID_LEN, 0);
  1406. }
  1407. break;
  1408. _php_ibase_fetch_error:
  1409. zval_dtor(result);
  1410. FREE_ZVAL(result);
  1411. RETURN_FALSE;
  1412. } /* switch */
  1413. if (fetch_type & FETCH_ROW) {
  1414. add_index_zval(return_value, i, result);
  1415. } else {
  1416. add_assoc_zval(return_value, alias, result);
  1417. }
  1418. } else {
  1419. if (fetch_type & FETCH_ROW) {
  1420. add_index_null(return_value, i);
  1421. } else {
  1422. add_assoc_null(return_value, alias);
  1423. }
  1424. }
  1425. } /* for field */
  1426. }
  1427. /* }}} */
  1428. /* {{{ proto array ibase_fetch_row(resource result [, int fetch_flags])
  1429. Fetch a row from the results of a query */
  1430. PHP_FUNCTION(ibase_fetch_row)
  1431. {
  1432. _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, FETCH_ROW);
  1433. }
  1434. /* }}} */
  1435. /* {{{ proto array ibase_fetch_assoc(resource result [, int fetch_flags])
  1436. Fetch a row from the results of a query */
  1437. PHP_FUNCTION(ibase_fetch_assoc)
  1438. {
  1439. _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, FETCH_ARRAY);
  1440. }
  1441. /* }}} */
  1442. /* {{{ proto object ibase_fetch_object(resource result [, int fetch_flags])
  1443. Fetch a object from the results of a query */
  1444. PHP_FUNCTION(ibase_fetch_object)
  1445. {
  1446. _php_ibase_fetch_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, FETCH_ARRAY);
  1447. if (Z_TYPE_P(return_value) == IS_ARRAY) {
  1448. object_and_properties_init(return_value, ZEND_STANDARD_CLASS_DEF_PTR, Z_ARRVAL_P(return_value));
  1449. }
  1450. }
  1451. /* }}} */
  1452. /* {{{ proto bool ibase_name_result(resource result, string name)
  1453. Assign a name to a result for use with ... WHERE CURRENT OF <name> statements */
  1454. PHP_FUNCTION(ibase_name_result)
  1455. {
  1456. zval *result_arg;
  1457. char *name_arg;
  1458. int name_arg_len;
  1459. ibase_result *ib_result;
  1460. RESET_ERRMSG;
  1461. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &result_arg, &name_arg, &name_arg_len) == FAILURE) {
  1462. return;
  1463. }
  1464. ZEND_FETCH_RESOURCE(ib_result, ibase_result *, &result_arg, -1, LE_RESULT, le_result);
  1465. if (isc_dsql_set_cursor_name(IB_STATUS, &ib_result->stmt, name_arg, 0)) {
  1466. _php_ibase_error(TSRMLS_C);
  1467. RETURN_FALSE;
  1468. }
  1469. RETURN_TRUE;
  1470. }
  1471. /* }}} */
  1472. /* {{{ proto bool ibase_free_result(resource result)
  1473. Free the memory used by a result */
  1474. PHP_FUNCTION(ibase_free_result)
  1475. {
  1476. zval *result_arg;
  1477. ibase_result *ib_result;
  1478. RESET_ERRMSG;
  1479. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result_arg) == FAILURE) {
  1480. return;
  1481. }
  1482. ZEND_FETCH_RESOURCE(ib_result, ibase_result *, &result_arg, -1, LE_RESULT, le_result);
  1483. zend_list_delete(Z_RESVAL_P(result_arg));
  1484. RETURN_TRUE;
  1485. }
  1486. /* }}} */
  1487. /* {{{ proto resource ibase_prepare(resource link_identifier[, string query [, resource trans_identifier ]])
  1488. Prepare a query for later execution */
  1489. PHP_FUNCTION(ibase_prepare)
  1490. {
  1491. zval *link_arg, *trans_arg;
  1492. ibase_db_link *ib_link;
  1493. ibase_trans *trans = NULL;
  1494. int query_len, trans_res_id = 0;
  1495. ibase_query *ib_query;
  1496. char *query;
  1497. RESET_ERRMSG;
  1498. if (ZEND_NUM_ARGS() == 1) {
  1499. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &query, &query_len) == FAILURE) {
  1500. return;
  1501. }
  1502. ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, IBG(default_link), LE_LINK, le_link, le_plink);
  1503. } else if (ZEND_NUM_ARGS() == 2) {
  1504. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &link_arg, &query, &query_len) == FAILURE) {
  1505. return;
  1506. }

Large files files are truncated, but you can click here to view the full file