oci_statement.c 27 KB

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