oci8_lob.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960
  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. | 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@php.net> |
  24. | Wez Furlong <wez@omniti.com> |
  25. +----------------------------------------------------------------------+
  26. */
  27. #ifdef HAVE_CONFIG_H
  28. #include "config.h"
  29. #endif
  30. #include "php.h"
  31. #include "ext/standard/info.h"
  32. #include "php_ini.h"
  33. #if HAVE_OCI8
  34. #include "php_oci8.h"
  35. #include "php_oci8_int.h"
  36. /* for import/export functions */
  37. #include <fcntl.h>
  38. #ifndef O_BINARY
  39. #define O_BINARY 0
  40. #endif
  41. /* {{{ php_oci_lob_create()
  42. Create LOB descriptor and allocate all the resources needed */
  43. php_oci_descriptor *php_oci_lob_create (php_oci_connection *connection, zend_long type)
  44. {
  45. php_oci_descriptor *descriptor;
  46. sword errstatus;
  47. switch (type) {
  48. case OCI_DTYPE_FILE:
  49. case OCI_DTYPE_LOB:
  50. case OCI_DTYPE_ROWID:
  51. /* these three are allowed */
  52. break;
  53. default:
  54. php_error_docref(NULL, E_WARNING, "Unknown descriptor type " ZEND_LONG_FMT, type);
  55. return NULL;
  56. break;
  57. }
  58. descriptor = ecalloc(1, sizeof(php_oci_descriptor));
  59. descriptor->type = (ub4) type;
  60. descriptor->connection = connection;
  61. GC_ADDREF(descriptor->connection->id);
  62. PHP_OCI_CALL_RETURN(errstatus, OCIDescriptorAlloc, (connection->env, (dvoid*)&(descriptor->descriptor), descriptor->type, (size_t) 0, (dvoid **) 0));
  63. if (errstatus != OCI_SUCCESS) {
  64. OCI_G(errcode) = php_oci_error(OCI_G(err), errstatus);
  65. PHP_OCI_HANDLE_ERROR(connection, OCI_G(errcode));
  66. efree(descriptor);
  67. return NULL;
  68. } else {
  69. OCI_G(errcode) = 0; /* retain backwards compat with OCI8 1.4 */
  70. }
  71. PHP_OCI_REGISTER_RESOURCE(descriptor, le_descriptor);
  72. descriptor->lob_current_position = 0;
  73. descriptor->lob_size = -1; /* we should set it to -1 to know, that it's just not initialized */
  74. descriptor->buffering = PHP_OCI_LOB_BUFFER_DISABLED; /* buffering is off by default */
  75. descriptor->charset_form = SQLCS_IMPLICIT; /* default value */
  76. descriptor->charset_id = connection->charset;
  77. descriptor->is_open = 0;
  78. descriptor->chunk_size = 0;
  79. if (descriptor->type == OCI_DTYPE_LOB || descriptor->type == OCI_DTYPE_FILE) {
  80. /* add Lobs & Files to hash. we'll flush them at the end */
  81. if (!connection->descriptors) {
  82. ALLOC_HASHTABLE(connection->descriptors);
  83. zend_hash_init(connection->descriptors, 0, NULL, php_oci_descriptor_flush_hash_dtor, 0);
  84. connection->descriptor_count = 0;
  85. }
  86. descriptor->index = (connection->descriptor_count)++;
  87. if (connection->descriptor_count == LONG_MAX) {
  88. php_error_docref(NULL, E_WARNING, "Internal descriptor counter has reached limit");
  89. php_oci_connection_descriptors_free(connection);
  90. return NULL;
  91. }
  92. zend_hash_index_update_ptr(connection->descriptors, descriptor->index, descriptor);
  93. }
  94. return descriptor;
  95. }
  96. /* }}} */
  97. /* {{{ php_oci_lob_get_length()
  98. Get length of the LOB. The length is cached so we don't need to ask Oracle every time */
  99. int php_oci_lob_get_length (php_oci_descriptor *descriptor, ub4 *length)
  100. {
  101. php_oci_connection *connection = descriptor->connection;
  102. sword errstatus;
  103. *length = 0;
  104. if (descriptor->lob_size >= 0) {
  105. *length = descriptor->lob_size;
  106. return 0;
  107. } else {
  108. if (descriptor->type == OCI_DTYPE_FILE) {
  109. PHP_OCI_CALL_RETURN(errstatus, OCILobFileOpen, (connection->svc, connection->err, descriptor->descriptor, OCI_FILE_READONLY));
  110. if (errstatus != OCI_SUCCESS) {
  111. connection->errcode = php_oci_error(connection->err, errstatus);
  112. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  113. return 1;
  114. }
  115. }
  116. PHP_OCI_CALL_RETURN(errstatus, OCILobGetLength, (connection->svc, connection->err, descriptor->descriptor, (ub4 *)length));
  117. if (errstatus != OCI_SUCCESS) {
  118. connection->errcode = php_oci_error(connection->err, errstatus);
  119. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  120. return 1;
  121. }
  122. descriptor->lob_size = *length;
  123. if (descriptor->type == OCI_DTYPE_FILE) {
  124. PHP_OCI_CALL_RETURN(errstatus, OCILobFileClose, (connection->svc, connection->err, descriptor->descriptor));
  125. if (errstatus != OCI_SUCCESS) {
  126. connection->errcode = php_oci_error(connection->err, errstatus);
  127. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  128. return 1;
  129. }
  130. }
  131. connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
  132. }
  133. return 0;
  134. }
  135. /* }}} */
  136. /* {{{ php_oci_lob_callback()
  137. Append LOB portion to a memory buffer */
  138. sb4 php_oci_lob_callback (dvoid *ctxp, CONST dvoid *bufxp, oraub8 len, ub1 piece, dvoid **changed_bufpp, oraub8 *changed_lenp)
  139. {
  140. ub4 lenp = (ub4) len;
  141. php_oci_lob_ctx *ctx = (php_oci_lob_ctx *)ctxp;
  142. switch (piece)
  143. {
  144. case OCI_LAST_PIECE:
  145. if ((*(ctx->lob_len) + lenp) > (ctx->alloc_len)) {
  146. /* this should not happen ever */
  147. *(ctx->lob_data) = NULL;
  148. *(ctx->lob_len) = 0;
  149. return OCI_ERROR;
  150. }
  151. memcpy(*(ctx->lob_data) + *(ctx->lob_len), bufxp, (size_t) lenp);
  152. *(ctx->lob_len) += lenp;
  153. *(*(ctx->lob_data) + *(ctx->lob_len)) = 0x00;
  154. return OCI_CONTINUE;
  155. case OCI_FIRST_PIECE:
  156. case OCI_NEXT_PIECE:
  157. if ((*(ctx->lob_len) + lenp) > ctx->alloc_len) {
  158. /* this should not happen ever */
  159. *(ctx->lob_data) = NULL;
  160. *(ctx->lob_len) = 0;
  161. return OCI_ERROR;
  162. }
  163. memcpy(*(ctx->lob_data) + *(ctx->lob_len), bufxp, (size_t) lenp);
  164. *(ctx->lob_len) += lenp;
  165. return OCI_CONTINUE;
  166. default: {
  167. php_error_docref(NULL, E_WARNING, "Unexpected LOB piece id received (value:%d)", piece);
  168. *(ctx->lob_data) = NULL;
  169. *(ctx->lob_len) = 0;
  170. return OCI_ERROR;
  171. }
  172. }
  173. }
  174. /* }}} */
  175. /* {{{ php_oci_lob_calculate_buffer()
  176. Work out the size for LOB buffering */
  177. static inline int php_oci_lob_calculate_buffer(php_oci_descriptor *descriptor, zend_long read_length)
  178. {
  179. php_oci_connection *connection = descriptor->connection;
  180. ub4 chunk_size;
  181. sword errstatus;
  182. if (descriptor->type == OCI_DTYPE_FILE) {
  183. return (int) read_length;
  184. }
  185. if (!descriptor->chunk_size) {
  186. PHP_OCI_CALL_RETURN(errstatus, OCILobGetChunkSize, (connection->svc, connection->err, descriptor->descriptor, &chunk_size));
  187. if (errstatus != OCI_SUCCESS) {
  188. connection->errcode = php_oci_error(connection->err, errstatus);
  189. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  190. return (int) read_length; /* we have to return original length here */
  191. }
  192. descriptor->chunk_size = chunk_size;
  193. connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
  194. }
  195. if ((read_length % descriptor->chunk_size) != 0) {
  196. return (int) descriptor->chunk_size * (((int) read_length / descriptor->chunk_size) + 1);
  197. }
  198. return (int) read_length;
  199. }
  200. /* }}} */
  201. /* {{{ php_oci_lob_read()
  202. Read specified portion of the LOB into the buffer */
  203. int php_oci_lob_read (php_oci_descriptor *descriptor, zend_long read_length, zend_long initial_offset, char **data, ub4 *data_len)
  204. {
  205. php_oci_connection *connection = descriptor->connection;
  206. ub4 length = 0;
  207. int buffer_size = PHP_OCI_LOB_BUFFER_SIZE;
  208. php_oci_lob_ctx ctx;
  209. ub1 *bufp;
  210. oraub8 bytes_read, offset = 0;
  211. oraub8 requested_len = read_length; /* this is by default */
  212. oraub8 chars_read = 0;
  213. int is_clob = 0;
  214. sb4 bytes_per_char = 1;
  215. sword errstatus;
  216. *data_len = 0;
  217. *data = NULL;
  218. ctx.lob_len = data_len;
  219. ctx.lob_data = data;
  220. ctx.alloc_len = 0;
  221. if (php_oci_lob_get_length(descriptor, &length)) {
  222. return 1;
  223. }
  224. if (length <= 0) {
  225. return 0;
  226. }
  227. if (initial_offset > length) {
  228. php_error_docref(NULL, E_WARNING, "Offset must be less than size of the LOB");
  229. return 1;
  230. }
  231. if (read_length == -1) {
  232. requested_len = length;
  233. }
  234. if ((ub4) requested_len > (length - (ub4) initial_offset)) {
  235. requested_len = length - initial_offset;
  236. }
  237. if (requested_len <= 0) {
  238. return 0;
  239. }
  240. offset = initial_offset;
  241. if (descriptor->type == OCI_DTYPE_FILE) {
  242. PHP_OCI_CALL_RETURN(errstatus, OCILobFileOpen, (connection->svc, connection->err, descriptor->descriptor, OCI_FILE_READONLY));
  243. if (errstatus != OCI_SUCCESS) {
  244. connection->errcode = php_oci_error(connection->err, errstatus);
  245. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  246. return 1;
  247. }
  248. } else {
  249. ub2 charset_id = 0;
  250. PHP_OCI_CALL_RETURN(errstatus, OCILobCharSetId, (connection->env, connection->err, descriptor->descriptor, &charset_id));
  251. if (errstatus != OCI_SUCCESS) {
  252. connection->errcode = php_oci_error(connection->err, errstatus);
  253. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  254. return 1;
  255. }
  256. if (charset_id > 0) { /* charset_id is always > 0 for [N]CLOBs */
  257. is_clob = 1;
  258. }
  259. }
  260. if (is_clob) {
  261. PHP_OCI_CALL_RETURN(errstatus, OCINlsNumericInfoGet, (connection->env, connection->err, &bytes_per_char, OCI_NLS_CHARSET_MAXBYTESZ));
  262. if (errstatus != OCI_SUCCESS) {
  263. connection->errcode = php_oci_error(connection->err, errstatus);
  264. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  265. return 1;
  266. }
  267. } else {
  268. /* BLOBs don't have encoding, so bytes_per_char == 1 */
  269. }
  270. ctx.alloc_len = ((ub4) requested_len + 1) * bytes_per_char;
  271. *data = ecalloc(bytes_per_char, requested_len + 1);
  272. if (is_clob) {
  273. chars_read = requested_len;
  274. bytes_read = 0;
  275. } else {
  276. chars_read = 0;
  277. bytes_read = requested_len;
  278. }
  279. buffer_size = ((int) requested_len < buffer_size ) ? (int) requested_len : buffer_size; /* optimize buffer size */
  280. buffer_size = php_oci_lob_calculate_buffer(descriptor, buffer_size); /* use chunk size */
  281. bufp = (ub1 *) ecalloc(1, buffer_size);
  282. PHP_OCI_CALL_RETURN(errstatus, OCILobRead2,
  283. (
  284. connection->svc,
  285. connection->err,
  286. descriptor->descriptor,
  287. (oraub8 *)&bytes_read, /* IN/OUT bytes toread/read */
  288. (oraub8 *)&chars_read, /* IN/OUT chars toread/read */
  289. (oraub8) offset + 1, /* offset (starts with 1) */
  290. (dvoid *) bufp,
  291. (oraub8) buffer_size, /* size of buffer */
  292. OCI_FIRST_PIECE,
  293. (dvoid *)&ctx,
  294. (OCICallbackLobRead2) php_oci_lob_callback, /* callback... */
  295. (ub2) descriptor->charset_id, /* The character set ID of the buffer data. */
  296. (ub1) descriptor->charset_form /* The character set form of the buffer data. */
  297. )
  298. );
  299. efree(bufp);
  300. if (is_clob) {
  301. offset = descriptor->lob_current_position + chars_read;
  302. } else {
  303. offset = descriptor->lob_current_position + bytes_read;
  304. }
  305. if (errstatus != OCI_SUCCESS) {
  306. connection->errcode = php_oci_error(connection->err, errstatus);
  307. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  308. if (*data) {
  309. efree(*data);
  310. *data = NULL;
  311. }
  312. *data_len = 0;
  313. return 1;
  314. }
  315. descriptor->lob_current_position = (int)offset;
  316. if (descriptor->type == OCI_DTYPE_FILE) {
  317. PHP_OCI_CALL_RETURN(errstatus, OCILobFileClose, (connection->svc, connection->err, descriptor->descriptor));
  318. if (errstatus != OCI_SUCCESS) {
  319. connection->errcode = php_oci_error(connection->err, errstatus);
  320. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  321. if (*data) {
  322. efree(*data);
  323. *data = NULL;
  324. }
  325. *data_len = 0;
  326. return 1;
  327. }
  328. }
  329. connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
  330. return 0;
  331. }
  332. /* }}} */
  333. /* {{{ php_oci_lob_write()
  334. Write data to the LOB */
  335. int php_oci_lob_write (php_oci_descriptor *descriptor, ub4 offset, char *data, int data_len, ub4 *bytes_written)
  336. {
  337. OCILobLocator *lob = (OCILobLocator *) descriptor->descriptor;
  338. php_oci_connection *connection = (php_oci_connection *) descriptor->connection;
  339. ub4 lob_length;
  340. sword errstatus;
  341. *bytes_written = 0;
  342. if (php_oci_lob_get_length(descriptor, &lob_length)) {
  343. return 1;
  344. }
  345. if (!data || data_len <= 0) {
  346. return 0;
  347. }
  348. if (offset > descriptor->lob_current_position) {
  349. offset = descriptor->lob_current_position;
  350. }
  351. PHP_OCI_CALL_RETURN(errstatus, OCILobWrite,
  352. (
  353. connection->svc,
  354. connection->err,
  355. lob,
  356. (ub4 *)&data_len,
  357. (ub4) offset + 1,
  358. (dvoid *) data,
  359. (ub4) data_len,
  360. OCI_ONE_PIECE,
  361. (dvoid *)0,
  362. (OCICallbackLobWrite) 0,
  363. (ub2) descriptor->charset_id,
  364. (ub1) descriptor->charset_form
  365. )
  366. );
  367. if (errstatus) {
  368. connection->errcode = php_oci_error(connection->err, errstatus);
  369. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  370. *bytes_written = 0;
  371. return 1;
  372. }
  373. *bytes_written = data_len;
  374. descriptor->lob_current_position += data_len;
  375. if ((int) descriptor->lob_current_position > (int) descriptor->lob_size) {
  376. descriptor->lob_size = descriptor->lob_current_position;
  377. }
  378. /* marking buffer as used */
  379. if (descriptor->buffering == PHP_OCI_LOB_BUFFER_ENABLED) {
  380. descriptor->buffering = PHP_OCI_LOB_BUFFER_USED;
  381. }
  382. connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
  383. return 0;
  384. }
  385. /* }}} */
  386. /* {{{ php_oci_lob_set_buffering()
  387. Turn buffering off/onn for this particular LOB */
  388. int php_oci_lob_set_buffering (php_oci_descriptor *descriptor, int on_off)
  389. {
  390. php_oci_connection *connection = descriptor->connection;
  391. sword errstatus;
  392. if (!on_off && descriptor->buffering == PHP_OCI_LOB_BUFFER_DISABLED) {
  393. /* disabling when it's already off */
  394. return 0;
  395. }
  396. if (on_off && descriptor->buffering != PHP_OCI_LOB_BUFFER_DISABLED) {
  397. /* enabling when it's already on */
  398. return 0;
  399. }
  400. if (on_off) {
  401. PHP_OCI_CALL_RETURN(errstatus, OCILobEnableBuffering, (connection->svc, connection->err, descriptor->descriptor));
  402. } else {
  403. PHP_OCI_CALL_RETURN(errstatus, OCILobDisableBuffering, (connection->svc, connection->err, descriptor->descriptor));
  404. }
  405. if (errstatus != OCI_SUCCESS) {
  406. connection->errcode = php_oci_error(connection->err, errstatus);
  407. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  408. return 1;
  409. }
  410. descriptor->buffering = on_off ? PHP_OCI_LOB_BUFFER_ENABLED : PHP_OCI_LOB_BUFFER_DISABLED;
  411. connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
  412. return 0;
  413. }
  414. /* }}} */
  415. /* {{{ php_oci_lob_get_buffering()
  416. Return current buffering state for the LOB */
  417. int php_oci_lob_get_buffering (php_oci_descriptor *descriptor)
  418. {
  419. if (descriptor->buffering != PHP_OCI_LOB_BUFFER_DISABLED) {
  420. return 1;
  421. } else {
  422. return 0;
  423. }
  424. }
  425. /* }}} */
  426. /* {{{ php_oci_lob_copy()
  427. Copy one LOB (or its part) to another one */
  428. int php_oci_lob_copy (php_oci_descriptor *descriptor_dest, php_oci_descriptor *descriptor_from, zend_long length)
  429. {
  430. php_oci_connection *connection = descriptor_dest->connection;
  431. ub4 length_dest, length_from, copy_len;
  432. sword errstatus;
  433. if (php_oci_lob_get_length(descriptor_dest, &length_dest)) {
  434. return 1;
  435. }
  436. if (php_oci_lob_get_length(descriptor_from, &length_from)) {
  437. return 1;
  438. }
  439. if (length == -1) {
  440. copy_len = length_from - descriptor_from->lob_current_position;
  441. } else {
  442. copy_len = (ub4) length;
  443. }
  444. if ((int)copy_len <= 0) {
  445. /* silently fail, there is nothing to copy */
  446. return 1;
  447. }
  448. PHP_OCI_CALL_RETURN(errstatus, OCILobCopy,
  449. (
  450. connection->svc,
  451. connection->err,
  452. descriptor_dest->descriptor,
  453. descriptor_from->descriptor,
  454. copy_len,
  455. descriptor_dest->lob_current_position+1,
  456. descriptor_from->lob_current_position+1
  457. )
  458. );
  459. if (errstatus != OCI_SUCCESS) {
  460. connection->errcode = php_oci_error(connection->err, errstatus);
  461. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  462. return 1;
  463. }
  464. connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
  465. return 0;
  466. }
  467. /* }}} */
  468. /* {{{ php_oci_lob_close()
  469. Close LOB */
  470. int php_oci_lob_close (php_oci_descriptor *descriptor)
  471. {
  472. php_oci_connection *connection = descriptor->connection;
  473. sword errstatus;
  474. if (descriptor->is_open) {
  475. PHP_OCI_CALL_RETURN(errstatus, OCILobClose, (connection->svc, connection->err, descriptor->descriptor));
  476. if (errstatus != OCI_SUCCESS) {
  477. connection->errcode = php_oci_error(connection->err, errstatus);
  478. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  479. return 1;
  480. }
  481. connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
  482. }
  483. if (php_oci_temp_lob_close(descriptor)) {
  484. return 1;
  485. }
  486. return 0;
  487. }
  488. /* }}} */
  489. /* {{{ php_oci_temp_lob_close()
  490. Close Temporary LOB */
  491. int php_oci_temp_lob_close (php_oci_descriptor *descriptor)
  492. {
  493. php_oci_connection *connection = descriptor->connection;
  494. int is_temporary;
  495. sword errstatus;
  496. PHP_OCI_CALL_RETURN(errstatus, OCILobIsTemporary, (connection->env,connection->err, descriptor->descriptor, &is_temporary));
  497. if (errstatus != OCI_SUCCESS) {
  498. connection->errcode = php_oci_error(connection->err, errstatus);
  499. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  500. return 1;
  501. }
  502. if (is_temporary) {
  503. PHP_OCI_CALL_RETURN(errstatus, OCILobFreeTemporary, (connection->svc, connection->err, descriptor->descriptor));
  504. if (errstatus != OCI_SUCCESS) {
  505. connection->errcode = php_oci_error(connection->err, errstatus);
  506. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  507. return 1;
  508. }
  509. }
  510. connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
  511. return 0;
  512. }
  513. /* }}} */
  514. /* {{{ php_oci_lob_flush()
  515. Flush buffers for the LOB (only if they have been used) */
  516. int php_oci_lob_flush(php_oci_descriptor *descriptor, zend_long flush_flag)
  517. {
  518. OCILobLocator *lob = descriptor->descriptor;
  519. php_oci_connection *connection = descriptor->connection;
  520. sword errstatus;
  521. if (!lob) {
  522. return 1;
  523. }
  524. switch (flush_flag) {
  525. case 0:
  526. case OCI_LOB_BUFFER_FREE:
  527. /* only these two are allowed */
  528. break;
  529. default:
  530. php_error_docref(NULL, E_WARNING, "Invalid flag value: " ZEND_LONG_FMT, flush_flag);
  531. return 1;
  532. break;
  533. }
  534. /* do not really flush buffer, but report success
  535. * to suppress OCI error when flushing not used buffer
  536. * */
  537. if (descriptor->buffering != PHP_OCI_LOB_BUFFER_USED) {
  538. return 0;
  539. }
  540. PHP_OCI_CALL_RETURN(errstatus, OCILobFlushBuffer, (connection->svc, connection->err, lob, (ub4) flush_flag));
  541. if (errstatus != OCI_SUCCESS) {
  542. connection->errcode = php_oci_error(connection->err, errstatus);
  543. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  544. return 1;
  545. }
  546. /* marking buffer as enabled and not used */
  547. descriptor->buffering = PHP_OCI_LOB_BUFFER_ENABLED;
  548. connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
  549. return 0;
  550. }
  551. /* }}} */
  552. /* {{{ php_oci_lob_free()
  553. Close LOB descriptor and free associated resources */
  554. void php_oci_lob_free (php_oci_descriptor *descriptor)
  555. {
  556. if (!descriptor || !descriptor->connection) {
  557. return;
  558. }
  559. if (descriptor->connection->descriptors) {
  560. if (zend_hash_num_elements(descriptor->connection->descriptors) == 0) {
  561. descriptor->connection->descriptor_count = 0;
  562. } else {
  563. /* delete descriptor from the hash */
  564. zend_hash_index_del(descriptor->connection->descriptors, descriptor->index);
  565. if (descriptor->index + 1 == descriptor->connection->descriptor_count) {
  566. /* If the descriptor being freed is the end-most one
  567. * allocated, then the descriptor_count is reduced so
  568. * a future descriptor can reuse the hash table index.
  569. * This can prevent the hash index range increasing in
  570. * the common case that each descriptor is
  571. * allocated/used/freed before another descriptor is
  572. * needed. However it is possible that a script frees
  573. * descriptors in arbitrary order which would prevent
  574. * descriptor_count ever being reduced to zero until
  575. * zend_hash_num_elements() returns 0.
  576. */
  577. descriptor->connection->descriptor_count--;
  578. }
  579. }
  580. }
  581. /* flushing Lobs & Files with buffering enabled */
  582. if ((descriptor->type == OCI_DTYPE_FILE || descriptor->type == OCI_DTYPE_LOB) && descriptor->buffering == PHP_OCI_LOB_BUFFER_USED) {
  583. php_oci_lob_flush(descriptor, OCI_LOB_BUFFER_FREE);
  584. }
  585. if (descriptor->type == OCI_DTYPE_LOB) {
  586. php_oci_temp_lob_close(descriptor);
  587. }
  588. PHP_OCI_CALL(OCIDescriptorFree, (descriptor->descriptor, descriptor->type));
  589. zend_list_delete(descriptor->connection->id);
  590. efree(descriptor);
  591. }
  592. /* }}} */
  593. /* {{{ php_oci_lob_import()
  594. Import LOB contents from the given file */
  595. int php_oci_lob_import (php_oci_descriptor *descriptor, char *filename)
  596. {
  597. int fp;
  598. ub4 loblen;
  599. OCILobLocator *lob = (OCILobLocator *)descriptor->descriptor;
  600. php_oci_connection *connection = descriptor->connection;
  601. char buf[8192];
  602. ub4 offset = 1;
  603. sword errstatus;
  604. if (php_check_open_basedir(filename)) {
  605. return 1;
  606. }
  607. if ((fp = VCWD_OPEN(filename, O_RDONLY|O_BINARY)) == -1) {
  608. php_error_docref(NULL, E_WARNING, "Can't open file %s", filename);
  609. return 1;
  610. }
  611. while ((loblen = read(fp, &buf, sizeof(buf))) > 0) {
  612. PHP_OCI_CALL_RETURN(errstatus,
  613. OCILobWrite,
  614. (
  615. connection->svc,
  616. connection->err,
  617. lob,
  618. &loblen,
  619. offset,
  620. (dvoid *) &buf,
  621. loblen,
  622. OCI_ONE_PIECE,
  623. (dvoid *)0,
  624. (OCICallbackLobWrite) 0,
  625. (ub2) descriptor->charset_id,
  626. (ub1) descriptor->charset_form
  627. )
  628. );
  629. if (errstatus != OCI_SUCCESS) {
  630. connection->errcode = php_oci_error(connection->err, errstatus);
  631. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  632. close(fp);
  633. return 1;
  634. } else {
  635. connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
  636. }
  637. offset += loblen;
  638. }
  639. close(fp);
  640. return 0;
  641. }
  642. /* }}} */
  643. /* {{{ php_oci_lob_append()
  644. Append data to the end of the LOB */
  645. int php_oci_lob_append (php_oci_descriptor *descriptor_dest, php_oci_descriptor *descriptor_from)
  646. {
  647. php_oci_connection *connection = descriptor_dest->connection;
  648. OCILobLocator *lob_dest = descriptor_dest->descriptor;
  649. OCILobLocator *lob_from = descriptor_from->descriptor;
  650. ub4 dest_len, from_len;
  651. sword errstatus;
  652. if (php_oci_lob_get_length(descriptor_dest, &dest_len)) {
  653. return 1;
  654. }
  655. if (php_oci_lob_get_length(descriptor_from, &from_len)) {
  656. return 1;
  657. }
  658. if (from_len <= 0) {
  659. return 0;
  660. }
  661. PHP_OCI_CALL_RETURN(errstatus, OCILobAppend, (connection->svc, connection->err, lob_dest, lob_from));
  662. if (errstatus != OCI_SUCCESS) {
  663. connection->errcode = php_oci_error(connection->err, errstatus);
  664. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  665. return 1;
  666. }
  667. connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
  668. return 0;
  669. }
  670. /* }}} */
  671. /* {{{ php_oci_lob_truncate()
  672. Truncate LOB to the given length */
  673. int php_oci_lob_truncate (php_oci_descriptor *descriptor, zend_long new_lob_length)
  674. {
  675. php_oci_connection *connection = descriptor->connection;
  676. OCILobLocator *lob = descriptor->descriptor;
  677. ub4 lob_length;
  678. sword errstatus;
  679. if (php_oci_lob_get_length(descriptor, &lob_length)) {
  680. return 1;
  681. }
  682. if (lob_length <= 0) {
  683. return 0;
  684. }
  685. if (new_lob_length < 0) {
  686. php_error_docref(NULL, E_WARNING, "Size must be greater than or equal to 0");
  687. return 1;
  688. }
  689. if (new_lob_length > lob_length) {
  690. php_error_docref(NULL, E_WARNING, "Size must be less than or equal to the current LOB size");
  691. return 1;
  692. }
  693. PHP_OCI_CALL_RETURN(errstatus, OCILobTrim, (connection->svc, connection->err, lob, (ub4) new_lob_length));
  694. if (errstatus != OCI_SUCCESS) {
  695. connection->errcode = php_oci_error(connection->err, errstatus);
  696. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  697. return 1;
  698. }
  699. descriptor->lob_size = (ub4) new_lob_length;
  700. connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
  701. return 0;
  702. }
  703. /* }}} */
  704. /* {{{ php_oci_lob_erase()
  705. Erase (or fill with whitespaces, depending on LOB type) the LOB (or its part) */
  706. int php_oci_lob_erase (php_oci_descriptor *descriptor, zend_long offset, ub4 length, ub4 *bytes_erased)
  707. {
  708. php_oci_connection *connection = descriptor->connection;
  709. OCILobLocator *lob = descriptor->descriptor;
  710. ub4 lob_length;
  711. sword errstatus;
  712. *bytes_erased = 0;
  713. if (php_oci_lob_get_length(descriptor, &lob_length)) {
  714. return 1;
  715. }
  716. if (offset == -1) {
  717. offset = descriptor->lob_current_position;
  718. }
  719. if (length == -1) {
  720. length = lob_length;
  721. }
  722. PHP_OCI_CALL_RETURN(errstatus, OCILobErase, (connection->svc, connection->err, lob, (ub4 *)&length, (ub4) offset+1));
  723. if (errstatus != OCI_SUCCESS) {
  724. connection->errcode = php_oci_error(connection->err, errstatus);
  725. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  726. return 1;
  727. }
  728. *bytes_erased = length;
  729. connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
  730. return 0;
  731. }
  732. /* }}} */
  733. /* {{{ php_oci_lob_is_equal()
  734. Compare two LOB descriptors and figure out if they are pointing to the same LOB */
  735. int php_oci_lob_is_equal (php_oci_descriptor *descriptor_first, php_oci_descriptor *descriptor_second, boolean *result)
  736. {
  737. php_oci_connection *connection = descriptor_first->connection;
  738. OCILobLocator *first_lob = descriptor_first->descriptor;
  739. OCILobLocator *second_lob = descriptor_second->descriptor;
  740. sword errstatus;
  741. PHP_OCI_CALL_RETURN(errstatus, OCILobIsEqual, (connection->env, first_lob, second_lob, result));
  742. if (errstatus) {
  743. connection->errcode = php_oci_error(connection->err, errstatus);
  744. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  745. return 1;
  746. }
  747. connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
  748. return 0;
  749. }
  750. /* }}} */
  751. /* {{{ php_oci_lob_write_tmp()
  752. Create temporary LOB and write data to it */
  753. int php_oci_lob_write_tmp (php_oci_descriptor *descriptor, zend_long type, char *data, int data_len)
  754. {
  755. php_oci_connection *connection = descriptor->connection;
  756. OCILobLocator *lob = descriptor->descriptor;
  757. ub4 bytes_written = 0;
  758. sword errstatus;
  759. switch (type) {
  760. case OCI_TEMP_BLOB:
  761. case OCI_TEMP_CLOB:
  762. /* only these two are allowed */
  763. break;
  764. default:
  765. php_error_docref(NULL, E_WARNING, "Invalid temporary lob type: " ZEND_LONG_FMT, type);
  766. return 1;
  767. break;
  768. }
  769. if (data_len < 0) {
  770. return 1;
  771. }
  772. PHP_OCI_CALL_RETURN(errstatus, OCILobCreateTemporary,
  773. (
  774. connection->svc,
  775. connection->err,
  776. lob,
  777. OCI_DEFAULT,
  778. OCI_DEFAULT,
  779. (ub1)type,
  780. OCI_ATTR_NOCACHE,
  781. OCI_DURATION_SESSION
  782. )
  783. );
  784. if (errstatus) {
  785. connection->errcode = php_oci_error(connection->err, errstatus);
  786. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  787. return 1;
  788. }
  789. PHP_OCI_CALL_RETURN(errstatus, OCILobOpen, (connection->svc, connection->err, lob, OCI_LOB_READWRITE));
  790. if (errstatus) {
  791. connection->errcode = php_oci_error(connection->err, errstatus);
  792. PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
  793. return 1;
  794. }
  795. descriptor->is_open = 1;
  796. connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
  797. return php_oci_lob_write(descriptor, 0, data, data_len, &bytes_written);
  798. }
  799. /* }}} */
  800. #endif /* HAVE_OCI8 */
  801. /*
  802. * Local variables:
  803. * tab-width: 4
  804. * c-basic-offset: 4
  805. * End:
  806. * vim600: noet sw=4 ts=4 fdm=marker
  807. * vim<600: noet sw=4 ts=4
  808. */