PageRenderTime 57ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/ext/oci8/oci8_statement.c

http://github.com/infusion/PHP
C | 1722 lines | 1329 code | 253 blank | 140 comment | 346 complexity | cc9d09745e208a77376e1a00c5027ff5 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause
  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: Stig Sæther Bakken <ssb@php.net> |
  16. | Thies C. Arntzen <thies@thieso.net> |
  17. | |
  18. | Collection support by Andy Sautins <asautins@veripost.net> |
  19. | Temporary LOB support by David Benson <dbenson@mancala.com> |
  20. | ZTS per process OCIPLogon by Harald Radi <harald.radi@nme.at> |
  21. | |
  22. | Redesigned by: Antony Dovgal <antony@zend.com> |
  23. | Andi Gutmans <andi@zend.com> |
  24. | Wez Furlong <wez@omniti.com> |
  25. +----------------------------------------------------------------------+
  26. */
  27. /* $Id: oci8_statement.c 306939 2011-01-01 02:19:59Z felipe $ */
  28. #ifdef HAVE_CONFIG_H
  29. #include "config.h"
  30. #endif
  31. #include "php.h"
  32. #include "ext/standard/info.h"
  33. #include "php_ini.h"
  34. #if HAVE_OCI8
  35. #include "php_oci8.h"
  36. #include "php_oci8_int.h"
  37. /* {{{ php_oci_statement_create()
  38. Create statemend handle and allocate necessary resources */
  39. php_oci_statement *php_oci_statement_create (php_oci_connection *connection, char *query, int query_len TSRMLS_DC)
  40. {
  41. php_oci_statement *statement;
  42. statement = ecalloc(1,sizeof(php_oci_statement));
  43. if (!query_len) {
  44. /* do not allocate stmt handle for refcursors, we'll get it from OCIStmtPrepare2() */
  45. PHP_OCI_CALL(OCIHandleAlloc, (connection->env, (dvoid **)&(statement->stmt), OCI_HTYPE_STMT, 0, NULL));
  46. }
  47. PHP_OCI_CALL(OCIHandleAlloc, (connection->env, (dvoid **)&(statement->err), OCI_HTYPE_ERROR, 0, NULL));
  48. if (query_len > 0) {
  49. PHP_OCI_CALL_RETURN(connection->errcode, OCIStmtPrepare2,
  50. (
  51. connection->svc,
  52. &(statement->stmt),
  53. connection->err,
  54. (text *)query,
  55. query_len,
  56. NULL,
  57. 0,
  58. OCI_NTV_SYNTAX,
  59. OCI_DEFAULT
  60. )
  61. );
  62. if (connection->errcode != OCI_SUCCESS) {
  63. connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
  64. PHP_OCI_CALL(OCIStmtRelease, (statement->stmt, statement->err, NULL, 0, statement->errcode ? OCI_STRLS_CACHE_DELETE : OCI_DEFAULT));
  65. PHP_OCI_CALL(OCIHandleFree,(statement->err, OCI_HTYPE_ERROR));
  66. efree(statement);
  67. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  68. return NULL;
  69. }
  70. }
  71. if (query && query_len) {
  72. statement->last_query = estrndup(query, query_len);
  73. statement->last_query_len = query_len;
  74. }
  75. else {
  76. statement->last_query = NULL;
  77. statement->last_query_len = 0;
  78. }
  79. statement->connection = connection;
  80. statement->has_data = 0;
  81. statement->has_descr = 0;
  82. statement->parent_stmtid = 0;
  83. zend_list_addref(statement->connection->rsrc_id);
  84. if (OCI_G(default_prefetch) >= 0) {
  85. php_oci_statement_set_prefetch(statement, OCI_G(default_prefetch) TSRMLS_CC);
  86. }
  87. PHP_OCI_REGISTER_RESOURCE(statement, le_statement);
  88. OCI_G(num_statements)++;
  89. return statement;
  90. }
  91. /* }}} */
  92. /* {{{ php_oci_statement_set_prefetch()
  93. Set prefetch buffer size for the statement (we're assuming that one row is ~1K sized) */
  94. int php_oci_statement_set_prefetch(php_oci_statement *statement, long size TSRMLS_DC)
  95. {
  96. ub4 prefetch = size;
  97. if (size < 0) {
  98. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number of rows to be prefetched has to be greater than or equal to 0");
  99. return 1;
  100. }
  101. PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrSet, (statement->stmt, OCI_HTYPE_STMT, &prefetch, 0, OCI_ATTR_PREFETCH_ROWS, statement->err));
  102. if (statement->errcode != OCI_SUCCESS) {
  103. statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
  104. PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
  105. return 1;
  106. }
  107. return 0;
  108. }
  109. /* }}} */
  110. /* {{{ php_oci_cleanup_pre_fetch()
  111. Helper function to cleanup ref-cursors and descriptors from the previous row */
  112. int php_oci_cleanup_pre_fetch(void *data TSRMLS_DC)
  113. {
  114. php_oci_out_column *outcol = data;
  115. if (!outcol->is_descr && !outcol->is_cursor)
  116. return ZEND_HASH_APPLY_KEEP;
  117. switch(outcol->data_type) {
  118. case SQLT_CLOB:
  119. case SQLT_BLOB:
  120. case SQLT_RDD:
  121. case SQLT_BFILE:
  122. if (outcol->descid) {
  123. zend_list_delete(outcol->descid);
  124. outcol->descid = 0;
  125. }
  126. break;
  127. case SQLT_RSET:
  128. if (outcol->stmtid) {
  129. zend_list_delete(outcol->stmtid);
  130. outcol->stmtid = 0;
  131. outcol->nested_statement = NULL;
  132. }
  133. break;
  134. default:
  135. break;
  136. }
  137. return ZEND_HASH_APPLY_KEEP;
  138. } /* }}} */
  139. /* {{{ php_oci_statement_fetch()
  140. Fetch a row from the statement */
  141. int php_oci_statement_fetch(php_oci_statement *statement, ub4 nrows TSRMLS_DC)
  142. {
  143. int i;
  144. void *handlepp;
  145. ub4 typep, iterp, idxp;
  146. ub1 in_outp, piecep;
  147. zend_bool piecewisecols = 0;
  148. php_oci_out_column *column;
  149. if (statement->has_descr && statement->columns) {
  150. zend_hash_apply(statement->columns, (apply_func_t) php_oci_cleanup_pre_fetch TSRMLS_CC);
  151. }
  152. PHP_OCI_CALL_RETURN(statement->errcode, OCIStmtFetch, (statement->stmt, statement->err, nrows, OCI_FETCH_NEXT, OCI_DEFAULT));
  153. if ( statement->errcode == OCI_NO_DATA || nrows == 0 ) {
  154. if (statement->last_query == NULL) {
  155. /* reset define-list for refcursors */
  156. if (statement->columns) {
  157. zend_hash_destroy(statement->columns);
  158. efree(statement->columns);
  159. statement->columns = NULL;
  160. statement->ncolumns = 0;
  161. }
  162. statement->executed = 0;
  163. }
  164. statement->errcode = 0; /* OCI_NO_DATA is NO error for us!!! */
  165. statement->has_data = 0;
  166. if (nrows == 0) {
  167. /* this is exactly what we requested */
  168. return 0;
  169. }
  170. return 1;
  171. }
  172. /* reset length for all piecewise columns */
  173. for (i = 0; i < statement->ncolumns; i++) {
  174. column = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
  175. if (column->piecewise) {
  176. column->retlen4 = 0;
  177. piecewisecols = 1;
  178. }
  179. }
  180. while (statement->errcode == OCI_NEED_DATA) {
  181. if (piecewisecols) {
  182. PHP_OCI_CALL_RETURN(statement->errcode,
  183. OCIStmtGetPieceInfo,
  184. (
  185. statement->stmt,
  186. statement->err,
  187. &handlepp,
  188. &typep,
  189. &in_outp,
  190. &iterp,
  191. &idxp,
  192. &piecep
  193. )
  194. );
  195. /* scan through our columns for a piecewise column with a matching handle */
  196. for (i = 0; i < statement->ncolumns; i++) {
  197. column = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
  198. if (column->piecewise && handlepp == column->oci_define) {
  199. if (!column->data) {
  200. column->data = (text *) ecalloc(1, PHP_OCI_PIECE_SIZE + 1);
  201. } else {
  202. column->data = erealloc(column->data, column->retlen4 + PHP_OCI_PIECE_SIZE + 1);
  203. }
  204. column->cb_retlen = PHP_OCI_PIECE_SIZE;
  205. /* and instruct fetch to fetch waiting piece into our buffer */
  206. PHP_OCI_CALL(OCIStmtSetPieceInfo,
  207. (
  208. (void *) column->oci_define,
  209. OCI_HTYPE_DEFINE,
  210. statement->err,
  211. ((char*)column->data) + column->retlen4,
  212. &(column->cb_retlen),
  213. piecep,
  214. &column->indicator,
  215. &column->retcode
  216. )
  217. );
  218. }
  219. }
  220. }
  221. PHP_OCI_CALL_RETURN(statement->errcode, OCIStmtFetch, (statement->stmt, statement->err, nrows, OCI_FETCH_NEXT, OCI_DEFAULT));
  222. if (piecewisecols) {
  223. for (i = 0; i < statement->ncolumns; i++) {
  224. column = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
  225. if (column && column->piecewise && handlepp == column->oci_define) {
  226. column->retlen4 += column->cb_retlen;
  227. }
  228. }
  229. }
  230. }
  231. if (statement->errcode == OCI_SUCCESS_WITH_INFO || statement->errcode == OCI_SUCCESS) {
  232. statement->has_data = 1;
  233. /* do the stuff needed for OCIDefineByName */
  234. for (i = 0; i < statement->ncolumns; i++) {
  235. column = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
  236. if (column == NULL) {
  237. continue;
  238. }
  239. if (!column->define) {
  240. continue;
  241. }
  242. zval_dtor(column->define->zval);
  243. php_oci_column_to_zval(column, column->define->zval, 0 TSRMLS_CC);
  244. }
  245. return 0;
  246. }
  247. statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
  248. PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
  249. statement->has_data = 0;
  250. return 1;
  251. }
  252. /* }}} */
  253. /* {{{ php_oci_statement_get_column()
  254. Get column from the result set */
  255. php_oci_out_column *php_oci_statement_get_column(php_oci_statement *statement, long column_index, char *column_name, int column_name_len TSRMLS_DC)
  256. {
  257. php_oci_out_column *column = NULL;
  258. int i;
  259. if (statement->columns == NULL) { /* we release the columns at the end of a fetch */
  260. return NULL;
  261. }
  262. if (column_name) {
  263. for (i = 0; i < statement->ncolumns; i++) {
  264. column = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
  265. if (column == NULL) {
  266. continue;
  267. } else if (((int) column->name_len == column_name_len) && (!strncmp(column->name, column_name, column_name_len))) {
  268. return column;
  269. }
  270. }
  271. } else if (column_index != -1) {
  272. if (zend_hash_index_find(statement->columns, column_index, (void **)&column) == FAILURE) {
  273. return NULL;
  274. }
  275. return column;
  276. }
  277. return NULL;
  278. }
  279. /* }}} */
  280. /* php_oci_define_callback() {{{ */
  281. sb4 php_oci_define_callback(dvoid *ctx, OCIDefine *define, ub4 iter, dvoid **bufpp, ub4 **alenpp, ub1 *piecep, dvoid **indpp, ub2 **rcpp)
  282. {
  283. php_oci_out_column *outcol = (php_oci_out_column *)ctx;
  284. TSRMLS_FETCH();
  285. if (!outcol) {
  286. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid context pointer value");
  287. return OCI_ERROR;
  288. }
  289. switch(outcol->data_type) {
  290. case SQLT_RSET: {
  291. php_oci_statement *nested_stmt;
  292. nested_stmt = php_oci_statement_create(outcol->statement->connection, NULL, 0 TSRMLS_CC);
  293. if (!nested_stmt) {
  294. return OCI_ERROR;
  295. }
  296. nested_stmt->parent_stmtid = outcol->statement->id;
  297. zend_list_addref(outcol->statement->id);
  298. outcol->nested_statement = nested_stmt;
  299. outcol->stmtid = nested_stmt->id;
  300. *bufpp = nested_stmt->stmt;
  301. *alenpp = &(outcol->retlen4);
  302. *piecep = OCI_ONE_PIECE;
  303. *indpp = &(outcol->indicator);
  304. *rcpp = &(outcol->retcode);
  305. return OCI_CONTINUE;
  306. }
  307. break;
  308. case SQLT_RDD:
  309. case SQLT_BLOB:
  310. case SQLT_CLOB:
  311. case SQLT_BFILE: {
  312. php_oci_descriptor *descr;
  313. int dtype;
  314. if (outcol->data_type == SQLT_BFILE) {
  315. dtype = OCI_DTYPE_FILE;
  316. } else if (outcol->data_type == SQLT_RDD ) {
  317. dtype = OCI_DTYPE_ROWID;
  318. } else {
  319. dtype = OCI_DTYPE_LOB;
  320. }
  321. descr = php_oci_lob_create(outcol->statement->connection, dtype TSRMLS_CC);
  322. if (!descr) {
  323. return OCI_ERROR;
  324. }
  325. outcol->descid = descr->id;
  326. descr->charset_form = outcol->charset_form;
  327. *bufpp = descr->descriptor;
  328. *alenpp = &(outcol->retlen4);
  329. *piecep = OCI_ONE_PIECE;
  330. *indpp = &(outcol->indicator);
  331. *rcpp = &(outcol->retcode);
  332. return OCI_CONTINUE;
  333. }
  334. break;
  335. }
  336. return OCI_ERROR;
  337. }
  338. /* }}} */
  339. /* {{{ php_oci_statement_execute()
  340. Execute statement */
  341. int php_oci_statement_execute(php_oci_statement *statement, ub4 mode TSRMLS_DC)
  342. {
  343. php_oci_out_column *outcol;
  344. php_oci_out_column column;
  345. OCIParam *param = NULL;
  346. text *colname;
  347. ub4 counter;
  348. ub2 define_type;
  349. ub4 iters;
  350. ub4 colcount;
  351. ub2 dynamic;
  352. dvoid *buf;
  353. switch (mode) {
  354. case OCI_COMMIT_ON_SUCCESS:
  355. case OCI_DESCRIBE_ONLY:
  356. case OCI_DEFAULT:
  357. /* only these are allowed */
  358. break;
  359. default:
  360. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid execute mode given: %d", mode);
  361. return 1;
  362. break;
  363. }
  364. if (!statement->stmttype) {
  365. /* get statement type */
  366. PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (ub2 *)&statement->stmttype, (ub4 *)0, OCI_ATTR_STMT_TYPE, statement->err));
  367. if (statement->errcode != OCI_SUCCESS) {
  368. statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
  369. PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
  370. return 1;
  371. }
  372. }
  373. if (statement->stmttype == OCI_STMT_SELECT) {
  374. iters = 0;
  375. } else {
  376. iters = 1;
  377. }
  378. if (statement->last_query) {
  379. /* if we execute refcursors we don't have a query and
  380. we don't want to execute!!! */
  381. if (statement->binds) {
  382. int result = 0;
  383. zend_hash_apply_with_argument(statement->binds, (apply_func_arg_t) php_oci_bind_pre_exec, (void *)&result TSRMLS_CC);
  384. if (result) {
  385. return 1;
  386. }
  387. }
  388. /* execute statement */
  389. PHP_OCI_CALL_RETURN(statement->errcode, OCIStmtExecute, (statement->connection->svc, statement->stmt, statement->err, iters, 0, NULL, NULL, mode));
  390. if (statement->errcode != OCI_SUCCESS) {
  391. statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
  392. PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
  393. return 1;
  394. }
  395. if (statement->binds) {
  396. zend_hash_apply(statement->binds, (apply_func_t) php_oci_bind_post_exec TSRMLS_CC);
  397. }
  398. if (mode & OCI_COMMIT_ON_SUCCESS) {
  399. statement->connection->needs_commit = 0;
  400. } else {
  401. statement->connection->needs_commit = 1;
  402. }
  403. }
  404. if (statement->stmttype == OCI_STMT_SELECT && statement->executed == 0) {
  405. /* we only need to do the define step is this very statement is executed the first time! */
  406. statement->executed = 1;
  407. ALLOC_HASHTABLE(statement->columns);
  408. zend_hash_init(statement->columns, 13, NULL, php_oci_column_hash_dtor, 0);
  409. counter = 1;
  410. /* get number of columns */
  411. PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (dvoid *)&colcount, (ub4 *)0, OCI_ATTR_PARAM_COUNT, statement->err));
  412. if (statement->errcode != OCI_SUCCESS) {
  413. statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
  414. PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
  415. return 1;
  416. }
  417. statement->ncolumns = colcount;
  418. for (counter = 1; counter <= colcount; counter++) {
  419. memset(&column,0,sizeof(php_oci_out_column));
  420. if (zend_hash_index_update(statement->columns, counter, &column, sizeof(php_oci_out_column), (void**) &outcol) == FAILURE) {
  421. efree(statement->columns);
  422. /* out of memory */
  423. return 1;
  424. }
  425. /* get column */
  426. PHP_OCI_CALL_RETURN(statement->errcode, OCIParamGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, statement->err, (dvoid**)&param, counter));
  427. if (statement->errcode != OCI_SUCCESS) {
  428. statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
  429. PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
  430. return 1;
  431. }
  432. /* get column datatype */
  433. PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->data_type, (ub4 *)0, OCI_ATTR_DATA_TYPE, statement->err));
  434. if (statement->errcode != OCI_SUCCESS) {
  435. PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
  436. statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
  437. PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
  438. return 1;
  439. }
  440. /* get character set form */
  441. PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->charset_form, (ub4 *)0, OCI_ATTR_CHARSET_FORM, statement->err));
  442. if (statement->errcode != OCI_SUCCESS) {
  443. PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
  444. statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
  445. PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
  446. return 1;
  447. }
  448. /* get character set id */
  449. PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->charset_id, (ub4 *)0, OCI_ATTR_CHARSET_ID, statement->err));
  450. if (statement->errcode != OCI_SUCCESS) {
  451. PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
  452. statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
  453. PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
  454. return 1;
  455. }
  456. /* get size of the column */
  457. PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->data_size, (dvoid *)0, OCI_ATTR_DATA_SIZE, statement->err));
  458. if (statement->errcode != OCI_SUCCESS) {
  459. PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
  460. statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
  461. PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
  462. return 1;
  463. }
  464. outcol->storage_size4 = outcol->data_size;
  465. outcol->retlen = outcol->data_size;
  466. /* get scale of the column */
  467. PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->scale, (dvoid *)0, OCI_ATTR_SCALE, statement->err));
  468. if (statement->errcode != OCI_SUCCESS) {
  469. PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
  470. statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
  471. PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
  472. return 1;
  473. }
  474. /* get precision of the column */
  475. PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->precision, (dvoid *)0, OCI_ATTR_PRECISION, statement->err));
  476. if (statement->errcode != OCI_SUCCESS) {
  477. PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
  478. statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
  479. PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
  480. return 1;
  481. }
  482. /* get name of the column */
  483. PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid **)&colname, (ub4 *)&outcol->name_len, (ub4)OCI_ATTR_NAME, statement->err));
  484. if (statement->errcode != OCI_SUCCESS) {
  485. PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
  486. statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
  487. PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
  488. return 1;
  489. }
  490. PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
  491. outcol->name = estrndup((char*) colname, outcol->name_len);
  492. /* find a user-setted define */
  493. if (statement->defines) {
  494. if (zend_hash_find(statement->defines,outcol->name,outcol->name_len,(void **) &outcol->define) == SUCCESS) {
  495. if (outcol->define->type) {
  496. outcol->data_type = outcol->define->type;
  497. }
  498. }
  499. }
  500. buf = 0;
  501. switch (outcol->data_type) {
  502. case SQLT_RSET:
  503. outcol->statement = statement; /* parent handle */
  504. define_type = SQLT_RSET;
  505. outcol->is_cursor = 1;
  506. outcol->statement->has_descr = 1;
  507. outcol->storage_size4 = -1;
  508. outcol->retlen = -1;
  509. dynamic = OCI_DYNAMIC_FETCH;
  510. break;
  511. case SQLT_RDD: /* ROWID */
  512. case SQLT_BLOB: /* binary LOB */
  513. case SQLT_CLOB: /* character LOB */
  514. case SQLT_BFILE: /* binary file LOB */
  515. outcol->statement = statement; /* parent handle */
  516. define_type = outcol->data_type;
  517. outcol->is_descr = 1;
  518. outcol->statement->has_descr = 1;
  519. outcol->storage_size4 = -1;
  520. dynamic = OCI_DYNAMIC_FETCH;
  521. break;
  522. case SQLT_LNG:
  523. case SQLT_LBI:
  524. if (outcol->data_type == SQLT_LBI) {
  525. define_type = SQLT_BIN;
  526. } else {
  527. define_type = SQLT_CHR;
  528. }
  529. outcol->storage_size4 = PHP_OCI_MAX_DATA_SIZE;
  530. outcol->piecewise = 1;
  531. dynamic = OCI_DYNAMIC_FETCH;
  532. break;
  533. case SQLT_BIN:
  534. default:
  535. define_type = SQLT_CHR;
  536. if (outcol->data_type == SQLT_BIN) {
  537. define_type = SQLT_BIN;
  538. }
  539. if ((outcol->data_type == SQLT_DAT) || (outcol->data_type == SQLT_NUM)
  540. #ifdef SQLT_TIMESTAMP
  541. || (outcol->data_type == SQLT_TIMESTAMP)
  542. #endif
  543. #ifdef SQLT_TIMESTAMP_TZ
  544. || (outcol->data_type == SQLT_TIMESTAMP_TZ)
  545. #endif
  546. #ifdef SQLT_TIMESTAMP_LTZ
  547. || (outcol->data_type == SQLT_TIMESTAMP_LTZ)
  548. #endif
  549. #ifdef SQLT_INTERVAL_YM
  550. || (outcol->data_type == SQLT_INTERVAL_YM)
  551. #endif
  552. #ifdef SQLT_INTERVAL_DS
  553. || (outcol->data_type == SQLT_INTERVAL_DS)
  554. #endif
  555. ) {
  556. outcol->storage_size4 = 512; /* XXX this should fit "most" NLS date-formats and Numbers */
  557. #if defined(SQLT_IBFLOAT) && defined(SQLT_IBDOUBLE)
  558. } else if (outcol->data_type == SQLT_IBFLOAT || outcol->data_type == SQLT_IBDOUBLE) {
  559. outcol->storage_size4 = 1024;
  560. #endif
  561. } else {
  562. outcol->storage_size4++; /* add one for string terminator */
  563. }
  564. outcol->storage_size4 *= 3;
  565. dynamic = OCI_DEFAULT;
  566. buf = outcol->data = (text *) safe_emalloc(1, outcol->storage_size4, 0);
  567. memset(buf, 0, outcol->storage_size4);
  568. break;
  569. }
  570. if (dynamic == OCI_DYNAMIC_FETCH) {
  571. PHP_OCI_CALL_RETURN(statement->errcode,
  572. OCIDefineByPos,
  573. (
  574. statement->stmt, /* IN/OUT handle to the requested SQL query */
  575. (OCIDefine **)&outcol->oci_define, /* IN/OUT pointer to a pointer to a define handle */
  576. statement->err, /* IN/OUT An error handle */
  577. counter, /* IN position in the select list */
  578. (dvoid *)NULL, /* IN/OUT pointer to a buffer */
  579. outcol->storage_size4, /* IN The size of each valuep buffer in bytes */
  580. define_type, /* IN The data type */
  581. (dvoid *)&outcol->indicator, /* IN pointer to an indicator variable or arr */
  582. (ub2 *)NULL, /* IN/OUT Pointer to array of length of data fetched */
  583. (ub2 *)NULL, /* OUT Pointer to array of column-level return codes */
  584. OCI_DYNAMIC_FETCH /* IN mode (OCI_DEFAULT, OCI_DYNAMIC_FETCH) */
  585. )
  586. );
  587. } else {
  588. PHP_OCI_CALL_RETURN(statement->errcode,
  589. OCIDefineByPos,
  590. (
  591. statement->stmt, /* IN/OUT handle to the requested SQL query */
  592. (OCIDefine **)&outcol->oci_define, /* IN/OUT pointer to a pointer to a define handle */
  593. statement->err, /* IN/OUT An error handle */
  594. counter, /* IN position in the select list */
  595. (dvoid *)buf, /* IN/OUT pointer to a buffer */
  596. outcol->storage_size4, /* IN The size of each valuep buffer in bytes */
  597. define_type, /* IN The data type */
  598. (dvoid *)&outcol->indicator, /* IN pointer to an indicator variable or arr */
  599. (ub2 *)&outcol->retlen, /* IN/OUT Pointer to array of length of data fetched */
  600. (ub2 *)&outcol->retcode, /* OUT Pointer to array of column-level return codes */
  601. OCI_DEFAULT /* IN mode (OCI_DEFAULT, OCI_DYNAMIC_FETCH) */
  602. )
  603. );
  604. }
  605. if (statement->errcode != OCI_SUCCESS) {
  606. statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
  607. PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
  608. return 0;
  609. }
  610. /* additional OCIDefineDynamic() call */
  611. switch (outcol->data_type) {
  612. case SQLT_RSET:
  613. case SQLT_RDD:
  614. case SQLT_BLOB:
  615. case SQLT_CLOB:
  616. case SQLT_BFILE:
  617. PHP_OCI_CALL_RETURN(statement->errcode,
  618. OCIDefineDynamic,
  619. (
  620. outcol->oci_define,
  621. statement->err,
  622. (dvoid *)outcol,
  623. php_oci_define_callback
  624. )
  625. );
  626. break;
  627. }
  628. }
  629. }
  630. return 0;
  631. }
  632. /* }}} */
  633. /* {{{ php_oci_statement_cancel()
  634. Cancel statement */
  635. int php_oci_statement_cancel(php_oci_statement *statement TSRMLS_DC)
  636. {
  637. return php_oci_statement_fetch(statement, 0 TSRMLS_CC);
  638. } /* }}} */
  639. /* {{{ php_oci_statement_free()
  640. Destroy statement handle and free associated resources */
  641. void php_oci_statement_free(php_oci_statement *statement TSRMLS_DC)
  642. {
  643. if (statement->stmt) {
  644. if (statement->last_query_len) { /* FIXME: magical */
  645. PHP_OCI_CALL(OCIStmtRelease, (statement->stmt, statement->err, NULL, 0, statement->errcode ? OCI_STRLS_CACHE_DELETE : OCI_DEFAULT));
  646. } else {
  647. PHP_OCI_CALL(OCIHandleFree, (statement->stmt, OCI_HTYPE_STMT));
  648. }
  649. statement->stmt = 0;
  650. }
  651. if (statement->err) {
  652. PHP_OCI_CALL(OCIHandleFree, (statement->err, OCI_HTYPE_ERROR));
  653. statement->err = 0;
  654. }
  655. if (statement->last_query) {
  656. efree(statement->last_query);
  657. }
  658. if (statement->columns) {
  659. zend_hash_destroy(statement->columns);
  660. efree(statement->columns);
  661. }
  662. if (statement->binds) {
  663. zend_hash_destroy(statement->binds);
  664. efree(statement->binds);
  665. }
  666. if (statement->defines) {
  667. zend_hash_destroy(statement->defines);
  668. efree(statement->defines);
  669. }
  670. if (statement->parent_stmtid) {
  671. zend_list_delete(statement->parent_stmtid);
  672. }
  673. zend_list_delete(statement->connection->rsrc_id);
  674. efree(statement);
  675. OCI_G(num_statements)--;
  676. } /* }}} */
  677. /* {{{ php_oci_bind_pre_exec()
  678. Helper function */
  679. int php_oci_bind_pre_exec(void *data, void *result TSRMLS_DC)
  680. {
  681. php_oci_bind *bind = (php_oci_bind *) data;
  682. *(int *)result = 0;
  683. if (Z_TYPE_P(bind->zval) == IS_ARRAY) {
  684. /* These checks are currently valid for oci_bind_by_name, not
  685. * oci_bind_array_by_name. Also bind->type and
  686. * bind->indicator are not used for oci_bind_array_by_name.
  687. */
  688. return 0;
  689. }
  690. switch (bind->type) {
  691. case SQLT_NTY:
  692. case SQLT_BFILEE:
  693. case SQLT_CFILEE:
  694. case SQLT_CLOB:
  695. case SQLT_BLOB:
  696. case SQLT_RDD:
  697. if (Z_TYPE_P(bind->zval) != IS_OBJECT) {
  698. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid variable used for bind");
  699. *(int *)result = 1;
  700. }
  701. break;
  702. case SQLT_INT:
  703. case SQLT_NUM:
  704. if (Z_TYPE_P(bind->zval) == IS_RESOURCE || Z_TYPE_P(bind->zval) == IS_OBJECT) {
  705. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid variable used for bind");
  706. *(int *)result = 1;
  707. }
  708. break;
  709. case SQLT_LBI:
  710. case SQLT_BIN:
  711. case SQLT_LNG:
  712. case SQLT_AFC:
  713. case SQLT_CHR:
  714. if (Z_TYPE_P(bind->zval) == IS_RESOURCE || Z_TYPE_P(bind->zval) == IS_OBJECT) {
  715. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid variable used for bind");
  716. *(int *)result = 1;
  717. }
  718. break;
  719. case SQLT_RSET:
  720. if (Z_TYPE_P(bind->zval) != IS_RESOURCE) {
  721. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid variable used for bind");
  722. *(int *)result = 1;
  723. }
  724. break;
  725. }
  726. /* reset all bind stuff to a normal state..-. */
  727. bind->indicator = 0;
  728. return 0;
  729. }
  730. /* }}} */
  731. /* {{{ php_oci_bind_post_exec()
  732. Helper function */
  733. int php_oci_bind_post_exec(void *data TSRMLS_DC)
  734. {
  735. php_oci_bind *bind = (php_oci_bind *) data;
  736. php_oci_connection *connection = bind->parent_statement->connection;
  737. if (bind->indicator == -1) { /* NULL */
  738. zval *val = bind->zval;
  739. if (Z_TYPE_P(val) == IS_STRING) {
  740. *Z_STRVAL_P(val) = '\0'; /* XXX avoid warning in debug mode */
  741. }
  742. zval_dtor(val);
  743. ZVAL_NULL(val);
  744. } else if (Z_TYPE_P(bind->zval) == IS_STRING
  745. && Z_STRLEN_P(bind->zval) > 0
  746. && Z_STRVAL_P(bind->zval)[ Z_STRLEN_P(bind->zval) ] != '\0') {
  747. /* The post- PHP 5.3 feature for "interned" strings disallows
  748. * their reallocation but (i) any IN binds either interned or
  749. * not should already be null terminated and (ii) for OUT
  750. * binds, php_oci_bind_out_callback() should have allocated a
  751. * new string that can be realloced.
  752. */
  753. Z_STRVAL_P(bind->zval) = erealloc(Z_STRVAL_P(bind->zval), Z_STRLEN_P(bind->zval)+1);
  754. Z_STRVAL_P(bind->zval)[ Z_STRLEN_P(bind->zval) ] = '\0';
  755. } else if (Z_TYPE_P(bind->zval) == IS_ARRAY) {
  756. int i;
  757. zval **entry;
  758. HashTable *hash = HASH_OF(bind->zval);
  759. zend_hash_internal_pointer_reset(hash);
  760. switch (bind->array.type) {
  761. case SQLT_NUM:
  762. case SQLT_INT:
  763. case SQLT_LNG:
  764. for (i = 0; i < bind->array.current_length; i++) {
  765. if ((i < bind->array.old_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
  766. zval_dtor(*entry);
  767. ZVAL_LONG(*entry, ((ub4 *)(bind->array.elements))[i]);
  768. zend_hash_move_forward(hash);
  769. } else {
  770. add_next_index_long(bind->zval, ((ub4 *)(bind->array.elements))[i]);
  771. }
  772. }
  773. break;
  774. case SQLT_FLT:
  775. for (i = 0; i < bind->array.current_length; i++) {
  776. if ((i < bind->array.old_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
  777. zval_dtor(*entry);
  778. ZVAL_DOUBLE(*entry, ((double *)(bind->array.elements))[i]);
  779. zend_hash_move_forward(hash);
  780. } else {
  781. add_next_index_double(bind->zval, ((double *)(bind->array.elements))[i]);
  782. }
  783. }
  784. break;
  785. case SQLT_ODT:
  786. for (i = 0; i < bind->array.current_length; i++) {
  787. oratext buff[1024];
  788. ub4 buff_len = 1024;
  789. memset((void*)buff,0,sizeof(buff));
  790. if ((i < bind->array.old_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
  791. PHP_OCI_CALL_RETURN(connection->errcode, OCIDateToText, (connection->err, &(((OCIDate *)(bind->array.elements))[i]), 0, 0, 0, 0, &buff_len, buff));
  792. zval_dtor(*entry);
  793. if (connection->errcode != OCI_SUCCESS) {
  794. connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
  795. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  796. ZVAL_NULL(*entry);
  797. } else {
  798. ZVAL_STRINGL(*entry, (char *)buff, buff_len, 1);
  799. }
  800. zend_hash_move_forward(hash);
  801. } else {
  802. PHP_OCI_CALL_RETURN(connection->errcode, OCIDateToText, (connection->err, &(((OCIDate *)(bind->array.elements))[i]), 0, 0, 0, 0, &buff_len, buff));
  803. if (connection->errcode != OCI_SUCCESS) {
  804. connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
  805. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  806. add_next_index_null(bind->zval);
  807. } else {
  808. add_next_index_stringl(bind->zval, (char *)buff, buff_len, 1);
  809. }
  810. }
  811. }
  812. break;
  813. case SQLT_AFC:
  814. case SQLT_CHR:
  815. case SQLT_VCS:
  816. case SQLT_AVC:
  817. case SQLT_STR:
  818. case SQLT_LVC:
  819. for (i = 0; i < bind->array.current_length; i++) {
  820. /* int curr_element_length = strlen(((text *)bind->array.elements)+i*bind->array.max_length); */
  821. int curr_element_length = bind->array.element_lengths[i];
  822. if ((i < bind->array.old_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
  823. zval_dtor(*entry);
  824. ZVAL_STRINGL(*entry, (char *)(((text *)bind->array.elements)+i*bind->array.max_length), curr_element_length, 1);
  825. zend_hash_move_forward(hash);
  826. } else {
  827. add_next_index_stringl(bind->zval, (char *)(((text *)bind->array.elements)+i*bind->array.max_length), curr_element_length, 1);
  828. }
  829. }
  830. break;
  831. }
  832. }
  833. return 0;
  834. }
  835. /* }}} */
  836. /* {{{ php_oci_bind_by_name()
  837. Bind zval to the given placeholder */
  838. int php_oci_bind_by_name(php_oci_statement *statement, char *name, int name_len, zval* var, long maxlength, ub2 type TSRMLS_DC)
  839. {
  840. php_oci_collection *bind_collection = NULL;
  841. php_oci_descriptor *bind_descriptor = NULL;
  842. php_oci_statement *bind_statement = NULL;
  843. dvoid *oci_desc = NULL;
  844. /* dvoid *php_oci_collection = NULL; */
  845. OCIStmt *oci_stmt = NULL;
  846. dvoid *bind_data = NULL;
  847. php_oci_bind bind, *old_bind, *bindp;
  848. int mode = OCI_DATA_AT_EXEC;
  849. sb4 value_sz = -1;
  850. switch (type) {
  851. case SQLT_NTY:
  852. {
  853. zval **tmp;
  854. if (Z_TYPE_P(var) != IS_OBJECT || zend_hash_find(Z_OBJPROP_P(var), "collection", sizeof("collection"), (void **)&tmp) == FAILURE) {
  855. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find collection property");
  856. return 1;
  857. }
  858. PHP_OCI_ZVAL_TO_COLLECTION_EX(*tmp, bind_collection);
  859. value_sz = sizeof(void*);
  860. mode = OCI_DEFAULT;
  861. if (!bind_collection->collection) {
  862. return 1;
  863. }
  864. }
  865. break;
  866. case SQLT_BFILEE:
  867. case SQLT_CFILEE:
  868. case SQLT_CLOB:
  869. case SQLT_BLOB:
  870. case SQLT_RDD:
  871. {
  872. zval **tmp;
  873. if (Z_TYPE_P(var) != IS_OBJECT || zend_hash_find(Z_OBJPROP_P(var), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
  874. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
  875. return 1;
  876. }
  877. PHP_OCI_ZVAL_TO_DESCRIPTOR_EX(*tmp, bind_descriptor);
  878. value_sz = sizeof(void*);
  879. oci_desc = bind_descriptor->descriptor;
  880. if (!oci_desc) {
  881. return 1;
  882. }
  883. }
  884. break;
  885. case SQLT_INT:
  886. case SQLT_NUM:
  887. if (Z_TYPE_P(var) == IS_RESOURCE || Z_TYPE_P(var) == IS_OBJECT) {
  888. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid variable used for bind");
  889. return 1;
  890. }
  891. convert_to_long(var);
  892. bind_data = (ub4 *)&Z_LVAL_P(var);
  893. value_sz = sizeof(ub4);
  894. mode = OCI_DEFAULT;
  895. break;
  896. case SQLT_LBI:
  897. case SQLT_BIN:
  898. case SQLT_LNG:
  899. case SQLT_AFC:
  900. case SQLT_CHR: /* SQLT_CHR is the default value when type was not specified */
  901. if (Z_TYPE_P(var) == IS_RESOURCE || Z_TYPE_P(var) == IS_OBJECT) {
  902. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid variable used for bind");
  903. return 1;
  904. }
  905. if (Z_TYPE_P(var) != IS_NULL) {
  906. convert_to_string(var);
  907. }
  908. if (maxlength == -1) {
  909. value_sz = (Z_TYPE_P(var) == IS_STRING) ? Z_STRLEN_P(var) : 0;
  910. } else {
  911. value_sz = maxlength;
  912. }
  913. break;
  914. case SQLT_RSET:
  915. if (Z_TYPE_P(var) != IS_RESOURCE) {
  916. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid variable used for bind");
  917. return 1;
  918. }
  919. PHP_OCI_ZVAL_TO_STATEMENT_EX(var, bind_statement);
  920. value_sz = sizeof(void*);
  921. oci_stmt = bind_statement->stmt;
  922. if (!oci_stmt) {
  923. return 1;
  924. }
  925. break;
  926. default:
  927. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or unsupported datatype given: %d", (int)type);
  928. return 1;
  929. break;
  930. }
  931. if (value_sz == 0) {
  932. value_sz = 1;
  933. }
  934. if (!statement->binds) {
  935. ALLOC_HASHTABLE(statement->binds);
  936. zend_hash_init(statement->binds, 13, NULL, php_oci_bind_hash_dtor, 0);
  937. }
  938. memset((void*)&bind,0,sizeof(php_oci_bind));
  939. if (zend_hash_find(statement->binds, name, name_len + 1, (void **)&old_bind) == SUCCESS) {
  940. bindp = old_bind;
  941. if (bindp->zval) {
  942. zval_ptr_dtor(&bindp->zval);
  943. }
  944. } else {
  945. zend_hash_update(statement->binds, name, name_len + 1, &bind, sizeof(php_oci_bind), (void **)&bindp);
  946. }
  947. bindp->descriptor = oci_desc;
  948. bindp->statement = oci_stmt;
  949. bindp->parent_statement = statement;
  950. bindp->zval = var;
  951. bindp->type = type;
  952. zval_add_ref(&var);
  953. PHP_OCI_CALL_RETURN(statement->errcode,
  954. OCIBindByName,
  955. (
  956. statement->stmt, /* statement handle */
  957. (OCIBind **)&bindp->bind, /* bind hdl (will alloc) */
  958. statement->err, /* error handle */
  959. (text*) name, /* placeholder name */
  960. name_len, /* placeholder length */
  961. (dvoid *)bind_data, /* in/out data */
  962. value_sz, /* PHP_OCI_MAX_DATA_SIZE, */ /* max size of input/output data */
  963. type, /* in/out data type */
  964. (dvoid *)&bindp->indicator, /* indicator (ignored) */
  965. (ub2 *)0, /* size array (ignored) */
  966. (ub2 *)&bindp->retcode, /* return code (ignored) */
  967. (ub4)0, /* maxarr_len (PL/SQL only?) */
  968. (ub4 *)0, /* actual array size (PL/SQL only?) */
  969. mode /* mode */
  970. )
  971. );
  972. if (statement->errcode != OCI_SUCCESS) {
  973. statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
  974. PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
  975. return 1;
  976. }
  977. if (mode == OCI_DATA_AT_EXEC) {
  978. PHP_OCI_CALL_RETURN(statement->errcode, OCIBindDynamic,
  979. (
  980. bindp->bind,
  981. statement->err,
  982. (dvoid *)bindp,
  983. php_oci_bind_in_callback,
  984. (dvoid *)bindp,
  985. php_oci_bind_out_callback
  986. )
  987. );
  988. if (statement->errcode != OCI_SUCCESS) {
  989. statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
  990. PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
  991. return 1;
  992. }
  993. }
  994. if (type == SQLT_NTY) {
  995. /* Bind object */
  996. PHP_OCI_CALL_RETURN(statement->errcode, OCIBindObject,
  997. (
  998. bindp->bind,
  999. statement->err,
  1000. bind_collection->tdo,
  1001. (dvoid **) &(bind_collection->collection),
  1002. (ub4 *) 0,
  1003. (dvoid **) 0,
  1004. (ub4 *) 0
  1005. )
  1006. );
  1007. if (statement->errcode) {
  1008. statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
  1009. PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
  1010. return 1;
  1011. }
  1012. }
  1013. return 0;
  1014. } /* }}} */
  1015. /* {{{ php_oci_bind_in_callback()
  1016. Callback used when binding LOBs and VARCHARs */
  1017. sb4 php_oci_bind_in_callback(
  1018. dvoid *ictxp, /* context pointer */
  1019. OCIBind *bindp, /* bind handle */
  1020. ub4 iter, /* 0-based execute iteration value */
  1021. ub4 index, /* index of current array for PL/SQL or row index for SQL */
  1022. dvoid **bufpp, /* pointer to data */
  1023. ub4 *alenp, /* size after value/piece has been read */
  1024. ub1 *piecep, /* which piece */
  1025. dvoid **indpp) /* indicator value */
  1026. {
  1027. php_oci_bind *phpbind;
  1028. zval *val;
  1029. TSRMLS_FETCH();
  1030. if (!(phpbind=(php_oci_bind *)ictxp) || !(val = phpbind->zval)) {
  1031. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid phpbind pointer value");
  1032. return OCI_ERROR;
  1033. }
  1034. if (ZVAL_IS_NULL(val)) {
  1035. /* we're going to insert a NULL column */
  1036. phpbind->indicator = -1;
  1037. *bufpp = 0;
  1038. *alenp = -1;
  1039. *indpp = (dvoid *)&phpbind->indicator;
  1040. } else if ((phpbind->descriptor == 0) && (phpbind->statement == 0)) {
  1041. /* "normal string bind */
  1042. convert_to_string(val);
  1043. *bufpp = Z_STRVAL_P(val);
  1044. *alenp = Z_STRLEN_P(val);
  1045. *indpp = (dvoid *)&phpbind->indicator;
  1046. } else if (phpbind->statement != 0) {
  1047. /* RSET */
  1048. *bufpp = phpbind->statement;
  1049. *alenp = -1; /* seems to be allright */
  1050. *indpp = (dvoid *)&phpbind->indicator;
  1051. } else {
  1052. /* descriptor bind */
  1053. *bufpp = phpbind->descriptor;
  1054. *alenp = -1; /* seems to be allright */
  1055. *indpp = (dvoid *)&phpbind->indicator;
  1056. }
  1057. *piecep = OCI_ONE_PIECE; /* pass all data in one go */
  1058. return OCI_CONTINUE;
  1059. }/* }}} */
  1060. /* {{{ php_oci_bind_out_callback()
  1061. Callback used when binding LOBs and VARCHARs */
  1062. sb4 php_oci_bind_out_callback(
  1063. dvoid *octxp, /* context pointer */
  1064. OCIBind *bindp, /* bind handle */
  1065. ub4 iter, /* 0-based execute iteration value */
  1066. ub4 index, /* index of current array for PL/SQL or row index for SQL */
  1067. dvoid **bufpp, /* pointer to data */
  1068. ub4 **alenpp, /* size after value/piece has been read */
  1069. ub1 *piecep, /* which piece */
  1070. dvoid **indpp, /* indicator value */
  1071. ub2 **rcodepp) /* return code */
  1072. {
  1073. php_oci_bind *phpbind;
  1074. zval *val;
  1075. sb4 retval = OCI_ERROR;
  1076. TSRMLS_FETCH();
  1077. if (!(phpbind=(php_oci_bind *)octxp) || !(val = phpbind->zval)) {
  1078. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid phpbind pointer value");
  1079. return retval;
  1080. }
  1081. if (Z_TYPE_P(val) == IS_RESOURCE) {
  1082. /* Processing for ref-cursor out binds */
  1083. if (phpbind->statement != NULL) {
  1084. *bufpp = phpbind->statement;
  1085. *alenpp = &phpbind->dummy_len;
  1086. *piecep = OCI_ONE_PIECE;
  1087. *rcodepp = &phpbind->retcode;
  1088. *indpp = &phpbind->indicator;
  1089. }
  1090. retval = OCI_CONTINUE;
  1091. } else if (Z_TYPE_P(val) == IS_OBJECT) {
  1092. zval **tmp;
  1093. php_oci_descriptor *desc;
  1094. if (!phpbind->descriptor) {
  1095. return OCI_ERROR;
  1096. }
  1097. /* Do not use the cached lob size if the descriptor is an
  1098. * out-bind as the contents would have been changed for in/out
  1099. * binds (Bug #46994).
  1100. */
  1101. if (zend_hash_find(Z_OBJPROP_P(val), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
  1102. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find object outbind descriptor property");
  1103. return OCI_ERROR;
  1104. }
  1105. PHP_OCI_ZVAL_TO_DESCRIPTOR_EX(*tmp, desc);
  1106. desc->lob_size = -1; /* force OCI8 to update cached size */
  1107. *alenpp = &phpbind->dummy_len;
  1108. *bufpp = phpbind->descriptor;
  1109. *piecep = OCI_ONE_PIECE;
  1110. *rcodepp = &phpbind->retcode;
  1111. *indpp = &phpbind->indicator;
  1112. retval = OCI_CONTINUE;
  1113. } else {
  1114. convert_to_string(val);
  1115. zval_dtor(val);
  1116. Z_STRLEN_P(val) = PHP_OCI_PIECE_SIZE; /* 64K-1 is max XXX */
  1117. Z_STRVAL_P(val) = ecalloc(1, Z_STRLEN_P(phpbind->zval) + 1);
  1118. /* XXX we assume that zend-zval len has 4 bytes */
  1119. *alenpp = (ub4*) &Z_STRLEN_P(phpbind->zval);
  1120. *bufpp = Z_STRVAL_P(phpbind->zval);
  1121. *piecep = OCI_ONE_PIECE;
  1122. *rcodepp = &phpbind->retcode;
  1123. *indpp = &phpbind->indicator;
  1124. retval = OCI_CONTINUE;
  1125. }
  1126. return retval;
  1127. }
  1128. /* }}} */
  1129. /* {{{ php_oci_statement_get_column_helper()
  1130. Helper function to get column by name and index */
  1131. php_oci_out_column *php_oci_statement_get_column_helper(INTERNAL_FUNCTION_PARAMETERS, int need_data)
  1132. {
  1133. zval *z_statement, *column_index;
  1134. php_oci_statement *statement;
  1135. php_oci_out_column *column;
  1136. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz", &z_statement, &column_index) == FAILURE) {
  1137. return NULL;
  1138. }
  1139. statement = (php_oci_statement *) zend_fetch_resource(&z_statement TSRMLS_CC, -1, "oci8 statement", NULL, 1, le_statement);
  1140. if (!statement) {
  1141. return NULL;
  1142. }
  1143. if (need_data && !statement->has_data) {
  1144. return NULL;
  1145. }
  1146. if (Z_TYPE_P(column_index) == IS_STRING) {
  1147. column = php_oci_statement_get_column(statement, -1, Z_STRVAL_P(column_index), Z_STRLEN_P(column_index) TSRMLS_CC);
  1148. if (!column) {
  1149. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid column name \"%s\"", Z_STRVAL_P(column_index));
  1150. return NULL;
  1151. }
  1152. } else {
  1153. zval tmp;
  1154. /* NB: for PHP4 compat only, it should be using 'Z' instead */
  1155. tmp = *column_index;
  1156. zval_copy_ctor(&tmp);
  1157. convert_to_long(&tmp);
  1158. column = php_oci_statement_get_column(statement, Z_LVAL(tmp), NULL, 0 TSRMLS_CC);
  1159. if (!column) {
  1160. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid column index \"%ld\"", Z_LVAL(tmp));
  1161. zval_dtor(&tmp);
  1162. return NULL;
  1163. }
  1164. zval_dtor(&tmp);
  1165. }
  1166. return column;
  1167. } /* }}} */
  1168. /* {{{ php_oci_statement_get_type()
  1169. Return type of the statement */
  1170. int php_oci_statement_get_type(php_oci_statement *statement, ub2 *type TSRMLS_DC)
  1171. {
  1172. ub2 statement_type;
  1173. *type = 0;
  1174. PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (ub2 *)&statement_type, (ub4 *)0, OCI_ATTR_STMT_TYPE, statement->err));
  1175. if (statement->errcode != OCI_SUCCESS) {
  1176. statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
  1177. PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
  1178. return 1;
  1179. }
  1180. *type = statement_type;
  1181. return 0;
  1182. } /* }}} */
  1183. /* {{{ php_oci_statement_get_numrows()
  1184. Get the number of rows fetched to the clientside (NOT the number of rows in the result set) */
  1185. int php_oci_statement_get_numrows(php_oci_statement *statement, ub4 *numrows TSRMLS_DC)
  1186. {
  1187. ub4 statement_numrows;
  1188. *numrows = 0;
  1189. PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (ub4 *)&statement_numrows, (ub4 *)0, OCI_ATTR_ROW_COUNT, statement->err));
  1190. if (statement->errcode != OCI_SUCCESS) {
  1191. statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
  1192. PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
  1193. return 1;
  1194. }
  1195. *numrows = statement_numrows;
  1196. return 0;
  1197. } /* }}} */
  1198. /* {{{ php_oci_bind_array_by_name()
  1199. Bind arrays to PL/SQL types */
  1200. int php_oci_bind_array_by_name(php_oci_statement *statement, char *name, int name_len, zval* var, long max_table_length, long maxlength, long type TSRMLS_DC)
  1201. {
  1202. php_oci_bind *bind, *bindp;
  1203. convert_to_array(var);
  1204. if (maxlength < -1) {
  1205. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid max length value (%ld)", maxlength);
  1206. return 1;
  1207. }
  1208. switch(type) {
  1209. case SQLT_NUM:
  1210. case SQLT_INT:
  1211. case SQLT_LNG:
  1212. bind = php_oci_bind_array_helper_number(var, max_table_length TSRMLS_CC);
  1213. break;
  1214. case SQLT_FLT:
  1215. bind = php_oci_bind_array_helper_double(var, max_table_length TSRMLS_CC);
  1216. break;
  1217. case SQLT_AFC:
  1218. case SQLT_CHR:
  1219. case SQLT_VCS:
  1220. case SQLT_AVC:
  1221. case SQLT_STR:
  1222. case SQLT_LVC:
  1223. if (maxlength == -1 && zend_hash_num_elements(Z_ARRVAL_P(var)) == 0) {
  1224. php_error_docref(NULL TSRMLS_CC, E_WARNING, "You must provide max length value for empty arrays");
  1225. return 1;
  1226. }
  1227. bind = php_oci_bind_array_helper_string(var, max_table_length, maxlength TSRMLS_CC);
  1228. break;
  1229. case SQLT_ODT:
  1230. bind = php_oci_bind_array_helper_date(var, max_table_length, statement->connection TSRMLS_CC);
  1231. break;
  1232. default:
  1233. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or unsupported datatype given: %ld", type);
  1234. return 1;
  1235. break;
  1236. }
  1237. if (bind == NULL) {
  1238. /* failed to generate bind struct */
  1239. return 1;
  1240. }
  1241. if (!statement->binds) {
  1242. ALLOC_HASHTABLE(statement->binds);
  1243. zend_hash_init(statement->binds, 13, NULL, php_oci_bind_hash_dtor, 0);
  1244. }
  1245. zend_hash_update(statement->binds, name, name_len + 1, bind, sizeof(php_oci_bind), (void **)&bindp);
  1246. bindp->descriptor = NULL;
  1247. bindp->statement = NULL;
  1248. bindp->parent_statement = statement;
  1249. bindp->bind = NULL;
  1250. bindp->zval = var;
  1251. bindp->array.type = type;
  1252. bindp->indicator = 0; /* not used for array binds */
  1253. bindp->type = 0; /* not used for array binds */
  1254. zval_add_ref(&var);
  1255. PHP_OCI_CALL_RETURN(statement->errcode,
  1256. OCIBindByName,
  1257. (
  1258. statement->stmt,
  1259. (OCIBind **)&bindp->bind,
  1260. statement->err,
  1261. (text *)name,
  1262. name_len,
  1263. (dvoid *) bindp->array.elements,
  1264. (sb4) bind->array.max_length,
  1265. type,
  1266. (dvoid *)bindp->array.indicators,
  1267. (ub2 *)bind->array.element_lengths,
  1268. (ub2 *)0, /* bindp->array.retcodes, */
  1269. (ub4) max_table_length,
  1270. (ub4 *) &(bindp->array.current_length),
  1271. (ub4) OCI_DEFAULT
  1272. )
  1273. );
  1274. if (statement->errcode != OCI_SUCCESS) {
  1275. efree(bind);
  1276. statement->errcode = php_oci_error(statement->err, statement->errcode TSRMLS_CC);
  1277. PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
  1278. return 1;
  1279. }
  1280. efree(bind);
  1281. return 0;
  1282. } /* }}} */
  1283. /* {{{ php_oci_bind_array_helper_string()
  1284. Bind arrays to PL/SQL types */
  1285. php_oci_bind *php_oci_bind_array_helper_string(zval* var, long max_table_length, long maxlength TSRMLS_DC)
  1286. {
  1287. php_oci_bind *bind;
  1288. ub4 i;
  1289. HashTable *hash;
  1290. zval **entry;
  1291. hash = HASH_OF(var);
  1292. if (maxlength == -1) {
  1293. zend_hash_internal_pointer_reset(hash);
  1294. while (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE) {
  1295. convert_to_string_ex(entry);
  1296. if (Z_STRLEN_PP(entry) > maxlength) {
  1297. maxlength = Z_STRLEN_PP(entry) + 1;
  1298. }
  1299. zend_hash_move_forward(hash);
  1300. }
  1301. }
  1302. bind = emalloc(sizeof(php_oci_bind));
  1303. bind->array.elements = (text *)safe_emalloc(max_table_length * (maxlength + 1), sizeof(text), 0);
  1304. memset(bind->array.elements, 0, max_table_length * (maxlength + 1) * sizeof(text));
  1305. bind->array.current_length = zend_hash_num_elements(Z_ARRVAL_P(var));
  1306. bind->array.old_length = bind->array.current_length;
  1307. bind->array.max_length = maxlength;
  1308. bind->array.element_lengths = safe_emalloc(max_table_length, sizeof(ub2), 0);
  1309. memset(bind->array.element_lengths, 0, max_table_length*sizeof(ub2));
  1310. bind->array.indicators = safe_emalloc(max_table_length, sizeof(sb2), 0);
  1311. memset(bind->array.indicators, 0, max_table_length*sizeof(sb2));
  1312. zend_hash_internal_pointer_reset(hash);
  1313. for (i = 0; i < bind->array.current_length; i++) {
  1314. if (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE) {
  1315. convert_to_string_ex(entry);
  1316. bind->array.element_lengths[i] = Z_STRLEN_PP(entry);
  1317. if (Z_STRLEN_PP(entry) == 0) {
  1318. bind->array.indicators[i] = -1;
  1319. }
  1320. zend_hash_move_forward(hash);
  1321. } else {
  1322. break;
  1323. }
  1324. }
  1325. zend_hash_internal_pointer_reset(hash);
  1326. for (i = 0; i < max_table_length; i++) {
  1327. if ((i < bind->array.current_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
  1328. int element_length;
  1329. convert_to_string_ex(entry);
  1330. element_length = (maxlength > Z_STRLEN_PP(entry)) ? Z_STRLEN_PP(entry) : maxlength;
  1331. memcpy((text *)bind->array.elements + i*maxlength, Z_STRVAL_PP(entry), element_length);
  1332. ((text *)bind->array.elements)[i*maxlength + element_length] = '\0';
  1333. zend_hash_move_forward(hash);
  1334. } else {
  1335. ((text *)bind->array.elements)[i*maxlength] = '\0';
  1336. }
  1337. }
  1338. zend_hash_internal_pointer_reset(hash);
  1339. return bind;
  1340. } /* }}} */
  1341. /* {{{ php_oci_bind_array_helper_number()
  1342. Bind arrays to PL/SQL types */
  1343. php_oci_bind *php_oci_bind_array_helper_number(zval* var, long max_table_length TSRMLS_DC)
  1344. {
  1345. php_oci_bind *bind;
  1346. ub4 i;
  1347. HashTable *hash;
  1348. zval **entry;
  1349. hash = HASH_OF(var);
  1350. bind = emalloc(sizeof(php_oci_bind));
  1351. bind->array.elements = (ub4 *)safe_emalloc(max_table_length, sizeof(ub4), 0);
  1352. bind->array.current_length = zend_hash_num_elements(Z_ARRVAL_P(var));
  1353. bind->array.old_length = bind->array.current_length;
  1354. bind->array.max_length = sizeof(ub4);
  1355. bind->array.element_lengths = safe_emalloc(max_table_length, sizeof(ub2), 0);
  1356. memset(bind->array.element_lengths, 0, max_table_length * sizeof(ub2));
  1357. bind->array.indicators = NULL;
  1358. zend_hash_internal_pointer_reset(hash);
  1359. for (i = 0; i < max_table_length; i++) {
  1360. if (i < bind->array.current_length) {
  1361. bind->array.element_lengths[i] = sizeof(ub4);
  1362. }
  1363. if ((i < bind->array.current_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
  1364. convert_to_long_ex(entry);
  1365. ((ub4 *)bind->array.elements)[i] = (ub4) Z_LVAL_PP(entry);
  1366. zend_hash_move_forward(hash);
  1367. } else {
  1368. ((ub4 *)bind->array.elements)[i] = 0;
  1369. }
  1370. }
  1371. zend_hash_internal_pointer_reset(hash);
  1372. return bind;
  1373. } /* }}} */
  1374. /* {{{ php_oci_bind_array_helper_double()
  1375. Bind arrays to PL/SQL types */
  1376. php_oci_bind *php_oci_bind_array_helper_double(zval* var, long max_table_length TSRMLS_DC)
  1377. {
  1378. php_oci_bind *bind;
  1379. ub4 i;
  1380. HashTable *hash;
  1381. zval **entry;
  1382. hash = HASH_OF(var);
  1383. bind = emalloc(sizeof(php_oci_bind));
  1384. bind->array.elements = (double *)safe_emalloc(max_table_length, sizeof(double), 0);
  1385. bind->array.current_length = zend_hash_num_elements(Z_ARRVAL_P(var));
  1386. bind->array.old_length = bind->array.current_length;
  1387. bind->array.max_length = sizeof(double);
  1388. bind->array.element_lengths = safe_emalloc(max_table_length, sizeof(ub2), 0);
  1389. memset(bind->array.element_lengths, 0, max_table_length * sizeof(ub2));
  1390. bind->array.indicators = NULL;
  1391. zend_hash_internal_pointer_reset(hash);
  1392. for (i = 0; i < max_table_length; i++) {
  1393. if (i < bind->array.current_length) {
  1394. bind->array.element_lengths[i] = sizeof(double);
  1395. }
  1396. if ((i < bind->array.current_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
  1397. convert_to_double_ex(entry);
  1398. ((double *)bind->array.elements)[i] = (double) Z_DVAL_PP(entry);
  1399. zend_hash_move_forward(hash);
  1400. } else {
  1401. ((double *)bind->array.elements)[i] = 0;
  1402. }
  1403. }
  1404. zend_hash_internal_pointer_reset(hash);
  1405. return bind;
  1406. } /* }}} */
  1407. /* {{{ php_oci_bind_array_helper_date()
  1408. Bind arrays to PL/SQL types */
  1409. php_oci_bind *php_oci_bind_array_helper_date(zval* var, long max_table_length, php_oci_connection *connection TSRMLS_DC)
  1410. {
  1411. php_oci_bind *bind;
  1412. ub4 i;
  1413. HashTable *hash;
  1414. zval **entry;
  1415. hash = HASH_OF(var);
  1416. bind = emalloc(sizeof(php_oci_bind));
  1417. bind->array.elements = (OCIDate *)safe_emalloc(max_table_length, sizeof(OCIDate), 0);
  1418. bind->array.current_length = zend_hash_num_elements(Z_ARRVAL_P(var));
  1419. bind->array.old_length = bind->array.current_length;
  1420. bind->array.max_length = sizeof(OCIDate);
  1421. bind->array.element_lengths = safe_emalloc(max_table_length, sizeof(ub2), 0);
  1422. memset(bind->array.element_lengths, 0, max_table_length * sizeof(ub2));
  1423. bind->array.indicators = NULL;
  1424. zend_hash_internal_pointer_reset(hash);
  1425. for (i = 0; i < max_table_length; i++) {
  1426. OCIDate oci_date;
  1427. if (i < bind->array.current_length) {
  1428. bind->array.element_lengths[i] = sizeof(OCIDate);
  1429. }
  1430. if ((i < bind->array.current_length) && (zend_hash_get_current_data(hash, (void **) &entry) != FAILURE)) {
  1431. convert_to_string_ex(entry);
  1432. PHP_OCI_CALL_RETURN(connection->errcode, OCIDateFromText, (connection->err, (CONST text *)Z_STRVAL_PP(entry), Z_STRLEN_PP(entry), NULL, 0, NULL, 0, &oci_date));
  1433. if (connection->errcode != OCI_SUCCESS) {
  1434. /* failed to convert string to date */
  1435. efree(bind->array.element_lengths);
  1436. efree(bind->array.elements);
  1437. efree(bind);
  1438. connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
  1439. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  1440. return NULL;
  1441. }
  1442. ((OCIDate *)bind->array.elements)[i] = oci_date;
  1443. zend_hash_move_forward(hash);
  1444. } else {
  1445. PHP_OCI_CALL_RETURN(connection->errcode, OCIDateFromText, (connection->err, (CONST text *)"01-JAN-00", sizeof("01-JAN-00")-1, NULL, 0, NULL, 0, &oci_date));
  1446. if (connection->errcode != OCI_SUCCESS) {
  1447. /* failed to convert string to date */
  1448. efree(bind->array.element_lengths);
  1449. efree(bind->array.elements);
  1450. efree(bind);
  1451. connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
  1452. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  1453. return NULL;
  1454. }
  1455. ((OCIDate *)bind->array.elements)[i] = oci_date;
  1456. }
  1457. }
  1458. zend_hash_internal_pointer_reset(hash);
  1459. return bind;
  1460. } /* }}} */
  1461. #endif /* HAVE_OCI8 */
  1462. /*
  1463. * Local variables:
  1464. * tab-width: 4
  1465. * c-basic-offset: 4
  1466. * End:
  1467. * vim600: noet sw=4 ts=4 fdm=marker
  1468. * vim<600: noet sw=4 ts=4
  1469. */