oci_statement.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 7 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2018 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Author: Wez Furlong <wez@php.net> |
  16. +----------------------------------------------------------------------+
  17. */
  18. #ifdef HAVE_CONFIG_H
  19. #include "config.h"
  20. #endif
  21. #include "php.h"
  22. #include "php_ini.h"
  23. #include "ext/standard/info.h"
  24. #include "pdo/php_pdo.h"
  25. #include "pdo/php_pdo_driver.h"
  26. #include "php_pdo_oci.h"
  27. #include "php_pdo_oci_int.h"
  28. #include "Zend/zend_extensions.h"
  29. #define PDO_OCI_LOBMAXSIZE (4294967295UL) /* OCI_LOBMAXSIZE */
  30. #define STMT_CALL(name, params) \
  31. do { \
  32. S->last_err = name params; \
  33. S->last_err = _oci_error(S->err, stmt->dbh, stmt, #name, S->last_err, FALSE, __FILE__, __LINE__); \
  34. if (S->last_err) { \
  35. return 0; \
  36. } \
  37. } while(0)
  38. #define STMT_CALL_MSG(name, msg, params) \
  39. do { \
  40. S->last_err = name params; \
  41. S->last_err = _oci_error(S->err, stmt->dbh, stmt, #name ": " #msg, S->last_err, FALSE, __FILE__, __LINE__); \
  42. if (S->last_err) { \
  43. return 0; \
  44. } \
  45. } while(0)
  46. static php_stream *oci_create_lob_stream(zval *dbh, pdo_stmt_t *stmt, OCILobLocator *lob);
  47. #define OCI_TEMPLOB_CLOSE(envhp, svchp, errhp, lob) \
  48. do \
  49. { \
  50. boolean isTempLOB; \
  51. OCILobIsTemporary(envhp, errhp, lob, &isTempLOB); \
  52. if (isTempLOB) \
  53. OCILobFreeTemporary(svchp, errhp, lob); \
  54. } while(0)
  55. static int oci_stmt_dtor(pdo_stmt_t *stmt) /* {{{ */
  56. {
  57. pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
  58. HashTable *BC = stmt->bound_columns;
  59. HashTable *BP = stmt->bound_params;
  60. int i;
  61. if (S->stmt) {
  62. /* cancel server side resources for the statement if we didn't
  63. * fetch it all */
  64. OCIStmtFetch(S->stmt, S->err, 0, OCI_FETCH_NEXT, OCI_DEFAULT);
  65. /* free the handle */
  66. OCIHandleFree(S->stmt, OCI_HTYPE_STMT);
  67. S->stmt = NULL;
  68. }
  69. if (S->err) {
  70. OCIHandleFree(S->err, OCI_HTYPE_ERROR);
  71. S->err = NULL;
  72. }
  73. /* need to ensure these go away now */
  74. if (BC) {
  75. zend_hash_destroy(BC);
  76. FREE_HASHTABLE(stmt->bound_columns);
  77. stmt->bound_columns = NULL;
  78. }
  79. if (BP) {
  80. zend_hash_destroy(BP);
  81. FREE_HASHTABLE(stmt->bound_params);
  82. stmt->bound_params = NULL;
  83. }
  84. if (S->einfo.errmsg) {
  85. pefree(S->einfo.errmsg, stmt->dbh->is_persistent);
  86. S->einfo.errmsg = NULL;
  87. }
  88. if (S->cols) {
  89. for (i = 0; i < stmt->column_count; i++) {
  90. if (S->cols[i].data) {
  91. switch (S->cols[i].dtype) {
  92. case SQLT_BLOB:
  93. case SQLT_CLOB:
  94. OCI_TEMPLOB_CLOSE(S->H->env, S->H->svc, S->H->err,
  95. (OCILobLocator *) S->cols[i].data);
  96. OCIDescriptorFree(S->cols[i].data, OCI_DTYPE_LOB);
  97. break;
  98. default:
  99. efree(S->cols[i].data);
  100. }
  101. }
  102. }
  103. efree(S->cols);
  104. S->cols = NULL;
  105. }
  106. efree(S);
  107. stmt->driver_data = NULL;
  108. return 1;
  109. } /* }}} */
  110. static int oci_stmt_execute(pdo_stmt_t *stmt) /* {{{ */
  111. {
  112. pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
  113. ub4 rowcount;
  114. b4 mode;
  115. if (!S->stmt_type) {
  116. STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_STMT_TYPE",
  117. (S->stmt, OCI_HTYPE_STMT, &S->stmt_type, 0, OCI_ATTR_STMT_TYPE, S->err));
  118. }
  119. if (stmt->executed) {
  120. /* ensure that we cancel the cursor from a previous fetch */
  121. OCIStmtFetch(S->stmt, S->err, 0, OCI_FETCH_NEXT, OCI_DEFAULT);
  122. }
  123. #ifdef OCI_STMT_SCROLLABLE_READONLY /* needed for oci8 ? */
  124. if (S->exec_type == OCI_STMT_SCROLLABLE_READONLY) {
  125. mode = OCI_STMT_SCROLLABLE_READONLY;
  126. } else
  127. #endif
  128. if (stmt->dbh->auto_commit && !stmt->dbh->in_txn) {
  129. mode = OCI_COMMIT_ON_SUCCESS;
  130. } else {
  131. mode = OCI_DEFAULT;
  132. }
  133. STMT_CALL(OCIStmtExecute, (S->H->svc, S->stmt, S->err,
  134. (S->stmt_type == OCI_STMT_SELECT && !S->have_blobs) ? 0 : 1, 0, NULL, NULL,
  135. mode));
  136. if (!stmt->executed) {
  137. ub4 colcount;
  138. /* do first-time-only definition of bind/mapping stuff */
  139. /* how many columns do we have ? */
  140. STMT_CALL_MSG(OCIAttrGet, "ATTR_PARAM_COUNT",
  141. (S->stmt, OCI_HTYPE_STMT, &colcount, 0, OCI_ATTR_PARAM_COUNT, S->err));
  142. stmt->column_count = (int)colcount;
  143. if (S->cols) {
  144. int i;
  145. for (i = 0; i < stmt->column_count; i++) {
  146. if (S->cols[i].data) {
  147. switch (S->cols[i].dtype) {
  148. case SQLT_BLOB:
  149. case SQLT_CLOB:
  150. /* do nothing */
  151. break;
  152. default:
  153. efree(S->cols[i].data);
  154. }
  155. }
  156. }
  157. efree(S->cols);
  158. }
  159. S->cols = ecalloc(colcount, sizeof(pdo_oci_column));
  160. }
  161. STMT_CALL_MSG(OCIAttrGet, "ATTR_ROW_COUNT",
  162. (S->stmt, OCI_HTYPE_STMT, &rowcount, 0, OCI_ATTR_ROW_COUNT, S->err));
  163. stmt->row_count = (long)rowcount;
  164. return 1;
  165. } /* }}} */
  166. static sb4 oci_bind_input_cb(dvoid *ctx, OCIBind *bindp, ub4 iter, ub4 index, dvoid **bufpp, ub4 *alenp, ub1 *piecep, dvoid **indpp) /* {{{ */
  167. {
  168. struct pdo_bound_param_data *param = (struct pdo_bound_param_data*)ctx;
  169. pdo_oci_bound_param *P = (pdo_oci_bound_param*)param->driver_data;
  170. zval *parameter;
  171. if (!param) {
  172. php_error_docref(NULL, E_WARNING, "param is NULL in oci_bind_input_cb; this should not happen");
  173. return OCI_ERROR;
  174. }
  175. *indpp = &P->indicator;
  176. if (Z_ISREF(param->parameter))
  177. parameter = Z_REFVAL(param->parameter);
  178. else
  179. parameter = &param->parameter;
  180. if (P->thing) {
  181. *bufpp = P->thing;
  182. *alenp = sizeof(void*);
  183. } else if (ZVAL_IS_NULL(parameter)) {
  184. /* insert a NULL value into the column */
  185. P->indicator = -1; /* NULL */
  186. *bufpp = 0;
  187. *alenp = -1;
  188. } else if (!P->thing) {
  189. /* regular string bind */
  190. convert_to_string(parameter);
  191. *bufpp = Z_STRVAL_P(parameter);
  192. *alenp = (ub4) Z_STRLEN_P(parameter);
  193. }
  194. *piecep = OCI_ONE_PIECE;
  195. return OCI_CONTINUE;
  196. } /* }}} */
  197. static sb4 oci_bind_output_cb(dvoid *ctx, OCIBind *bindp, ub4 iter, ub4 index, dvoid **bufpp, ub4 **alenpp, ub1 *piecep, dvoid **indpp, ub2 **rcodepp) /* {{{ */
  198. {
  199. struct pdo_bound_param_data *param = (struct pdo_bound_param_data*)ctx;
  200. pdo_oci_bound_param *P = (pdo_oci_bound_param*)param->driver_data;
  201. zval *parameter;
  202. if (!param) {
  203. php_error_docref(NULL, E_WARNING, "param is NULL in oci_bind_output_cb; this should not happen");
  204. return OCI_ERROR;
  205. }
  206. if (Z_ISREF(param->parameter))
  207. parameter = Z_REFVAL(param->parameter);
  208. else
  209. parameter = &param->parameter;
  210. if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
  211. P->actual_len = sizeof(OCILobLocator*);
  212. *bufpp = P->thing;
  213. *alenpp = &P->actual_len;
  214. *piecep = OCI_ONE_PIECE;
  215. *rcodepp = &P->retcode;
  216. *indpp = &P->indicator;
  217. return OCI_CONTINUE;
  218. }
  219. if (Z_TYPE_P(parameter) == IS_OBJECT || Z_TYPE_P(parameter) == IS_RESOURCE) {
  220. return OCI_CONTINUE;
  221. }
  222. convert_to_string(parameter);
  223. zval_ptr_dtor_str(parameter);
  224. Z_STR_P(parameter) = zend_string_alloc(param->max_value_len, 1);
  225. P->used_for_output = 1;
  226. P->actual_len = (ub4) Z_STRLEN_P(parameter);
  227. *alenpp = &P->actual_len;
  228. *bufpp = (Z_STR_P(parameter))->val;
  229. *piecep = OCI_ONE_PIECE;
  230. *rcodepp = &P->retcode;
  231. *indpp = &P->indicator;
  232. return OCI_CONTINUE;
  233. } /* }}} */
  234. static int oci_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param, enum pdo_param_event event_type) /* {{{ */
  235. {
  236. pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
  237. /* we're only interested in parameters for prepared SQL right now */
  238. if (param->is_param) {
  239. pdo_oci_bound_param *P;
  240. sb4 value_sz = -1;
  241. zval *parameter;
  242. if (Z_ISREF(param->parameter))
  243. parameter = Z_REFVAL(param->parameter);
  244. else
  245. parameter = &param->parameter;
  246. P = (pdo_oci_bound_param*)param->driver_data;
  247. switch (event_type) {
  248. case PDO_PARAM_EVT_FETCH_PRE:
  249. case PDO_PARAM_EVT_FETCH_POST:
  250. case PDO_PARAM_EVT_NORMALIZE:
  251. /* Do nothing */
  252. break;
  253. case PDO_PARAM_EVT_FREE:
  254. P = param->driver_data;
  255. if (P && P->thing) {
  256. OCI_TEMPLOB_CLOSE(S->H->env, S->H->svc, S->H->err, P->thing);
  257. OCIDescriptorFree(P->thing, OCI_DTYPE_LOB);
  258. P->thing = NULL;
  259. efree(P);
  260. }
  261. else if (P) {
  262. efree(P);
  263. }
  264. break;
  265. case PDO_PARAM_EVT_ALLOC:
  266. P = (pdo_oci_bound_param*)ecalloc(1, sizeof(pdo_oci_bound_param));
  267. param->driver_data = P;
  268. /* figure out what we're doing */
  269. switch (PDO_PARAM_TYPE(param->param_type)) {
  270. case PDO_PARAM_STMT:
  271. return 0;
  272. case PDO_PARAM_LOB:
  273. /* P->thing is now an OCILobLocator * */
  274. P->oci_type = SQLT_BLOB;
  275. value_sz = (sb4) sizeof(OCILobLocator*);
  276. break;
  277. case PDO_PARAM_STR:
  278. default:
  279. P->oci_type = SQLT_CHR;
  280. value_sz = (sb4) param->max_value_len;
  281. if (param->max_value_len == 0) {
  282. value_sz = (sb4) 1332; /* maximum size before value is interpreted as a LONG value */
  283. }
  284. }
  285. if (param->name) {
  286. STMT_CALL(OCIBindByName, (S->stmt,
  287. &P->bind, S->err, (text*)param->name->val,
  288. (sb4) param->name->len, 0, value_sz, P->oci_type,
  289. &P->indicator, 0, &P->retcode, 0, 0,
  290. OCI_DATA_AT_EXEC));
  291. } else {
  292. STMT_CALL(OCIBindByPos, (S->stmt,
  293. &P->bind, S->err, ((ub4)param->paramno)+1,
  294. 0, value_sz, P->oci_type,
  295. &P->indicator, 0, &P->retcode, 0, 0,
  296. OCI_DATA_AT_EXEC));
  297. }
  298. STMT_CALL(OCIBindDynamic, (P->bind,
  299. S->err,
  300. param, oci_bind_input_cb,
  301. param, oci_bind_output_cb));
  302. return 1;
  303. case PDO_PARAM_EVT_EXEC_PRE:
  304. P->indicator = 0;
  305. P->used_for_output = 0;
  306. if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
  307. ub4 empty = 0;
  308. STMT_CALL(OCIDescriptorAlloc, (S->H->env, &P->thing, OCI_DTYPE_LOB, 0, NULL));
  309. STMT_CALL(OCIAttrSet, (P->thing, OCI_DTYPE_LOB, &empty, 0, OCI_ATTR_LOBEMPTY, S->err));
  310. S->have_blobs = 1;
  311. }
  312. return 1;
  313. case PDO_PARAM_EVT_EXEC_POST:
  314. /* fixup stuff set in motion in oci_bind_output_cb */
  315. if (P->used_for_output) {
  316. if (P->indicator == -1) {
  317. /* set up a NULL value */
  318. if (Z_TYPE_P(parameter) == IS_STRING) {
  319. /* OCI likes to stick non-terminated strings in things */
  320. *Z_STRVAL_P(parameter) = '\0';
  321. }
  322. zval_ptr_dtor_str(parameter);
  323. ZVAL_UNDEF(parameter);
  324. } else if (Z_TYPE_P(parameter) == IS_STRING) {
  325. Z_STR_P(parameter) = zend_string_init(Z_STRVAL_P(parameter), P->actual_len, 1);
  326. }
  327. } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB && P->thing) {
  328. php_stream *stm;
  329. if (Z_TYPE_P(parameter) == IS_NULL) {
  330. /* if the param is NULL, then we assume that they
  331. * wanted to bind a lob locator into it from the query
  332. * */
  333. stm = oci_create_lob_stream(&stmt->database_object_handle, stmt, (OCILobLocator*)P->thing);
  334. if (stm) {
  335. OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
  336. php_stream_to_zval(stm, parameter);
  337. }
  338. } else {
  339. /* we're a LOB being used for insert; transfer the data now */
  340. size_t n;
  341. ub4 amt, offset = 1;
  342. char *consume;
  343. php_stream_from_zval_no_verify(stm, parameter);
  344. if (stm) {
  345. OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
  346. do {
  347. char buf[8192];
  348. n = php_stream_read(stm, buf, sizeof(buf));
  349. if ((int)n <= 0) {
  350. break;
  351. }
  352. consume = buf;
  353. do {
  354. amt = (ub4) n;
  355. OCILobWrite(S->H->svc, S->err, (OCILobLocator*)P->thing,
  356. &amt, offset, consume, (ub4) n,
  357. OCI_ONE_PIECE,
  358. NULL, NULL, 0, SQLCS_IMPLICIT);
  359. offset += amt;
  360. n -= amt;
  361. consume += amt;
  362. } while (n);
  363. } while (1);
  364. OCILobClose(S->H->svc, S->err, (OCILobLocator*)P->thing);
  365. OCILobFlushBuffer(S->H->svc, S->err, (OCILobLocator*)P->thing, 0);
  366. } else if (Z_TYPE_P(parameter) == IS_STRING) {
  367. /* stick the string into the LOB */
  368. consume = Z_STRVAL_P(parameter);
  369. n = Z_STRLEN_P(parameter);
  370. if (n) {
  371. OCILobOpen(S->H->svc, S->err, (OCILobLocator*)P->thing, OCI_LOB_READWRITE);
  372. while (n) {
  373. amt = (ub4) n;
  374. OCILobWrite(S->H->svc, S->err, (OCILobLocator*)P->thing,
  375. &amt, offset, consume, (ub4) n,
  376. OCI_ONE_PIECE,
  377. NULL, NULL, 0, SQLCS_IMPLICIT);
  378. consume += amt;
  379. n -= amt;
  380. }
  381. OCILobClose(S->H->svc, S->err, (OCILobLocator*)P->thing);
  382. }
  383. }
  384. OCI_TEMPLOB_CLOSE(S->H->env, S->H->svc, S->H->err, P->thing);
  385. OCIDescriptorFree(P->thing, OCI_DTYPE_LOB);
  386. P->thing = NULL;
  387. }
  388. }
  389. return 1;
  390. }
  391. }
  392. return 1;
  393. } /* }}} */
  394. static int oci_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, zend_long offset) /* {{{ */
  395. {
  396. #if HAVE_OCISTMTFETCH2
  397. ub4 ociori;
  398. #endif
  399. pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
  400. #if HAVE_OCISTMTFETCH2
  401. switch (ori) {
  402. case PDO_FETCH_ORI_NEXT: ociori = OCI_FETCH_NEXT; break;
  403. case PDO_FETCH_ORI_PRIOR: ociori = OCI_FETCH_PRIOR; break;
  404. case PDO_FETCH_ORI_FIRST: ociori = OCI_FETCH_FIRST; break;
  405. case PDO_FETCH_ORI_LAST: ociori = OCI_FETCH_LAST; break;
  406. case PDO_FETCH_ORI_ABS: ociori = OCI_FETCH_ABSOLUTE; break;
  407. case PDO_FETCH_ORI_REL: ociori = OCI_FETCH_RELATIVE; break;
  408. }
  409. S->last_err = OCIStmtFetch2(S->stmt, S->err, 1, ociori, (sb4) offset, OCI_DEFAULT);
  410. #else
  411. S->last_err = OCIStmtFetch(S->stmt, S->err, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
  412. #endif
  413. if (S->last_err == OCI_NO_DATA) {
  414. /* no (more) data */
  415. return 0;
  416. }
  417. if (S->last_err == OCI_NEED_DATA) {
  418. oci_stmt_error("OCI_NEED_DATA");
  419. return 0;
  420. }
  421. if (S->last_err == OCI_SUCCESS_WITH_INFO || S->last_err == OCI_SUCCESS) {
  422. return 1;
  423. }
  424. oci_stmt_error("OCIStmtFetch");
  425. return 0;
  426. } /* }}} */
  427. static sb4 oci_define_callback(dvoid *octxp, OCIDefine *define, ub4 iter, dvoid **bufpp,
  428. ub4 **alenpp, ub1 *piecep, dvoid **indpp, ub2 **rcodepp)
  429. {
  430. pdo_oci_column *col = (pdo_oci_column*)octxp;
  431. switch (col->dtype) {
  432. case SQLT_BLOB:
  433. case SQLT_CLOB:
  434. *piecep = OCI_ONE_PIECE;
  435. *bufpp = col->data;
  436. *alenpp = &col->datalen;
  437. *indpp = (dvoid *)&col->indicator;
  438. break;
  439. default:
  440. php_error_docref(NULL, E_WARNING,
  441. "unhandled datatype in oci_define_callback; this should not happen");
  442. return OCI_ERROR;
  443. }
  444. return OCI_CONTINUE;
  445. }
  446. static int oci_stmt_describe(pdo_stmt_t *stmt, int colno) /* {{{ */
  447. {
  448. pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
  449. OCIParam *param = NULL;
  450. text *colname;
  451. ub2 dtype, data_size, scale, precis;
  452. ub4 namelen;
  453. struct pdo_column_data *col = &stmt->columns[colno];
  454. zend_bool dyn = FALSE;
  455. /* describe the column */
  456. STMT_CALL(OCIParamGet, (S->stmt, OCI_HTYPE_STMT, S->err, (dvoid*)&param, colno+1));
  457. /* what type ? */
  458. STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_DATA_TYPE",
  459. (param, OCI_DTYPE_PARAM, &dtype, 0, OCI_ATTR_DATA_TYPE, S->err));
  460. /* how big ? */
  461. STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_DATA_SIZE",
  462. (param, OCI_DTYPE_PARAM, &data_size, 0, OCI_ATTR_DATA_SIZE, S->err));
  463. /* scale ? */
  464. STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_SCALE",
  465. (param, OCI_DTYPE_PARAM, &scale, 0, OCI_ATTR_SCALE, S->err));
  466. /* precision ? */
  467. STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_PRECISION",
  468. (param, OCI_DTYPE_PARAM, &precis, 0, OCI_ATTR_PRECISION, S->err));
  469. /* name ? */
  470. STMT_CALL_MSG(OCIAttrGet, "OCI_ATTR_NAME",
  471. (param, OCI_DTYPE_PARAM, &colname, &namelen, OCI_ATTR_NAME, S->err));
  472. col->precision = scale;
  473. col->maxlen = data_size;
  474. col->name = zend_string_init((char *)colname, namelen, 0);
  475. S->cols[colno].dtype = dtype;
  476. /* how much room do we need to store the field */
  477. switch (dtype) {
  478. case SQLT_LBI:
  479. case SQLT_LNG:
  480. if (dtype == SQLT_LBI) {
  481. dtype = SQLT_BIN;
  482. } else {
  483. dtype = SQLT_CHR;
  484. }
  485. S->cols[colno].datalen = 512; /* XXX should be INT_MAX and fetched by pieces */
  486. S->cols[colno].data = emalloc(S->cols[colno].datalen + 1);
  487. col->param_type = PDO_PARAM_STR;
  488. break;
  489. case SQLT_BLOB:
  490. case SQLT_CLOB:
  491. col->param_type = PDO_PARAM_LOB;
  492. STMT_CALL(OCIDescriptorAlloc, (S->H->env, (dvoid**)&S->cols[colno].data, OCI_DTYPE_LOB, 0, NULL));
  493. S->cols[colno].datalen = sizeof(OCILobLocator*);
  494. dyn = TRUE;
  495. break;
  496. case SQLT_BIN:
  497. default:
  498. if (dtype == SQLT_DAT || dtype == SQLT_NUM || dtype == SQLT_RDD
  499. #ifdef SQLT_TIMESTAMP
  500. || dtype == SQLT_TIMESTAMP
  501. #endif
  502. #ifdef SQLT_TIMESTAMP_TZ
  503. || dtype == SQLT_TIMESTAMP_TZ
  504. #endif
  505. ) {
  506. /* should be big enough for most date formats and numbers */
  507. S->cols[colno].datalen = 512;
  508. #if defined(SQLT_IBFLOAT) && defined(SQLT_IBDOUBLE)
  509. } else if (dtype == SQLT_IBFLOAT || dtype == SQLT_IBDOUBLE) {
  510. S->cols[colno].datalen = 1024;
  511. #endif
  512. } else if (dtype == SQLT_BIN) {
  513. S->cols[colno].datalen = (ub4) col->maxlen * 2; // raw characters to hex digits
  514. } else {
  515. S->cols[colno].datalen = (ub4) (col->maxlen * S->H->max_char_width);
  516. }
  517. S->cols[colno].data = emalloc(S->cols[colno].datalen + 1);
  518. dtype = SQLT_CHR;
  519. /* returning data as a string */
  520. col->param_type = PDO_PARAM_STR;
  521. }
  522. STMT_CALL(OCIDefineByPos, (S->stmt, &S->cols[colno].def, S->err, colno+1,
  523. S->cols[colno].data, S->cols[colno].datalen, dtype, &S->cols[colno].indicator,
  524. &S->cols[colno].fetched_len, &S->cols[colno].retcode, dyn ? OCI_DYNAMIC_FETCH : OCI_DEFAULT));
  525. if (dyn) {
  526. STMT_CALL(OCIDefineDynamic, (S->cols[colno].def, S->err, &S->cols[colno],
  527. oci_define_callback));
  528. }
  529. return 1;
  530. } /* }}} */
  531. struct _oci_lob_env {
  532. OCISvcCtx *svc;
  533. OCIError *err;
  534. };
  535. typedef struct _oci_lob_env oci_lob_env;
  536. struct oci_lob_self {
  537. zval dbh;
  538. pdo_stmt_t *stmt;
  539. pdo_oci_stmt *S;
  540. OCILobLocator *lob;
  541. oci_lob_env *E;
  542. ub4 offset;
  543. };
  544. static size_t oci_blob_write(php_stream *stream, const char *buf, size_t count)
  545. {
  546. struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
  547. ub4 amt;
  548. sword r;
  549. amt = (ub4) count;
  550. r = OCILobWrite(self->E->svc, self->E->err, self->lob,
  551. &amt, self->offset, (char*)buf, (ub4) count,
  552. OCI_ONE_PIECE,
  553. NULL, NULL, 0, SQLCS_IMPLICIT);
  554. if (r != OCI_SUCCESS) {
  555. return (size_t)-1;
  556. }
  557. self->offset += amt;
  558. return amt;
  559. }
  560. static size_t oci_blob_read(php_stream *stream, char *buf, size_t count)
  561. {
  562. struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
  563. ub4 amt;
  564. sword r;
  565. amt = (ub4) count;
  566. r = OCILobRead(self->E->svc, self->E->err, self->lob,
  567. &amt, self->offset, buf, (ub4) count,
  568. NULL, NULL, 0, SQLCS_IMPLICIT);
  569. if (r != OCI_SUCCESS && r != OCI_NEED_DATA) {
  570. return (size_t)-1;
  571. }
  572. self->offset += amt;
  573. if (amt < count) {
  574. stream->eof = 1;
  575. }
  576. return amt;
  577. }
  578. static int oci_blob_close(php_stream *stream, int close_handle)
  579. {
  580. struct oci_lob_self *self = (struct oci_lob_self *)stream->abstract;
  581. pdo_stmt_t *stmt = self->stmt;
  582. if (close_handle) {
  583. zend_object *obj = &stmt->std;
  584. OCILobClose(self->E->svc, self->E->err, self->lob);
  585. zval_ptr_dtor(&self->dbh);
  586. GC_DELREF(obj);
  587. efree(self->E);
  588. efree(self);
  589. }
  590. /* php_pdo_free_statement(stmt); */
  591. return 0;
  592. }
  593. static int oci_blob_flush(php_stream *stream)
  594. {
  595. struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
  596. OCILobFlushBuffer(self->E->svc, self->E->err, self->lob, 0);
  597. return 0;
  598. }
  599. static int oci_blob_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffset)
  600. {
  601. struct oci_lob_self *self = (struct oci_lob_self*)stream->abstract;
  602. if (offset >= PDO_OCI_LOBMAXSIZE) {
  603. return -1;
  604. } else {
  605. self->offset = (ub4) offset + 1; /* Oracle LOBS are 1-based, but PHP is 0-based */
  606. return 0;
  607. }
  608. }
  609. static const php_stream_ops oci_blob_stream_ops = {
  610. oci_blob_write,
  611. oci_blob_read,
  612. oci_blob_close,
  613. oci_blob_flush,
  614. "pdo_oci blob stream",
  615. oci_blob_seek,
  616. NULL,
  617. NULL,
  618. NULL
  619. };
  620. static php_stream *oci_create_lob_stream(zval *dbh, pdo_stmt_t *stmt, OCILobLocator *lob)
  621. {
  622. php_stream *stm;
  623. struct oci_lob_self *self = ecalloc(1, sizeof(*self));
  624. ZVAL_COPY_VALUE(&self->dbh, dbh);
  625. self->lob = lob;
  626. self->offset = 1; /* 1-based */
  627. self->stmt = stmt;
  628. self->S = (pdo_oci_stmt*)stmt->driver_data;
  629. self->E = ecalloc(1, sizeof(oci_lob_env));
  630. self->E->svc = self->S->H->svc;
  631. self->E->err = self->S->err;
  632. stm = php_stream_alloc(&oci_blob_stream_ops, self, 0, "r+b");
  633. if (stm) {
  634. zend_object *obj;
  635. obj = &stmt->std;
  636. Z_ADDREF(self->dbh);
  637. GC_ADDREF(obj);
  638. return stm;
  639. }
  640. efree(self);
  641. return NULL;
  642. }
  643. static int oci_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, size_t *len, int *caller_frees) /* {{{ */
  644. {
  645. pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
  646. pdo_oci_column *C = &S->cols[colno];
  647. /* check the indicator to ensure that the data is intact */
  648. if (C->indicator == -1) {
  649. /* A NULL value */
  650. *ptr = NULL;
  651. *len = 0;
  652. return 1;
  653. } else if (C->indicator == 0) {
  654. /* it was stored perfectly */
  655. if (C->dtype == SQLT_BLOB || C->dtype == SQLT_CLOB) {
  656. if (C->data) {
  657. *ptr = (char*)oci_create_lob_stream(&stmt->database_object_handle, stmt, (OCILobLocator*)C->data);
  658. OCILobOpen(S->H->svc, S->err, (OCILobLocator*)C->data, OCI_LOB_READONLY);
  659. }
  660. *len = (size_t) 0;
  661. return *ptr ? 1 : 0;
  662. }
  663. *ptr = C->data;
  664. *len = (size_t) C->fetched_len;
  665. return 1;
  666. } else {
  667. /* it was truncated */
  668. php_error_docref(NULL, E_WARNING, "column %d data was too large for buffer and was truncated to fit it", colno);
  669. *ptr = C->data;
  670. *len = (size_t) C->fetched_len;
  671. return 1;
  672. }
  673. } /* }}} */
  674. const struct pdo_stmt_methods oci_stmt_methods = {
  675. oci_stmt_dtor,
  676. oci_stmt_execute,
  677. oci_stmt_fetch,
  678. oci_stmt_describe,
  679. oci_stmt_get_col,
  680. oci_stmt_param_hook
  681. };
  682. /*
  683. * Local variables:
  684. * tab-width: 4
  685. * c-basic-offset: 4
  686. * End:
  687. * vim600: noet sw=4 ts=4 fdm=marker
  688. * vim<600: noet sw=4 ts=4
  689. */