oci_driver.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2016 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. /* $Id$ */
  19. #ifdef HAVE_CONFIG_H
  20. #include "config.h"
  21. #endif
  22. #include "php.h"
  23. #include "php_ini.h"
  24. #include "ext/standard/info.h"
  25. #include "pdo/php_pdo.h"
  26. #include "pdo/php_pdo_driver.h"
  27. #include "php_pdo_oci.h"
  28. #include "php_pdo_oci_int.h"
  29. #include "Zend/zend_exceptions.h"
  30. static inline ub4 pdo_oci_sanitize_prefetch(long prefetch);
  31. static int pdo_oci_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC) /* {{{ */
  32. {
  33. pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
  34. pdo_oci_error_info *einfo;
  35. einfo = &H->einfo;
  36. if (stmt) {
  37. pdo_oci_stmt *S = (pdo_oci_stmt*)stmt->driver_data;
  38. if (S->einfo.errmsg) {
  39. einfo = &S->einfo;
  40. }
  41. }
  42. if (einfo->errcode) {
  43. add_next_index_long(info, einfo->errcode);
  44. add_next_index_string(info, einfo->errmsg, 1);
  45. }
  46. return 1;
  47. }
  48. /* }}} */
  49. ub4 _oci_error(OCIError *err, pdo_dbh_t *dbh, pdo_stmt_t *stmt, char *what, sword status, int isinit, const char *file, int line TSRMLS_DC) /* {{{ */
  50. {
  51. text errbuf[1024] = "<<Unknown>>";
  52. char tmp_buf[2048];
  53. pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
  54. pdo_oci_error_info *einfo;
  55. pdo_oci_stmt *S = NULL;
  56. pdo_error_type *pdo_err = &dbh->error_code;
  57. if (stmt) {
  58. S = (pdo_oci_stmt*)stmt->driver_data;
  59. einfo = &S->einfo;
  60. pdo_err = &stmt->error_code;
  61. }
  62. else {
  63. einfo = &H->einfo;
  64. }
  65. if (einfo->errmsg) {
  66. pefree(einfo->errmsg, dbh->is_persistent);
  67. }
  68. einfo->errmsg = NULL;
  69. einfo->errcode = 0;
  70. einfo->file = file;
  71. einfo->line = line;
  72. if (isinit) { /* Initialization error */
  73. strcpy(*pdo_err, "HY000");
  74. slprintf(tmp_buf, sizeof(tmp_buf), "%s (%s:%d)", what, file, line);
  75. einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
  76. }
  77. else {
  78. switch (status) {
  79. case OCI_SUCCESS:
  80. strcpy(*pdo_err, "00000");
  81. break;
  82. case OCI_ERROR:
  83. OCIErrorGet(err, (ub4)1, NULL, &einfo->errcode, errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR);
  84. slprintf(tmp_buf, sizeof(tmp_buf), "%s: %s (%s:%d)", what, errbuf, file, line);
  85. einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
  86. break;
  87. case OCI_SUCCESS_WITH_INFO:
  88. OCIErrorGet(err, (ub4)1, NULL, &einfo->errcode, errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR);
  89. slprintf(tmp_buf, sizeof(tmp_buf), "%s: OCI_SUCCESS_WITH_INFO: %s (%s:%d)", what, errbuf, file, line);
  90. einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
  91. break;
  92. case OCI_NEED_DATA:
  93. slprintf(tmp_buf, sizeof(tmp_buf), "%s: OCI_NEED_DATA (%s:%d)", what, file, line);
  94. einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
  95. break;
  96. case OCI_NO_DATA:
  97. slprintf(tmp_buf, sizeof(tmp_buf), "%s: OCI_NO_DATA (%s:%d)", what, file, line);
  98. einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
  99. break;
  100. case OCI_INVALID_HANDLE:
  101. slprintf(tmp_buf, sizeof(tmp_buf), "%s: OCI_INVALID_HANDLE (%s:%d)", what, file, line);
  102. einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
  103. break;
  104. case OCI_STILL_EXECUTING:
  105. slprintf(tmp_buf, sizeof(tmp_buf), "%s: OCI_STILL_EXECUTING (%s:%d)", what, file, line);
  106. einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
  107. break;
  108. case OCI_CONTINUE:
  109. slprintf(tmp_buf, sizeof(tmp_buf), "%s: OCI_CONTINUE (%s:%d)", what, file, line);
  110. einfo->errmsg = pestrdup(tmp_buf, dbh->is_persistent);
  111. break;
  112. }
  113. if (einfo->errcode) {
  114. switch (einfo->errcode) {
  115. case 1013: /* user requested cancel of current operation */
  116. zend_bailout();
  117. break;
  118. #if 0
  119. case 955: /* ORA-00955: name is already used by an existing object */
  120. *pdo_err = PDO_ERR_ALREADY_EXISTS;
  121. break;
  122. #endif
  123. case 12154: /* ORA-12154: TNS:could not resolve service name */
  124. strcpy(*pdo_err, "42S02");
  125. break;
  126. case 22: /* ORA-00022: invalid session id */
  127. case 378:
  128. case 602:
  129. case 603:
  130. case 604:
  131. case 609:
  132. case 1012: /* ORA-01012: */
  133. case 1033:
  134. case 1041:
  135. case 1043:
  136. case 1089:
  137. case 1090:
  138. case 1092:
  139. case 3113: /* ORA-03133: end of file on communication channel */
  140. case 3114:
  141. case 3122:
  142. case 3135:
  143. case 12153:
  144. case 27146:
  145. case 28511:
  146. /* consider the connection closed */
  147. dbh->is_closed = 1;
  148. H->attached = 0;
  149. strcpy(*pdo_err, "01002"); /* FIXME */
  150. break;
  151. default:
  152. strcpy(*pdo_err, "HY000");
  153. }
  154. }
  155. if (stmt) {
  156. /* always propogate the error code back up to the dbh,
  157. * so that we can catch the error information when execute
  158. * is called via query. See Bug #33707 */
  159. if (H->einfo.errmsg) {
  160. pefree(H->einfo.errmsg, dbh->is_persistent);
  161. }
  162. H->einfo = *einfo;
  163. H->einfo.errmsg = einfo->errmsg ? pestrdup(einfo->errmsg, dbh->is_persistent) : NULL;
  164. strcpy(dbh->error_code, stmt->error_code);
  165. }
  166. }
  167. /* little mini hack so that we can use this code from the dbh ctor */
  168. if (!dbh->methods) {
  169. zend_throw_exception_ex(php_pdo_get_exception(), einfo->errcode TSRMLS_CC, "SQLSTATE[%s]: %s", *pdo_err, einfo->errmsg);
  170. }
  171. return einfo->errcode;
  172. }
  173. /* }}} */
  174. static int oci_handle_closer(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
  175. {
  176. pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
  177. if (H->svc) {
  178. /* rollback any outstanding work */
  179. OCITransRollback(H->svc, H->err, 0);
  180. }
  181. if (H->session) {
  182. OCIHandleFree(H->session, OCI_HTYPE_SESSION);
  183. H->session = NULL;
  184. }
  185. if (H->svc) {
  186. OCIHandleFree(H->svc, OCI_HTYPE_SVCCTX);
  187. H->svc = NULL;
  188. }
  189. if (H->server && H->attached) {
  190. H->last_err = OCIServerDetach(H->server, H->err, OCI_DEFAULT);
  191. if (H->last_err) {
  192. oci_drv_error("OCIServerDetach");
  193. }
  194. H->attached = 0;
  195. }
  196. if (H->server) {
  197. OCIHandleFree(H->server, OCI_HTYPE_SERVER);
  198. H->server = NULL;
  199. }
  200. if (H->err) {
  201. OCIHandleFree(H->err, OCI_HTYPE_ERROR);
  202. H->err = NULL;
  203. }
  204. if (H->charset && H->env) {
  205. OCIHandleFree(H->env, OCI_HTYPE_ENV);
  206. H->env = NULL;
  207. }
  208. if (H->einfo.errmsg) {
  209. pefree(H->einfo.errmsg, dbh->is_persistent);
  210. H->einfo.errmsg = NULL;
  211. }
  212. pefree(H, dbh->is_persistent);
  213. return 0;
  214. }
  215. /* }}} */
  216. static int oci_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC) /* {{{ */
  217. {
  218. pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
  219. pdo_oci_stmt *S = ecalloc(1, sizeof(*S));
  220. ub4 prefetch;
  221. char *nsql = NULL;
  222. int nsql_len = 0;
  223. int ret;
  224. #if HAVE_OCISTMTFETCH2
  225. S->exec_type = pdo_attr_lval(driver_options, PDO_ATTR_CURSOR,
  226. PDO_CURSOR_FWDONLY TSRMLS_CC) == PDO_CURSOR_SCROLL ?
  227. OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT;
  228. #else
  229. S->exec_type = OCI_DEFAULT;
  230. #endif
  231. S->H = H;
  232. stmt->supports_placeholders = PDO_PLACEHOLDER_NAMED;
  233. ret = pdo_parse_params(stmt, (char*)sql, sql_len, &nsql, &nsql_len TSRMLS_CC);
  234. if (ret == 1) {
  235. /* query was re-written */
  236. sql = nsql;
  237. sql_len = nsql_len;
  238. } else if (ret == -1) {
  239. /* couldn't grok it */
  240. strcpy(dbh->error_code, stmt->error_code);
  241. efree(S);
  242. return 0;
  243. }
  244. /* create an OCI statement handle */
  245. OCIHandleAlloc(H->env, (dvoid*)&S->stmt, OCI_HTYPE_STMT, 0, NULL);
  246. /* and our own private error handle */
  247. OCIHandleAlloc(H->env, (dvoid*)&S->err, OCI_HTYPE_ERROR, 0, NULL);
  248. if (sql_len) {
  249. H->last_err = OCIStmtPrepare(S->stmt, H->err, (text*)sql, sql_len, OCI_NTV_SYNTAX, OCI_DEFAULT);
  250. if (nsql) {
  251. efree(nsql);
  252. nsql = NULL;
  253. }
  254. if (H->last_err) {
  255. H->last_err = oci_drv_error("OCIStmtPrepare");
  256. OCIHandleFree(S->stmt, OCI_HTYPE_STMT);
  257. OCIHandleFree(S->err, OCI_HTYPE_ERROR);
  258. efree(S);
  259. return 0;
  260. }
  261. }
  262. prefetch = pdo_oci_sanitize_prefetch(pdo_attr_lval(driver_options, PDO_ATTR_PREFETCH, PDO_OCI_PREFETCH_DEFAULT TSRMLS_CC));
  263. if (prefetch) {
  264. H->last_err = OCIAttrSet(S->stmt, OCI_HTYPE_STMT, &prefetch, 0,
  265. OCI_ATTR_PREFETCH_ROWS, H->err);
  266. if (!H->last_err) {
  267. prefetch *= PDO_OCI_PREFETCH_ROWSIZE;
  268. H->last_err = OCIAttrSet(S->stmt, OCI_HTYPE_STMT, &prefetch, 0,
  269. OCI_ATTR_PREFETCH_MEMORY, H->err);
  270. }
  271. }
  272. stmt->driver_data = S;
  273. stmt->methods = &oci_stmt_methods;
  274. if (nsql) {
  275. efree(nsql);
  276. nsql = NULL;
  277. }
  278. return 1;
  279. }
  280. /* }}} */
  281. static long oci_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC) /* {{{ */
  282. {
  283. pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
  284. OCIStmt *stmt;
  285. ub2 stmt_type;
  286. ub4 rowcount;
  287. int ret = -1;
  288. OCIHandleAlloc(H->env, (dvoid*)&stmt, OCI_HTYPE_STMT, 0, NULL);
  289. H->last_err = OCIStmtPrepare(stmt, H->err, (text*)sql, sql_len, OCI_NTV_SYNTAX, OCI_DEFAULT);
  290. if (H->last_err) {
  291. H->last_err = oci_drv_error("OCIStmtPrepare");
  292. OCIHandleFree(stmt, OCI_HTYPE_STMT);
  293. return -1;
  294. }
  295. H->last_err = OCIAttrGet(stmt, OCI_HTYPE_STMT, &stmt_type, 0, OCI_ATTR_STMT_TYPE, H->err);
  296. if (stmt_type == OCI_STMT_SELECT) {
  297. /* invalid usage; cancel it */
  298. OCIHandleFree(stmt, OCI_HTYPE_STMT);
  299. php_error_docref(NULL TSRMLS_CC, E_WARNING, "issuing a SELECT query here is invalid");
  300. return -1;
  301. }
  302. /* now we are good to go */
  303. H->last_err = OCIStmtExecute(H->svc, stmt, H->err, 1, 0, NULL, NULL,
  304. (dbh->auto_commit && !dbh->in_txn) ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT);
  305. if (H->last_err) {
  306. H->last_err = oci_drv_error("OCIStmtExecute");
  307. } else {
  308. /* return the number of affected rows */
  309. H->last_err = OCIAttrGet(stmt, OCI_HTYPE_STMT, &rowcount, 0, OCI_ATTR_ROW_COUNT, H->err);
  310. ret = rowcount;
  311. }
  312. OCIHandleFree(stmt, OCI_HTYPE_STMT);
  313. return ret;
  314. }
  315. /* }}} */
  316. static int oci_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen, enum pdo_param_type paramtype TSRMLS_DC) /* {{{ */
  317. {
  318. int qcount = 0;
  319. char const *cu, *l, *r;
  320. char *c;
  321. if (!unquotedlen) {
  322. *quotedlen = 2;
  323. *quoted = emalloc(*quotedlen+1);
  324. strcpy(*quoted, "''");
  325. return 1;
  326. }
  327. /* count single quotes */
  328. for (cu = unquoted; (cu = strchr(cu,'\'')); qcount++, cu++)
  329. ; /* empty loop */
  330. *quotedlen = unquotedlen + qcount + 2;
  331. *quoted = c = emalloc(*quotedlen+1);
  332. *c++ = '\'';
  333. /* foreach (chunk that ends in a quote) */
  334. for (l = unquoted; (r = strchr(l,'\'')); l = r+1) {
  335. strncpy(c, l, r-l+1);
  336. c += (r-l+1);
  337. *c++ = '\''; /* add second quote */
  338. }
  339. /* Copy remainder and add enclosing quote */
  340. strncpy(c, l, *quotedlen-(c-*quoted)-1);
  341. (*quoted)[*quotedlen-1] = '\'';
  342. (*quoted)[*quotedlen] = '\0';
  343. return 1;
  344. }
  345. /* }}} */
  346. static int oci_handle_begin(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
  347. {
  348. /* with Oracle, there is nothing special to be done */
  349. return 1;
  350. }
  351. /* }}} */
  352. static int oci_handle_commit(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
  353. {
  354. pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
  355. H->last_err = OCITransCommit(H->svc, H->err, 0);
  356. if (H->last_err) {
  357. H->last_err = oci_drv_error("OCITransCommit");
  358. return 0;
  359. }
  360. return 1;
  361. }
  362. /* }}} */
  363. static int oci_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
  364. {
  365. pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
  366. H->last_err = OCITransRollback(H->svc, H->err, 0);
  367. if (H->last_err) {
  368. H->last_err = oci_drv_error("OCITransRollback");
  369. return 0;
  370. }
  371. return 1;
  372. }
  373. /* }}} */
  374. static int oci_handle_set_attribute(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC) /* {{{ */
  375. {
  376. pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
  377. if (attr == PDO_ATTR_AUTOCOMMIT) {
  378. if (dbh->in_txn) {
  379. /* Assume they want to commit whatever is outstanding */
  380. H->last_err = OCITransCommit(H->svc, H->err, 0);
  381. if (H->last_err) {
  382. H->last_err = oci_drv_error("OCITransCommit");
  383. return 0;
  384. }
  385. dbh->in_txn = 0;
  386. }
  387. convert_to_long(val);
  388. dbh->auto_commit = Z_LVAL_P(val);
  389. return 1;
  390. } else {
  391. return 0;
  392. }
  393. }
  394. /* }}} */
  395. static int oci_handle_get_attribute(pdo_dbh_t *dbh, long attr, zval *return_value TSRMLS_DC) /* {{{ */
  396. {
  397. pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
  398. switch (attr) {
  399. case PDO_ATTR_SERVER_VERSION:
  400. case PDO_ATTR_SERVER_INFO:
  401. {
  402. text infostr[512];
  403. char verstr[15];
  404. ub4 vernum;
  405. if (OCIServerRelease(H->svc, H->err, infostr, (ub4)sizeof(infostr), (ub1)OCI_HTYPE_SVCCTX, &vernum))
  406. {
  407. ZVAL_STRING(return_value, "<<Unknown>>", 1);
  408. } else {
  409. if (attr == PDO_ATTR_SERVER_INFO) {
  410. ZVAL_STRING(return_value, (char *)infostr, 1);
  411. } else {
  412. slprintf(verstr, sizeof(verstr), "%d.%d.%d.%d.%d",
  413. (int)((vernum>>24) & 0xFF), /* version number */
  414. (int)((vernum>>20) & 0x0F), /* release number*/
  415. (int)((vernum>>12) & 0xFF), /* update number */
  416. (int)((vernum>>8) & 0x0F), /* port release number */
  417. (int)((vernum>>0) & 0xFF)); /* port update number */
  418. ZVAL_STRING(return_value, verstr, 1);
  419. }
  420. }
  421. return TRUE;
  422. }
  423. case PDO_ATTR_CLIENT_VERSION:
  424. {
  425. #if OCI_MAJOR_VERSION > 10 || (OCI_MAJOR_VERSION == 10 && OCI_MINOR_VERSION >= 2)
  426. /* Run time client version */
  427. sword major, minor, update, patch, port_update;
  428. char verstr[15];
  429. OCIClientVersion(&major, &minor, &update, &patch, &port_update);
  430. slprintf(verstr, sizeof(verstr), "%d.%d.%d.%d.%d", major, minor, update, patch, port_update);
  431. ZVAL_STRING(return_value, verstr, 1);
  432. #elif defined(PHP_PDO_OCI_CLIENT_VERSION)
  433. /* Compile time client version */
  434. ZVAL_STRING(return_value, PHP_PDO_OCI_CLIENT_VERSION, 1);
  435. #else
  436. return FALSE;
  437. #endif /* Check for OCIClientVersion() support */
  438. return TRUE;
  439. }
  440. case PDO_ATTR_AUTOCOMMIT:
  441. ZVAL_BOOL(return_value, dbh->auto_commit);
  442. return TRUE;
  443. default:
  444. return FALSE;
  445. }
  446. return FALSE;
  447. }
  448. /* }}} */
  449. static int pdo_oci_check_liveness(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
  450. {
  451. pdo_oci_db_handle *H = (pdo_oci_db_handle *)dbh->driver_data;
  452. sb4 error_code = 0;
  453. #if (!((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2))))
  454. char version[256];
  455. #endif
  456. /* TODO move attached check to PDO level */
  457. if (H->attached == 0) {
  458. return FAILURE;
  459. }
  460. /* TODO add persistent_timeout check at PDO level */
  461. /* Use OCIPing instead of OCIServerVersion. If OCIPing returns ORA-1010 (invalid OCI operation)
  462. * such as from Pre-10.1 servers, the error is still from the server and we would have
  463. * successfully performed a roundtrip and validated the connection. Use OCIServerVersion for
  464. * Pre-10.2 clients
  465. */
  466. #if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2))) /* OCIPing available 10.2 onwards */
  467. H->last_err = OCIPing (H->svc, H->err, OCI_DEFAULT);
  468. #else
  469. /* use good old OCIServerVersion() */
  470. H->last_err = OCIServerVersion (H->svc, H->err, (text *)version, sizeof(version), OCI_HTYPE_SVCCTX);
  471. #endif
  472. if (H->last_err == OCI_SUCCESS) {
  473. return SUCCESS;
  474. }
  475. OCIErrorGet (H->err, (ub4)1, NULL, &error_code, NULL, 0, OCI_HTYPE_ERROR);
  476. if (error_code == 1010) {
  477. return SUCCESS;
  478. }
  479. return FAILURE;
  480. }
  481. /* }}} */
  482. static struct pdo_dbh_methods oci_methods = {
  483. oci_handle_closer,
  484. oci_handle_preparer,
  485. oci_handle_doer,
  486. oci_handle_quoter,
  487. oci_handle_begin,
  488. oci_handle_commit,
  489. oci_handle_rollback,
  490. oci_handle_set_attribute,
  491. NULL,
  492. pdo_oci_fetch_error_func,
  493. oci_handle_get_attribute,
  494. pdo_oci_check_liveness, /* check_liveness */
  495. NULL /* get_driver_methods */
  496. };
  497. static int pdo_oci_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */
  498. {
  499. pdo_oci_db_handle *H;
  500. int i, ret = 0;
  501. struct pdo_data_src_parser vars[] = {
  502. { "charset", NULL, 0 },
  503. { "dbname", "", 0 }
  504. };
  505. php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, 2);
  506. H = pecalloc(1, sizeof(*H), dbh->is_persistent);
  507. dbh->driver_data = H;
  508. /* allocate an environment */
  509. #if HAVE_OCIENVNLSCREATE
  510. if (vars[0].optval) {
  511. H->charset = OCINlsCharSetNameToId(pdo_oci_Env, (const oratext *)vars[0].optval);
  512. if (!H->charset) {
  513. oci_init_error("OCINlsCharSetNameToId: unknown character set name");
  514. goto cleanup;
  515. } else {
  516. if (OCIEnvNlsCreate(&H->env, PDO_OCI_INIT_MODE, 0, NULL, NULL, NULL, 0, NULL, H->charset, H->charset) != OCI_SUCCESS) {
  517. oci_init_error("OCIEnvNlsCreate: Check the character set is valid and that PHP has access to Oracle libraries and NLS data");
  518. goto cleanup;
  519. }
  520. }
  521. }
  522. #endif
  523. if (H->env == NULL) {
  524. /* use the global environment */
  525. H->env = pdo_oci_Env;
  526. }
  527. /* something to hold errors */
  528. OCIHandleAlloc(H->env, (dvoid **)&H->err, OCI_HTYPE_ERROR, 0, NULL);
  529. /* handle for the server */
  530. OCIHandleAlloc(H->env, (dvoid **)&H->server, OCI_HTYPE_SERVER, 0, NULL);
  531. H->last_err = OCIServerAttach(H->server, H->err, (text*)vars[1].optval,
  532. strlen(vars[1].optval), OCI_DEFAULT);
  533. if (H->last_err) {
  534. oci_drv_error("pdo_oci_handle_factory");
  535. goto cleanup;
  536. }
  537. H->attached = 1;
  538. /* create a service context */
  539. H->last_err = OCIHandleAlloc(H->env, (dvoid**)&H->svc, OCI_HTYPE_SVCCTX, 0, NULL);
  540. if (H->last_err) {
  541. oci_drv_error("OCIHandleAlloc: OCI_HTYPE_SVCCTX");
  542. goto cleanup;
  543. }
  544. H->last_err = OCIHandleAlloc(H->env, (dvoid**)&H->session, OCI_HTYPE_SESSION, 0, NULL);
  545. if (H->last_err) {
  546. oci_drv_error("OCIHandleAlloc: OCI_HTYPE_SESSION");
  547. goto cleanup;
  548. }
  549. /* set server handle into service handle */
  550. H->last_err = OCIAttrSet(H->svc, OCI_HTYPE_SVCCTX, H->server, 0, OCI_ATTR_SERVER, H->err);
  551. if (H->last_err) {
  552. oci_drv_error("OCIAttrSet: OCI_ATTR_SERVER");
  553. goto cleanup;
  554. }
  555. /* username */
  556. if (dbh->username) {
  557. H->last_err = OCIAttrSet(H->session, OCI_HTYPE_SESSION,
  558. dbh->username, strlen(dbh->username),
  559. OCI_ATTR_USERNAME, H->err);
  560. if (H->last_err) {
  561. oci_drv_error("OCIAttrSet: OCI_ATTR_USERNAME");
  562. goto cleanup;
  563. }
  564. }
  565. /* password */
  566. if (dbh->password) {
  567. H->last_err = OCIAttrSet(H->session, OCI_HTYPE_SESSION,
  568. dbh->password, strlen(dbh->password),
  569. OCI_ATTR_PASSWORD, H->err);
  570. if (H->last_err) {
  571. oci_drv_error("OCIAttrSet: OCI_ATTR_PASSWORD");
  572. goto cleanup;
  573. }
  574. }
  575. /* Now fire up the session */
  576. H->last_err = OCISessionBegin(H->svc, H->err, H->session, OCI_CRED_RDBMS, OCI_DEFAULT);
  577. if (H->last_err) {
  578. oci_drv_error("OCISessionBegin");
  579. goto cleanup;
  580. }
  581. /* set the server handle into service handle */
  582. H->last_err = OCIAttrSet(H->svc, OCI_HTYPE_SVCCTX, H->session, 0, OCI_ATTR_SESSION, H->err);
  583. if (H->last_err) {
  584. oci_drv_error("OCIAttrSet: OCI_ATTR_SESSION");
  585. goto cleanup;
  586. }
  587. dbh->methods = &oci_methods;
  588. dbh->alloc_own_columns = 1;
  589. dbh->native_case = PDO_CASE_UPPER;
  590. ret = 1;
  591. cleanup:
  592. for (i = 0; i < sizeof(vars)/sizeof(vars[0]); i++) {
  593. if (vars[i].freeme) {
  594. efree(vars[i].optval);
  595. }
  596. }
  597. if (!ret) {
  598. oci_handle_closer(dbh TSRMLS_CC);
  599. }
  600. return ret;
  601. }
  602. /* }}} */
  603. pdo_driver_t pdo_oci_driver = {
  604. PDO_DRIVER_HEADER(oci),
  605. pdo_oci_handle_factory
  606. };
  607. static inline ub4 pdo_oci_sanitize_prefetch(long prefetch) /* {{{ */
  608. {
  609. if (prefetch < 0) {
  610. prefetch = 0;
  611. } else if (prefetch > UB4MAXVAL / PDO_OCI_PREFETCH_ROWSIZE) {
  612. prefetch = PDO_OCI_PREFETCH_DEFAULT;
  613. }
  614. return ((ub4)prefetch);
  615. }
  616. /* }}} */
  617. /*
  618. * Local variables:
  619. * tab-width: 4
  620. * c-basic-offset: 4
  621. * End:
  622. * vim600: noet sw=4 ts=4 fdm=marker
  623. * vim<600: noet sw=4 ts=4
  624. */