1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 6 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Authors: Stig Sæther Bakken <ssb@php.net> |
16 : | Thies C. Arntzen <thies@thieso.net> |
17 : | |
18 : | Collection support by Andy Sautins <asautins@veripost.net> |
19 : | Temporary LOB support by David Benson <dbenson@mancala.com> |
20 : | ZTS per process OCIPLogon by Harald Radi <harald.radi@nme.at> |
21 : | |
22 : | Redesigned by: Antony Dovgal <antony@zend.com> |
23 : | Andi Gutmans <andi@zend.com> |
24 : | Wez Furlong <wez@omniti.com> |
25 : +----------------------------------------------------------------------+
26 : */
27 :
28 : /* $Id: oci8_lob.c 277841 2009-03-26 20:02:53Z felipe $ */
29 :
30 :
31 :
32 : #ifdef HAVE_CONFIG_H
33 : #include "config.h"
34 : #endif
35 :
36 : #include "php.h"
37 : #include "ext/standard/info.h"
38 : #include "php_ini.h"
39 :
40 : #if HAVE_OCI8
41 :
42 : #include "php_oci8.h"
43 : #include "php_oci8_int.h"
44 :
45 : /* for import/export functions */
46 : #include <fcntl.h>
47 :
48 : #ifndef O_BINARY
49 : #define O_BINARY 0
50 : #endif
51 :
52 : /* {{{ php_oci_lob_create()
53 : Create LOB descriptor and allocate all the resources needed */
54 : php_oci_descriptor *php_oci_lob_create (php_oci_connection *connection, long type TSRMLS_DC)
55 183634 : {
56 : php_oci_descriptor *descriptor;
57 :
58 183634 : switch (type) {
59 : case OCI_DTYPE_FILE:
60 : case OCI_DTYPE_LOB:
61 : case OCI_DTYPE_ROWID:
62 : /* these three are allowed */
63 : break;
64 : default:
65 4 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown descriptor type %ld", type);
66 4 : return NULL;
67 : break;
68 : }
69 :
70 183630 : descriptor = ecalloc(1, sizeof(php_oci_descriptor));
71 183630 : descriptor->type = type;
72 183630 : descriptor->connection = connection;
73 183630 : zend_list_addref(descriptor->connection->rsrc_id);
74 :
75 183630 : PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIDescriptorAlloc, (connection->env, (dvoid*)&(descriptor->descriptor), descriptor->type, (size_t) 0, (dvoid **) 0));
76 :
77 183630 : if (OCI_G(errcode) != OCI_SUCCESS) {
78 0 : OCI_G(errcode) = php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
79 0 : PHP_OCI_HANDLE_ERROR(connection, OCI_G(errcode));
80 0 : efree(descriptor);
81 0 : return NULL;
82 : }
83 :
84 183630 : PHP_OCI_REGISTER_RESOURCE(descriptor, le_descriptor);
85 :
86 183630 : descriptor->lob_current_position = 0;
87 183630 : descriptor->lob_size = -1; /* we should set it to -1 to know, that it's just not initialized */
88 183630 : descriptor->buffering = PHP_OCI_LOB_BUFFER_DISABLED; /* buffering is off by default */
89 183630 : descriptor->charset_form = SQLCS_IMPLICIT; /* default value */
90 183630 : descriptor->charset_id = connection->charset;
91 183630 : descriptor->is_open = 0;
92 :
93 183630 : if (descriptor->type == OCI_DTYPE_LOB || descriptor->type == OCI_DTYPE_FILE) {
94 : /* add Lobs & Files to hash. we'll flush them at the end */
95 183626 : if (!connection->descriptors) {
96 121 : ALLOC_HASHTABLE(connection->descriptors);
97 121 : zend_hash_init(connection->descriptors, 0, NULL, php_oci_descriptor_flush_hash_dtor, 0);
98 : }
99 :
100 183626 : zend_hash_next_index_insert(connection->descriptors,&descriptor,sizeof(php_oci_descriptor *),NULL);
101 : }
102 183630 : return descriptor;
103 :
104 : } /* }}} */
105 :
106 : /* {{{ php_oci_lob_get_length()
107 : Get length of the LOB. The length is cached so we don't need to ask Oracle every time */
108 : int php_oci_lob_get_length (php_oci_descriptor *descriptor, ub4 *length TSRMLS_DC)
109 2021 : {
110 2021 : php_oci_connection *connection = descriptor->connection;
111 :
112 2021 : *length = 0;
113 :
114 2021 : if (descriptor->lob_size >= 0) {
115 518 : *length = descriptor->lob_size;
116 518 : return 0;
117 : } else {
118 1503 : if (descriptor->type == OCI_DTYPE_FILE) {
119 4 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobFileOpen, (connection->svc, connection->err, descriptor->descriptor, OCI_FILE_READONLY));
120 4 : if (connection->errcode != OCI_SUCCESS) {
121 0 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
122 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
123 0 : return 1;
124 : }
125 : }
126 :
127 1503 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobGetLength, (connection->svc, connection->err, descriptor->descriptor, (ub4 *)length));
128 :
129 1503 : if (connection->errcode != OCI_SUCCESS) {
130 3 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
131 3 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
132 3 : return 1;
133 : }
134 :
135 1500 : descriptor->lob_size = *length;
136 :
137 1500 : if (descriptor->type == OCI_DTYPE_FILE) {
138 4 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobFileClose, (connection->svc, connection->err, descriptor->descriptor));
139 :
140 4 : if (connection->errcode != OCI_SUCCESS) {
141 0 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
142 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
143 0 : return 1;
144 : }
145 : }
146 : }
147 1500 : return 0;
148 : } /* }}} */
149 :
150 : /* {{{ php_oci_lob_callback()
151 : Append LOB portion to a memory buffer */
152 : #if defined(HAVE_OCI_LOB_READ2)
153 : sb4 php_oci_lob_callback (dvoid *ctxp, CONST dvoid *bufxp, oraub8 len, ub1 piece, dvoid **changed_bufpp, oraub8 *changed_lenp)
154 : #else
155 : sb4 php_oci_lob_callback (dvoid *ctxp, CONST dvoid *bufxp, ub4 len, ub1 piece)
156 : #endif
157 2596 : {
158 2596 : ub4 lenp = (ub4) len;
159 2596 : php_oci_lob_ctx *ctx = (php_oci_lob_ctx *)ctxp;
160 : TSRMLS_FETCH();
161 :
162 2596 : switch (piece)
163 : {
164 : case OCI_LAST_PIECE:
165 1525 : if ((*(ctx->lob_len) + lenp) > (ctx->alloc_len)) {
166 : /* this should not happen ever */
167 0 : *(ctx->lob_data) = NULL;
168 0 : *(ctx->lob_len) = 0;
169 0 : return OCI_ERROR;
170 : }
171 :
172 1525 : memcpy(*(ctx->lob_data) + *(ctx->lob_len), bufxp, (size_t) lenp);
173 1525 : *(ctx->lob_len) += lenp;
174 :
175 1525 : *(*(ctx->lob_data) + *(ctx->lob_len) + 1) = 0;
176 1525 : *(*(ctx->lob_data) + *(ctx->lob_len)) = 0;
177 :
178 1525 : return OCI_CONTINUE;
179 :
180 : case OCI_FIRST_PIECE:
181 : case OCI_NEXT_PIECE:
182 1071 : if ((*(ctx->lob_len) + lenp) > ctx->alloc_len) {
183 : /* this should not happen ever */
184 0 : *(ctx->lob_data) = NULL;
185 0 : *(ctx->lob_len) = 0;
186 0 : return OCI_ERROR;
187 : }
188 :
189 1071 : memcpy(*(ctx->lob_data) + *(ctx->lob_len), bufxp, (size_t) lenp);
190 1071 : *(ctx->lob_len) += lenp;
191 1071 : return OCI_CONTINUE;
192 :
193 : default:
194 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unexpected LOB piece id received (value:%d)", piece);
195 0 : *(ctx->lob_data) = NULL;
196 0 : *(ctx->lob_len) = 0;
197 0 : return OCI_ERROR;
198 : }
199 : }
200 : /* }}} */
201 :
202 : /* {{{ php_oci_lob_calculate_buffer() */
203 : static inline int php_oci_lob_calculate_buffer(php_oci_descriptor *descriptor, long read_length TSRMLS_DC)
204 1525 : {
205 1525 : php_oci_connection *connection = descriptor->connection;
206 : ub4 chunk_size;
207 :
208 1525 : if (descriptor->type == OCI_DTYPE_FILE) {
209 4 : return read_length;
210 : }
211 :
212 1521 : if (!descriptor->chunk_size) {
213 1299 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobGetChunkSize, (connection->svc, connection->err, descriptor->descriptor, &chunk_size));
214 :
215 1299 : if (connection->errcode != OCI_SUCCESS) {
216 0 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
217 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
218 0 : return read_length; /* we have to return original length here */
219 : }
220 1299 : descriptor->chunk_size = chunk_size;
221 : }
222 :
223 1521 : if ((read_length % descriptor->chunk_size) != 0) {
224 1521 : return descriptor->chunk_size * ((read_length / descriptor->chunk_size) + 1);
225 : }
226 0 : return read_length;
227 : }
228 : /* }}} */
229 :
230 : /* {{{ php_oci_lob_read()
231 : Read specified portion of the LOB into the buffer */
232 : int php_oci_lob_read (php_oci_descriptor *descriptor, long read_length, long initial_offset, zstr *data, ub4 *data_len TSRMLS_DC)
233 1548 : {
234 1548 : php_oci_connection *connection = descriptor->connection;
235 1548 : ub4 length = 0;
236 1548 : int buffer_size = PHP_OCI_LOB_BUFFER_SIZE;
237 : php_oci_lob_ctx ctx;
238 : ub1 *bufp;
239 : php_oci_lob_type lob_type;
240 : #if defined(HAVE_OCI_LOB_READ2)
241 1548 : oraub8 bytes_read, offset = 0;
242 1548 : oraub8 requested_len = read_length; /* this is by default */
243 1548 : oraub8 chars_read = 0;
244 : #else
245 : int bytes_read, offset = 0;
246 : int requested_len = read_length; /* this is by default */
247 : #endif
248 1548 : sb4 bytes_per_char = 1;
249 :
250 1548 : *data_len = 0;
251 1548 : *data = NULL_ZSTR;
252 1548 : ctx.lob_len = data_len;
253 1548 : ctx.lob_data = &(data->s);
254 1548 : ctx.alloc_len = 0;
255 :
256 1548 : if (php_oci_lob_get_length(descriptor, &length TSRMLS_CC)) {
257 0 : return 1;
258 : }
259 :
260 1548 : if (length <= 0) {
261 21 : return 0;
262 : }
263 :
264 1527 : if (initial_offset > length) {
265 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset must be less than size of the LOB");
266 1 : return 1;
267 : }
268 :
269 1526 : if (read_length == -1) {
270 1087 : requested_len = length;
271 : }
272 :
273 1526 : if (requested_len > (length - initial_offset)) {
274 16 : requested_len = length - initial_offset;
275 : }
276 :
277 1526 : if (requested_len <= 0) {
278 1 : return 0;
279 : }
280 :
281 1525 : offset = initial_offset;
282 :
283 1525 : if (descriptor->type == OCI_DTYPE_FILE) {
284 4 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobFileOpen, (connection->svc, connection->err, descriptor->descriptor, OCI_FILE_READONLY));
285 :
286 4 : if (connection->errcode != OCI_SUCCESS) {
287 0 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
288 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
289 0 : return 1;
290 : }
291 : }
292 :
293 1525 : if (php_oci_lob_get_type(descriptor, &lob_type TSRMLS_CC) > 0) {
294 0 : return 1;
295 : }
296 :
297 1525 : if (lob_type == OCI_IS_CLOB) {
298 1461 : PHP_OCI_CALL_RETURN(connection->errcode, OCINlsNumericInfoGet, (connection->env, connection->err, &bytes_per_char, OCI_NLS_CHARSET_MAXBYTESZ));
299 :
300 1461 : if (connection->errcode != OCI_SUCCESS) {
301 0 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
302 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
303 0 : return 1;
304 : }
305 : } else {
306 : /* BLOBs don't have encoding, so bytes_per_char == 1 */
307 : }
308 :
309 1525 : ctx.alloc_len = (requested_len + UBYTES(1)) * bytes_per_char;
310 1525 : data->s = ecalloc(bytes_per_char, requested_len + UBYTES(1));
311 :
312 : #ifdef HAVE_OCI_LOB_READ2
313 1525 : if (lob_type == OCI_IS_CLOB) {
314 1461 : chars_read = requested_len;
315 1461 : bytes_read = 0;
316 : } else {
317 64 : chars_read = 0;
318 64 : bytes_read = requested_len;
319 : }
320 :
321 1525 : buffer_size = (requested_len < buffer_size ) ? requested_len : buffer_size; /* optimize buffer size */
322 1525 : buffer_size = php_oci_lob_calculate_buffer(descriptor, buffer_size TSRMLS_CC); /* use chunk size */
323 :
324 1525 : bufp = (ub1 *) ecalloc(1, buffer_size);
325 1525 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobRead2,
326 : (
327 : connection->svc,
328 : connection->err,
329 : descriptor->descriptor,
330 : (oraub8 *)&bytes_read, /* IN/OUT bytes toread/read */
331 : (oraub8 *)&chars_read, /* IN/OUT chars toread/read */
332 : (oraub8) offset + 1, /* offset (starts with 1) */
333 : (dvoid *) bufp,
334 : (oraub8) buffer_size, /* size of buffer */
335 : OCI_FIRST_PIECE,
336 : (dvoid *)&ctx,
337 : (OCICallbackLobRead2) php_oci_lob_callback, /* callback... */
338 : (ub2) descriptor->charset_id, /* The character set ID of the buffer data. */
339 : (ub1) descriptor->charset_form /* The character set form of the buffer data. */
340 : )
341 : );
342 :
343 1525 : efree(bufp);
344 :
345 1525 : if (lob_type == OCI_IS_CLOB) {
346 1461 : offset = descriptor->lob_current_position + chars_read;
347 : } else {
348 64 : offset = descriptor->lob_current_position + bytes_read;
349 : }
350 :
351 : #else
352 :
353 : bytes_read = requested_len;
354 : buffer_size = (requested_len < buffer_size ) ? requested_len : buffer_size; /* optimize buffer size */
355 : buffer_size = php_oci_lob_calculate_buffer(descriptor, buffer_size TSRMLS_CC); /* use chunk size */
356 :
357 : bufp = (ub1 *) ecalloc(1, buffer_size);
358 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobRead,
359 : (
360 : connection->svc,
361 : connection->err,
362 : descriptor->descriptor,
363 : &bytes_read, /* IN/OUT bytes toread/read */
364 : offset + 1, /* offset (starts with 1) */
365 : (dvoid *) bufp,
366 : (ub4) buffer_size, /* size of buffer */
367 : (dvoid *)&ctx,
368 : (OCICallbackLobRead) php_oci_lob_callback, /* callback... */
369 : (ub2) descriptor->charset_id, /* The character set ID of the buffer data. */
370 : (ub1) descriptor->charset_form /* The character set form of the buffer data. */
371 : )
372 : );
373 :
374 : efree(bufp);
375 : offset = descriptor->lob_current_position + bytes_read;
376 :
377 : #endif
378 :
379 1525 : if (connection->errcode != OCI_SUCCESS) {
380 0 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
381 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
382 0 : if (data->s) {
383 0 : efree(data->s);
384 0 : *data = NULL_ZSTR;
385 : }
386 0 : *data_len = 0;
387 0 : return 1;
388 : }
389 :
390 1525 : descriptor->lob_current_position = (offset <= descriptor->lob_size) ? offset : descriptor->lob_size;
391 :
392 1525 : if (descriptor->type == OCI_DTYPE_FILE) {
393 4 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobFileClose, (connection->svc, connection->err, descriptor->descriptor));
394 :
395 4 : if (connection->errcode != OCI_SUCCESS) {
396 0 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
397 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
398 0 : if (data->s) {
399 0 : efree(data->s);
400 0 : *data = NULL_ZSTR;
401 : }
402 0 : *data_len = 0;
403 0 : return 1;
404 : }
405 : }
406 :
407 1525 : return 0;
408 : } /* }}} */
409 :
410 : /* {{{ php_oci_lob_write()
411 : Write data to the LOB */
412 : int php_oci_lob_write (php_oci_descriptor *descriptor, ub4 offset, zstr data, int data_len, ub4 *bytes_written TSRMLS_DC)
413 203 : {
414 203 : OCILobLocator *lob = (OCILobLocator *) descriptor->descriptor;
415 203 : php_oci_connection *connection = (php_oci_connection *) descriptor->connection;
416 : ub4 lob_length;
417 203 : ub4 data_len_out = data_len;
418 : php_oci_lob_type lob_type;
419 :
420 203 : *bytes_written = 0;
421 203 : if (php_oci_lob_get_length(descriptor, &lob_length TSRMLS_CC)) {
422 1 : return 1;
423 : }
424 :
425 202 : if (php_oci_lob_get_type(descriptor, &lob_type TSRMLS_CC)) {
426 0 : return 1;
427 : }
428 :
429 202 : if (lob_type == OCI_IS_CLOB) {
430 147 : data_len_out = TEXT_CHARS(data_len);
431 : }
432 :
433 202 : if (!data.v || data_len <= 0) {
434 7 : return 0;
435 : }
436 :
437 : if (offset < 0) {
438 : offset = 0;
439 : }
440 :
441 195 : if (offset > descriptor->lob_current_position) {
442 1 : offset = descriptor->lob_current_position;
443 : }
444 :
445 195 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobWrite,
446 : (
447 : connection->svc,
448 : connection->err,
449 : lob,
450 : (ub4 *)&data_len_out,
451 : (ub4) offset + 1,
452 : (dvoid *) (text *)data.s,
453 : (ub4) data_len,
454 : OCI_ONE_PIECE,
455 : (dvoid *)0,
456 : (OCICallbackLobWrite) 0,
457 : (ub2) descriptor->charset_id,
458 : (ub1) descriptor->charset_form
459 : )
460 : );
461 :
462 195 : if (connection->errcode) {
463 1 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
464 1 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
465 1 : *bytes_written = 0;
466 1 : return 1;
467 : }
468 194 : *bytes_written = data_len_out;
469 194 : descriptor->lob_current_position += data_len_out;
470 :
471 194 : if (descriptor->lob_current_position > descriptor->lob_size) {
472 192 : descriptor->lob_size = descriptor->lob_current_position;
473 : }
474 :
475 : /* marking buffer as used */
476 194 : if (descriptor->buffering == PHP_OCI_LOB_BUFFER_ENABLED) {
477 2 : descriptor->buffering = PHP_OCI_LOB_BUFFER_USED;
478 : }
479 :
480 194 : return 0;
481 : } /* }}} */
482 :
483 : /* {{{ php_oci_lob_set_buffering()
484 : Turn buffering off/onn for this particular LOB */
485 : int php_oci_lob_set_buffering (php_oci_descriptor *descriptor, int on_off TSRMLS_DC)
486 6 : {
487 6 : php_oci_connection *connection = descriptor->connection;
488 :
489 6 : if (!on_off && descriptor->buffering == PHP_OCI_LOB_BUFFER_DISABLED) {
490 : /* disabling when it's already off */
491 2 : return 0;
492 : }
493 :
494 4 : if (on_off && descriptor->buffering != PHP_OCI_LOB_BUFFER_DISABLED) {
495 : /* enabling when it's already on */
496 1 : return 0;
497 : }
498 :
499 3 : if (on_off) {
500 3 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobEnableBuffering, (connection->svc, connection->err, descriptor->descriptor));
501 : } else {
502 0 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobDisableBuffering, (connection->svc, connection->err, descriptor->descriptor));
503 : }
504 :
505 3 : if (connection->errcode != OCI_SUCCESS) {
506 0 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
507 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
508 0 : return 1;
509 : }
510 3 : descriptor->buffering = on_off ? PHP_OCI_LOB_BUFFER_ENABLED : PHP_OCI_LOB_BUFFER_DISABLED;
511 3 : return 0;
512 : } /* }}} */
513 :
514 : /* {{{ php_oci_lob_get_buffering()
515 : Return current buffering state for the LOB */
516 : int php_oci_lob_get_buffering (php_oci_descriptor *descriptor)
517 0 : {
518 0 : if (descriptor->buffering != PHP_OCI_LOB_BUFFER_DISABLED) {
519 0 : return 1;
520 : } else {
521 0 : return 0;
522 : }
523 : } /* }}} */
524 :
525 : /* {{{ php_oci_lob_copy()
526 : Copy one LOB (or its part) to another one */
527 : int php_oci_lob_copy (php_oci_descriptor *descriptor_dest, php_oci_descriptor *descriptor_from, long length TSRMLS_DC)
528 5 : {
529 5 : php_oci_connection *connection = descriptor_dest->connection;
530 : ub4 length_dest, length_from, copy_len;
531 :
532 5 : if (php_oci_lob_get_length(descriptor_dest, &length_dest TSRMLS_CC)) {
533 1 : return 1;
534 : }
535 :
536 4 : if (php_oci_lob_get_length(descriptor_from, &length_from TSRMLS_CC)) {
537 1 : return 1;
538 : }
539 :
540 3 : if (length == -1) {
541 1 : copy_len = length_from - descriptor_from->lob_current_position;
542 : } else {
543 2 : copy_len = length;
544 : }
545 :
546 3 : if ((int)copy_len <= 0) {
547 : /* silently fail, there is nothing to copy */
548 1 : return 1;
549 : }
550 :
551 2 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobCopy,
552 : (
553 : connection->svc,
554 : connection->err,
555 : descriptor_dest->descriptor,
556 : descriptor_from->descriptor,
557 : copy_len,
558 : descriptor_dest->lob_current_position+1,
559 : descriptor_from->lob_current_position+1
560 : )
561 : );
562 :
563 2 : if (connection->errcode != OCI_SUCCESS) {
564 0 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
565 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
566 0 : return 1;
567 : }
568 :
569 2 : return 0;
570 : } /* }}} */
571 :
572 : /* {{{ php_oci_lob_close()
573 : Close LOB */
574 : int php_oci_lob_close (php_oci_descriptor *descriptor TSRMLS_DC)
575 115 : {
576 115 : php_oci_connection *connection = descriptor->connection;
577 :
578 115 : if (descriptor->is_open) {
579 112 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobClose, (connection->svc, connection->err, descriptor->descriptor));
580 : }
581 :
582 115 : if (connection->errcode != OCI_SUCCESS) {
583 0 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
584 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
585 0 : return 1;
586 : }
587 :
588 115 : if (php_oci_temp_lob_close(descriptor TSRMLS_CC)) {
589 0 : return 1;
590 : }
591 :
592 115 : return 0;
593 : } /* }}} */
594 :
595 : /* {{{ php_oci_temp_lob_close()
596 : Close Temporary LOB */
597 : int php_oci_temp_lob_close (php_oci_descriptor *descriptor TSRMLS_DC)
598 184769 : {
599 184769 : php_oci_connection *connection = descriptor->connection;
600 : int is_temporary;
601 :
602 184769 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobIsTemporary, (connection->env,connection->err, descriptor->descriptor, &is_temporary));
603 :
604 184769 : if (connection->errcode != OCI_SUCCESS) {
605 0 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
606 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
607 0 : return 1;
608 : }
609 :
610 184769 : if (is_temporary) {
611 3118 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobFreeTemporary, (connection->svc, connection->err, descriptor->descriptor));
612 :
613 3118 : if (connection->errcode != OCI_SUCCESS) {
614 0 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
615 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
616 0 : return 1;
617 : }
618 : }
619 184769 : return 0;
620 : } /* }}} */
621 :
622 :
623 : /* {{{ php_oci_lob_flush()
624 : Flush buffers for the LOB (only if they have been used) */
625 : int php_oci_lob_flush(php_oci_descriptor *descriptor, long flush_flag TSRMLS_DC)
626 5 : {
627 5 : OCILobLocator *lob = descriptor->descriptor;
628 5 : php_oci_connection *connection = descriptor->connection;
629 :
630 5 : if (!lob) {
631 0 : return 1;
632 : }
633 :
634 5 : switch (flush_flag) {
635 : case 0:
636 : case OCI_LOB_BUFFER_FREE:
637 : /* only these two are allowed */
638 : break;
639 : default:
640 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid flag value: %ld", flush_flag);
641 1 : return 1;
642 : break;
643 : }
644 :
645 : /* do not really flush buffer, but report success
646 : * to suppress OCI error when flushing not used buffer
647 : * */
648 4 : if (descriptor->buffering != PHP_OCI_LOB_BUFFER_USED) {
649 2 : return 0;
650 : }
651 :
652 2 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobFlushBuffer, (connection->svc, connection->err, lob, flush_flag));
653 :
654 2 : if (connection->errcode != OCI_SUCCESS) {
655 0 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
656 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
657 0 : return 1;
658 : }
659 :
660 : /* marking buffer as enabled and not used */
661 2 : descriptor->buffering = PHP_OCI_LOB_BUFFER_ENABLED;
662 2 : return 0;
663 : } /* }}} */
664 :
665 : /* {{{ php_oci_lob_free()
666 : Close LOB descriptor and free associated resources */
667 : void php_oci_lob_free (php_oci_descriptor *descriptor TSRMLS_DC)
668 183630 : {
669 183630 : if (!descriptor || !descriptor->connection) {
670 0 : return;
671 : }
672 :
673 183630 : if (descriptor->connection->descriptors) {
674 : /* delete descriptor from the hash */
675 183619 : zend_hash_apply_with_argument(descriptor->connection->descriptors, php_oci_descriptor_delete_from_hash, (void *)&descriptor->id TSRMLS_CC);
676 : }
677 :
678 : /* flushing Lobs & Files with buffering enabled */
679 183630 : if ((descriptor->type == OCI_DTYPE_FILE || descriptor->type == OCI_DTYPE_LOB) && descriptor->buffering == PHP_OCI_LOB_BUFFER_USED) {
680 0 : php_oci_lob_flush(descriptor, OCI_LOB_BUFFER_FREE TSRMLS_CC);
681 : }
682 :
683 183630 : if (descriptor->type == OCI_DTYPE_LOB) {
684 183620 : php_oci_temp_lob_close(descriptor TSRMLS_CC);
685 : }
686 :
687 183630 : PHP_OCI_CALL(OCIDescriptorFree, (descriptor->descriptor, descriptor->type));
688 :
689 183630 : zend_list_delete(descriptor->connection->rsrc_id);
690 183630 : efree(descriptor);
691 : } /* }}} */
692 :
693 : /* {{{ php_oci_lob_import()
694 : Import LOB contents from the given file */
695 : int php_oci_lob_import (php_oci_descriptor *descriptor, char *filename TSRMLS_DC)
696 6 : {
697 : int fp;
698 : ub4 loblen;
699 6 : OCILobLocator *lob = (OCILobLocator *)descriptor->descriptor;
700 6 : php_oci_connection *connection = descriptor->connection;
701 : char buf[8192];
702 6 : ub4 offset = 1;
703 :
704 6 : if (php_check_open_basedir(filename TSRMLS_CC)) {
705 0 : return 1;
706 : }
707 :
708 6 : if ((fp = VCWD_OPEN(filename, O_RDONLY|O_BINARY)) == -1) {
709 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't open file %s", filename);
710 2 : return 1;
711 : }
712 :
713 12 : while ((loblen = read(fp, &buf, sizeof(buf))) > 0) {
714 4 : PHP_OCI_CALL_RETURN(connection->errcode,
715 : OCILobWrite,
716 : (
717 : connection->svc,
718 : connection->err,
719 : lob,
720 : &loblen,
721 : offset,
722 : (dvoid *) &buf,
723 : loblen,
724 : OCI_ONE_PIECE,
725 : (dvoid *)0,
726 : (OCICallbackLobWrite) 0,
727 : (ub2) descriptor->charset_id,
728 : (ub1) descriptor->charset_form
729 : )
730 : );
731 :
732 4 : if (connection->errcode != OCI_SUCCESS) {
733 0 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
734 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
735 0 : close(fp);
736 0 : return 1;
737 : }
738 4 : offset += loblen;
739 : }
740 4 : close(fp);
741 :
742 4 : return 0;
743 : } /* }}} */
744 :
745 : /* {{{ php_oci_lob_append()
746 : Append data to the end of the LOB */
747 : int php_oci_lob_append (php_oci_descriptor *descriptor_dest, php_oci_descriptor *descriptor_from TSRMLS_DC)
748 2 : {
749 2 : php_oci_connection *connection = descriptor_dest->connection;
750 2 : OCILobLocator *lob_dest = descriptor_dest->descriptor;
751 2 : OCILobLocator *lob_from = descriptor_from->descriptor;
752 : ub4 dest_len, from_len;
753 :
754 2 : if (php_oci_lob_get_length(descriptor_dest, &dest_len TSRMLS_CC)) {
755 0 : return 1;
756 : }
757 :
758 2 : if (php_oci_lob_get_length(descriptor_from, &from_len TSRMLS_CC)) {
759 0 : return 1;
760 : }
761 :
762 2 : if (from_len <= 0) {
763 0 : return 0;
764 : }
765 :
766 2 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobAppend, (connection->svc, connection->err, lob_dest, lob_from));
767 :
768 2 : if (connection->errcode != OCI_SUCCESS) {
769 0 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
770 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
771 0 : return 1;
772 : }
773 2 : return 0;
774 : } /* }}} */
775 :
776 : /* {{{ php_oci_lob_truncate()
777 : Truncate LOB to the given length */
778 : int php_oci_lob_truncate (php_oci_descriptor *descriptor, long new_lob_length TSRMLS_DC)
779 10 : {
780 10 : php_oci_connection *connection = descriptor->connection;
781 10 : OCILobLocator *lob = descriptor->descriptor;
782 : ub4 lob_length;
783 :
784 10 : if (php_oci_lob_get_length(descriptor, &lob_length TSRMLS_CC)) {
785 0 : return 1;
786 : }
787 :
788 10 : if (lob_length <= 0) {
789 1 : return 0;
790 : }
791 :
792 9 : if (new_lob_length < 0) {
793 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Size must be greater than or equal to 0");
794 0 : return 1;
795 : }
796 :
797 9 : if (new_lob_length > lob_length) {
798 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Size must be less than or equal to the current LOB size");
799 1 : return 1;
800 : }
801 :
802 8 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobTrim, (connection->svc, connection->err, lob, new_lob_length));
803 :
804 8 : if (connection->errcode != OCI_SUCCESS) {
805 0 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
806 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
807 0 : return 1;
808 : }
809 :
810 8 : descriptor->lob_size = new_lob_length;
811 8 : return 0;
812 : } /* }}} */
813 :
814 : /* {{{ php_oci_lob_erase()
815 : Erase (or fill with whitespaces, depending on LOB type) the LOB (or its part) */
816 : int php_oci_lob_erase (php_oci_descriptor *descriptor, long offset, ub4 length, ub4 *bytes_erased TSRMLS_DC)
817 5 : {
818 5 : php_oci_connection *connection = descriptor->connection;
819 5 : OCILobLocator *lob = descriptor->descriptor;
820 : ub4 lob_length;
821 :
822 5 : *bytes_erased = 0;
823 :
824 5 : if (php_oci_lob_get_length(descriptor, &lob_length TSRMLS_CC)) {
825 0 : return 1;
826 : }
827 :
828 5 : if (offset == -1) {
829 2 : offset = descriptor->lob_current_position;
830 : }
831 :
832 5 : if (length == -1) {
833 2 : length = lob_length;
834 : }
835 :
836 5 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobErase, (connection->svc, connection->err, lob, (ub4 *)&length, offset+1));
837 :
838 5 : if (connection->errcode != OCI_SUCCESS) {
839 2 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
840 2 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
841 2 : return 1;
842 : }
843 :
844 3 : *bytes_erased = length;
845 3 : return 0;
846 : } /* }}} */
847 :
848 : /* {{{ php_oci_lob_is_equal()
849 : Compare two LOB descriptors and figure out if they are pointing to the same LOB */
850 : int php_oci_lob_is_equal (php_oci_descriptor *descriptor_first, php_oci_descriptor *descriptor_second, boolean *result TSRMLS_DC)
851 1 : {
852 1 : php_oci_connection *connection = descriptor_first->connection;
853 1 : OCILobLocator *first_lob = descriptor_first->descriptor;
854 1 : OCILobLocator *second_lob = descriptor_second->descriptor;
855 :
856 1 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobIsEqual, (connection->env, first_lob, second_lob, result));
857 :
858 1 : if (connection->errcode) {
859 0 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
860 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
861 0 : return 1;
862 : }
863 1 : return 0;
864 : } /* }}} */
865 :
866 : /* {{{ php_oci_lob_write_tmp()
867 : Create temporary LOB and write data to it */
868 : int php_oci_lob_write_tmp (php_oci_descriptor *descriptor, ub1 type, zstr data, int data_len TSRMLS_DC)
869 116 : {
870 116 : php_oci_connection *connection = descriptor->connection;
871 116 : OCILobLocator *lob = descriptor->descriptor;
872 116 : ub4 bytes_written = 0;
873 :
874 116 : switch (type) {
875 : case OCI_TEMP_BLOB:
876 : case OCI_TEMP_CLOB:
877 : /* only these two are allowed */
878 : break;
879 : default:
880 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid temporary lob type: %d", type);
881 1 : return 1;
882 : break;
883 : }
884 :
885 115 : if (data_len < 0) {
886 0 : return 1;
887 : }
888 :
889 115 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobCreateTemporary,
890 : (
891 : connection->svc,
892 : connection->err,
893 : lob,
894 : OCI_DEFAULT,
895 : OCI_DEFAULT,
896 : type,
897 : OCI_ATTR_NOCACHE,
898 : OCI_DURATION_SESSION
899 : )
900 : );
901 :
902 115 : if (connection->errcode) {
903 0 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
904 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
905 0 : return 1;
906 : }
907 :
908 115 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobOpen, (connection->svc, connection->err, lob, OCI_LOB_READWRITE));
909 :
910 115 : if (connection->errcode) {
911 0 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
912 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
913 0 : return 1;
914 : }
915 :
916 115 : descriptor->is_open = 1;
917 :
918 115 : return php_oci_lob_write(descriptor, 0, data, data_len, &bytes_written TSRMLS_CC);
919 : } /* }}} */
920 :
921 : /* {{{ php_oci_lob_get_type()
922 : Determine whether LOB is a CLOB or a BLOB */
923 : int php_oci_lob_get_type(php_oci_descriptor *descriptor, php_oci_lob_type *lob_type TSRMLS_DC)
924 3274 : {
925 3274 : php_oci_connection *connection = descriptor->connection;
926 :
927 3274 : *lob_type = 0;
928 :
929 3274 : if (descriptor->lob_type) {
930 1790 : *lob_type = descriptor->lob_type;
931 1790 : return 0;
932 : }
933 :
934 1484 : if (descriptor->type == OCI_DTYPE_FILE) {
935 4 : *lob_type = OCI_IS_BLOB;
936 4 : descriptor->lob_type = OCI_IS_BLOB;
937 4 : return 0;
938 : } else {
939 1480 : ub2 charset_id = 0;
940 :
941 1480 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobCharSetId, (connection->env, connection->err, descriptor->descriptor, &charset_id));
942 :
943 1480 : if (connection->errcode != OCI_SUCCESS) {
944 0 : connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
945 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
946 0 : return 1;
947 : }
948 :
949 1480 : if (charset_id > 0) { /* charset_id is always > 0 for [N]CLOBs */
950 1400 : *lob_type = OCI_IS_CLOB;
951 1400 : descriptor->lob_type = OCI_IS_CLOB;
952 1400 : return 0;
953 : }
954 : }
955 :
956 80 : *lob_type = OCI_IS_BLOB;
957 80 : descriptor->lob_type = OCI_IS_BLOB;
958 :
959 80 : return 0;
960 : }
961 : /* }}} */
962 :
963 : #endif /* HAVE_OCI8 */
964 :
965 : /*
966 : * Local variables:
967 : * tab-width: 4
968 : * c-basic-offset: 4
969 : * End:
970 : * vim600: noet sw=4 ts=4 fdm=marker
971 : * vim<600: noet sw=4 ts=4
972 : */
|