1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
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 272374 2008-12-31 11:17:49Z sebastian $ */
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 183677 : {
56 : php_oci_descriptor *descriptor;
57 :
58 183677 : 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 183673 : descriptor = ecalloc(1, sizeof(php_oci_descriptor));
71 183673 : descriptor->type = type;
72 183673 : descriptor->connection = connection;
73 183673 : zend_list_addref(descriptor->connection->rsrc_id);
74 :
75 183673 : PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIDescriptorAlloc, (connection->env, (dvoid*)&(descriptor->descriptor), descriptor->type, (size_t) 0, (dvoid **) 0));
76 :
77 183673 : if (OCI_G(errcode) != OCI_SUCCESS) {
78 0 : connection->errcode = php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
79 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
80 0 : efree(descriptor);
81 0 : return NULL;
82 : }
83 :
84 183673 : PHP_OCI_REGISTER_RESOURCE(descriptor, le_descriptor);
85 :
86 183673 : descriptor->lob_current_position = 0;
87 183673 : descriptor->lob_size = -1; /* we should set it to -1 to know, that it's just not initialized */
88 183673 : descriptor->buffering = PHP_OCI_LOB_BUFFER_DISABLED; /* buffering is off by default */
89 183673 : descriptor->charset_form = SQLCS_IMPLICIT; /* default value */
90 183673 : descriptor->charset_id = connection->charset;
91 183673 : descriptor->is_open = 0;
92 :
93 183673 : 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 183669 : if (!connection->descriptors) {
96 131 : ALLOC_HASHTABLE(connection->descriptors);
97 131 : zend_hash_init(connection->descriptors, 0, NULL, php_oci_descriptor_flush_hash_dtor, 0);
98 : }
99 :
100 183669 : zend_hash_next_index_insert(connection->descriptors,&descriptor,sizeof(php_oci_descriptor *),NULL);
101 : }
102 183673 : 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 2009 : {
110 2009 : php_oci_connection *connection = descriptor->connection;
111 :
112 2009 : *length = 0;
113 :
114 2009 : if (descriptor->lob_size >= 0) {
115 525 : *length = descriptor->lob_size;
116 525 : return 0;
117 : } else {
118 1484 : 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 : 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 1484 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobGetLength, (connection->svc, connection->err, descriptor->descriptor, (ub4 *)length));
128 :
129 1484 : if (connection->errcode != OCI_SUCCESS) {
130 3 : 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 1481 : descriptor->lob_size = *length;
136 :
137 1481 : 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 : 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 1481 : 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 4615 : {
158 4615 : ub4 lenp = (ub4) len;
159 4615 : php_oci_lob_ctx *ctx = (php_oci_lob_ctx *)ctxp;
160 :
161 4615 : switch (piece)
162 : {
163 : case OCI_LAST_PIECE:
164 1516 : if ((*(ctx->lob_len) + lenp) > (ctx->alloc_len)) {
165 : /* this should not happen ever */
166 0 : *(ctx->lob_data) = NULL;
167 0 : *(ctx->lob_len) = 0;
168 0 : return OCI_ERROR;
169 : }
170 1516 : memcpy(*(ctx->lob_data) + *(ctx->lob_len), bufxp, (size_t) lenp);
171 1516 : *(ctx->lob_len) += lenp;
172 1516 : *(*(ctx->lob_data) + *(ctx->lob_len)) = 0x00;
173 1516 : return OCI_CONTINUE;
174 :
175 : case OCI_FIRST_PIECE:
176 : case OCI_NEXT_PIECE:
177 3099 : if ((*(ctx->lob_len) + lenp) > ctx->alloc_len) {
178 : /* this should not happen ever */
179 0 : *(ctx->lob_data) = NULL;
180 0 : *(ctx->lob_len) = 0;
181 0 : return OCI_ERROR;
182 : }
183 3099 : memcpy(*(ctx->lob_data) + *(ctx->lob_len), bufxp, (size_t) lenp);
184 3099 : *(ctx->lob_len) += lenp;
185 3099 : return OCI_CONTINUE;
186 :
187 : default: {
188 : TSRMLS_FETCH();
189 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unexpected LOB piece id received (value:%d)", piece);
190 0 : *(ctx->lob_data) = NULL;
191 0 : *(ctx->lob_len) = 0;
192 0 : return OCI_ERROR;
193 : }
194 : }
195 : }
196 : /* }}} */
197 :
198 : /* {{{ php_oci_lob_calculate_buffer() */
199 : static inline int php_oci_lob_calculate_buffer(php_oci_descriptor *descriptor, long read_length TSRMLS_DC)
200 1516 : {
201 1516 : php_oci_connection *connection = descriptor->connection;
202 : ub4 chunk_size;
203 :
204 1516 : if (descriptor->type == OCI_DTYPE_FILE) {
205 4 : return read_length;
206 : }
207 :
208 1512 : if (!descriptor->chunk_size) {
209 1293 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobGetChunkSize, (connection->svc, connection->err, descriptor->descriptor, &chunk_size));
210 :
211 1293 : if (connection->errcode != OCI_SUCCESS) {
212 0 : php_oci_error(connection->err, connection->errcode TSRMLS_CC);
213 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
214 0 : return read_length; /* we have to return original length here */
215 : }
216 1293 : descriptor->chunk_size = chunk_size;
217 : }
218 :
219 1512 : if ((read_length % descriptor->chunk_size) != 0) {
220 1512 : return descriptor->chunk_size * ((read_length / descriptor->chunk_size) + 1);
221 : }
222 0 : return read_length;
223 : }
224 : /* }}} */
225 :
226 : /* {{{ php_oci_lob_read()
227 : Read specified portion of the LOB into the buffer */
228 : int php_oci_lob_read (php_oci_descriptor *descriptor, long read_length, long initial_offset, char **data, ub4 *data_len TSRMLS_DC)
229 1539 : {
230 1539 : php_oci_connection *connection = descriptor->connection;
231 1539 : ub4 length = 0;
232 1539 : int buffer_size = PHP_OCI_LOB_BUFFER_SIZE;
233 : php_oci_lob_ctx ctx;
234 : ub1 *bufp;
235 : #if defined(HAVE_OCI_LOB_READ2)
236 1539 : oraub8 bytes_read, offset = 0;
237 1539 : oraub8 requested_len = read_length; /* this is by default */
238 1539 : oraub8 chars_read = 0;
239 : #else
240 : int bytes_read, offset = 0;
241 : int requested_len = read_length; /* this is by default */
242 : #endif
243 1539 : int is_clob = 0;
244 1539 : sb4 bytes_per_char = 1;
245 :
246 1539 : *data_len = 0;
247 1539 : *data = NULL;
248 :
249 1539 : ctx.lob_len = data_len;
250 1539 : ctx.lob_data = data;
251 1539 : ctx.alloc_len = 0;
252 :
253 1539 : if (php_oci_lob_get_length(descriptor, &length TSRMLS_CC)) {
254 0 : return 1;
255 : }
256 :
257 1539 : if (length <= 0) {
258 21 : return 0;
259 : }
260 :
261 1518 : if (initial_offset > length) {
262 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset must be less than size of the LOB");
263 1 : return 1;
264 : }
265 :
266 1517 : if (read_length == -1) {
267 1078 : requested_len = length;
268 : }
269 :
270 1517 : if (requested_len > (length - initial_offset)) {
271 16 : requested_len = length - initial_offset;
272 : }
273 :
274 1517 : if (requested_len <= 0) {
275 1 : return 0;
276 : }
277 :
278 1516 : offset = initial_offset;
279 :
280 1516 : if (descriptor->type == OCI_DTYPE_FILE) {
281 4 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobFileOpen, (connection->svc, connection->err, descriptor->descriptor, OCI_FILE_READONLY));
282 :
283 4 : if (connection->errcode != OCI_SUCCESS) {
284 0 : php_oci_error(connection->err, connection->errcode TSRMLS_CC);
285 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
286 0 : return 1;
287 : }
288 : } else {
289 1512 : ub2 charset_id = 0;
290 :
291 1512 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobCharSetId, (connection->env, connection->err, descriptor->descriptor, &charset_id));
292 :
293 1512 : if (connection->errcode != OCI_SUCCESS) {
294 0 : php_oci_error(connection->err, connection->errcode TSRMLS_CC);
295 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
296 0 : return 1;
297 : }
298 :
299 1512 : if (charset_id > 0) { /* charset_id is always > 0 for [N]CLOBs */
300 1450 : is_clob = 1;
301 : }
302 : }
303 :
304 1516 : if (is_clob) {
305 : #ifdef OCI_NLS_CHARSET_MAXBYTESZ
306 1450 : PHP_OCI_CALL_RETURN(connection->errcode, OCINlsNumericInfoGet, (connection->env, connection->err, &bytes_per_char, OCI_NLS_CHARSET_MAXBYTESZ));
307 :
308 1450 : if (connection->errcode != OCI_SUCCESS) {
309 0 : php_oci_error(connection->err, connection->errcode TSRMLS_CC);
310 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
311 0 : return 1;
312 : }
313 : #else
314 : /* Oracle 8.1 doesn't define OCI_NLS_CHARSET_MAXBYTESZ, so allocate worst case size */
315 : bytes_per_char = 4;
316 : #endif
317 : } else {
318 : /* BLOBs don't have encoding, so bytes_per_char == 1 */
319 : }
320 :
321 1516 : ctx.alloc_len = (requested_len + 1) * bytes_per_char;
322 1516 : *data = ecalloc(bytes_per_char, requested_len + 1);
323 :
324 : #ifdef HAVE_OCI_LOB_READ2
325 1516 : if (is_clob) {
326 1450 : chars_read = requested_len;
327 1450 : bytes_read = 0;
328 : } else {
329 66 : chars_read = 0;
330 66 : bytes_read = requested_len;
331 : }
332 :
333 1516 : buffer_size = (requested_len < buffer_size ) ? requested_len : buffer_size; /* optimize buffer size */
334 1516 : buffer_size = php_oci_lob_calculate_buffer(descriptor, buffer_size TSRMLS_CC); /* use chunk size */
335 :
336 1516 : bufp = (ub1 *) ecalloc(1, buffer_size);
337 1516 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobRead2,
338 : (
339 : connection->svc,
340 : connection->err,
341 : descriptor->descriptor,
342 : (oraub8 *)&bytes_read, /* IN/OUT bytes toread/read */
343 : (oraub8 *)&chars_read, /* IN/OUT chars toread/read */
344 : (oraub8) offset + 1, /* offset (starts with 1) */
345 : (dvoid *) bufp,
346 : (oraub8) buffer_size, /* size of buffer */
347 : OCI_FIRST_PIECE,
348 : (dvoid *)&ctx,
349 : (OCICallbackLobRead2) php_oci_lob_callback, /* callback... */
350 : (ub2) descriptor->charset_id, /* The character set ID of the buffer data. */
351 : (ub1) descriptor->charset_form /* The character set form of the buffer data. */
352 : )
353 : );
354 :
355 1516 : efree(bufp);
356 :
357 1516 : if (is_clob) {
358 1450 : offset = descriptor->lob_current_position + chars_read;
359 : } else {
360 66 : offset = descriptor->lob_current_position + bytes_read;
361 : }
362 :
363 : #else
364 :
365 : bytes_read = requested_len;
366 : buffer_size = (requested_len < buffer_size ) ? requested_len : buffer_size; /* optimize buffer size */
367 : buffer_size = php_oci_lob_calculate_buffer(descriptor, buffer_size TSRMLS_CC); /* use chunk size */
368 :
369 : bufp = (ub1 *) ecalloc(1, buffer_size);
370 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobRead,
371 : (
372 : connection->svc,
373 : connection->err,
374 : descriptor->descriptor,
375 : &bytes_read, /* IN/OUT bytes toread/read */
376 : offset + 1, /* offset (starts with 1) */
377 : (dvoid *) bufp,
378 : (ub4) buffer_size, /* size of buffer */
379 : (dvoid *)&ctx,
380 : (OCICallbackLobRead) php_oci_lob_callback, /* callback... */
381 : (ub2) descriptor->charset_id, /* The character set ID of the buffer data. */
382 : (ub1) descriptor->charset_form /* The character set form of the buffer data. */
383 : )
384 : );
385 :
386 : efree(bufp);
387 : offset = descriptor->lob_current_position + bytes_read;
388 :
389 : #endif
390 :
391 1516 : if (connection->errcode != OCI_SUCCESS) {
392 0 : php_oci_error(connection->err, connection->errcode TSRMLS_CC);
393 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
394 0 : if (*data) {
395 0 : efree(*data);
396 0 : *data = NULL;
397 : }
398 0 : *data_len = 0;
399 0 : return 1;
400 : }
401 :
402 1516 : descriptor->lob_current_position = (int)offset;
403 :
404 1516 : if (descriptor->type == OCI_DTYPE_FILE) {
405 4 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobFileClose, (connection->svc, connection->err, descriptor->descriptor));
406 :
407 4 : if (connection->errcode != OCI_SUCCESS) {
408 0 : php_oci_error(connection->err, connection->errcode TSRMLS_CC);
409 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
410 0 : if (*data) {
411 0 : efree(*data);
412 0 : *data = NULL;
413 : }
414 0 : *data_len = 0;
415 0 : return 1;
416 : }
417 : }
418 :
419 1516 : return 0;
420 : } /* }}} */
421 :
422 : /* {{{ php_oci_lob_write()
423 : Write data to the LOB */
424 : int php_oci_lob_write (php_oci_descriptor *descriptor, ub4 offset, char *data, int data_len, ub4 *bytes_written TSRMLS_DC)
425 200 : {
426 200 : OCILobLocator *lob = (OCILobLocator *) descriptor->descriptor;
427 200 : php_oci_connection *connection = (php_oci_connection *) descriptor->connection;
428 : ub4 lob_length;
429 :
430 200 : *bytes_written = 0;
431 200 : if (php_oci_lob_get_length(descriptor, &lob_length TSRMLS_CC)) {
432 1 : return 1;
433 : }
434 :
435 199 : if (!data || data_len <= 0) {
436 7 : return 0;
437 : }
438 :
439 : if (offset < 0) {
440 : offset = 0;
441 : }
442 :
443 192 : if (offset > descriptor->lob_current_position) {
444 1 : offset = descriptor->lob_current_position;
445 : }
446 :
447 192 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobWrite,
448 : (
449 : connection->svc,
450 : connection->err,
451 : lob,
452 : (ub4 *)&data_len,
453 : (ub4) offset + 1,
454 : (dvoid *) data,
455 : (ub4) data_len,
456 : OCI_ONE_PIECE,
457 : (dvoid *)0,
458 : (OCICallbackLobWrite) 0,
459 : (ub2) descriptor->charset_id,
460 : (ub1) descriptor->charset_form
461 : )
462 : );
463 :
464 192 : if (connection->errcode) {
465 1 : php_oci_error(connection->err, connection->errcode TSRMLS_CC);
466 1 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
467 1 : *bytes_written = 0;
468 1 : return 1;
469 : }
470 191 : *bytes_written = data_len;
471 191 : descriptor->lob_current_position += data_len;
472 :
473 191 : if (descriptor->lob_current_position > descriptor->lob_size) {
474 189 : descriptor->lob_size = descriptor->lob_current_position;
475 : }
476 :
477 : /* marking buffer as used */
478 191 : if (descriptor->buffering == PHP_OCI_LOB_BUFFER_ENABLED) {
479 2 : descriptor->buffering = PHP_OCI_LOB_BUFFER_USED;
480 : }
481 :
482 191 : return 0;
483 : } /* }}} */
484 :
485 : /* {{{ php_oci_lob_set_buffering()
486 : Turn buffering off/onn for this particular LOB */
487 : int php_oci_lob_set_buffering (php_oci_descriptor *descriptor, int on_off TSRMLS_DC)
488 6 : {
489 6 : php_oci_connection *connection = descriptor->connection;
490 :
491 6 : if (!on_off && descriptor->buffering == PHP_OCI_LOB_BUFFER_DISABLED) {
492 : /* disabling when it's already off */
493 2 : return 0;
494 : }
495 :
496 4 : if (on_off && descriptor->buffering != PHP_OCI_LOB_BUFFER_DISABLED) {
497 : /* enabling when it's already on */
498 1 : return 0;
499 : }
500 :
501 3 : if (on_off) {
502 3 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobEnableBuffering, (connection->svc, connection->err, descriptor->descriptor));
503 : } else {
504 0 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobDisableBuffering, (connection->svc, connection->err, descriptor->descriptor));
505 : }
506 :
507 3 : if (connection->errcode != OCI_SUCCESS) {
508 0 : php_oci_error(connection->err, connection->errcode TSRMLS_CC);
509 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
510 0 : return 1;
511 : }
512 3 : descriptor->buffering = on_off ? PHP_OCI_LOB_BUFFER_ENABLED : PHP_OCI_LOB_BUFFER_DISABLED;
513 3 : return 0;
514 : } /* }}} */
515 :
516 : /* {{{ php_oci_lob_get_buffering()
517 : Return current buffering state for the LOB */
518 : int php_oci_lob_get_buffering (php_oci_descriptor *descriptor)
519 0 : {
520 0 : if (descriptor->buffering != PHP_OCI_LOB_BUFFER_DISABLED) {
521 0 : return 1;
522 : } else {
523 0 : return 0;
524 : }
525 : } /* }}} */
526 :
527 : /* {{{ php_oci_lob_copy()
528 : Copy one LOB (or its part) to another one */
529 : int php_oci_lob_copy (php_oci_descriptor *descriptor_dest, php_oci_descriptor *descriptor_from, long length TSRMLS_DC)
530 5 : {
531 5 : php_oci_connection *connection = descriptor_dest->connection;
532 : ub4 length_dest, length_from, copy_len;
533 :
534 5 : if (php_oci_lob_get_length(descriptor_dest, &length_dest TSRMLS_CC)) {
535 1 : return 1;
536 : }
537 :
538 4 : if (php_oci_lob_get_length(descriptor_from, &length_from TSRMLS_CC)) {
539 1 : return 1;
540 : }
541 :
542 3 : if (length == -1) {
543 1 : copy_len = length_from - descriptor_from->lob_current_position;
544 : } else {
545 2 : copy_len = length;
546 : }
547 :
548 3 : if ((int)copy_len <= 0) {
549 : /* silently fail, there is nothing to copy */
550 1 : return 1;
551 : }
552 :
553 2 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobCopy,
554 : (
555 : connection->svc,
556 : connection->err,
557 : descriptor_dest->descriptor,
558 : descriptor_from->descriptor,
559 : copy_len,
560 : descriptor_dest->lob_current_position+1,
561 : descriptor_from->lob_current_position+1
562 : )
563 : );
564 :
565 2 : if (connection->errcode != OCI_SUCCESS) {
566 0 : php_oci_error(connection->err, connection->errcode TSRMLS_CC);
567 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
568 0 : return 1;
569 : }
570 :
571 2 : return 0;
572 : } /* }}} */
573 :
574 : /* {{{ php_oci_lob_close()
575 : Close LOB */
576 : int php_oci_lob_close (php_oci_descriptor *descriptor TSRMLS_DC)
577 113 : {
578 113 : php_oci_connection *connection = descriptor->connection;
579 :
580 113 : if (descriptor->is_open) {
581 110 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobClose, (connection->svc, connection->err, descriptor->descriptor));
582 : }
583 :
584 113 : if (connection->errcode != OCI_SUCCESS) {
585 0 : php_oci_error(connection->err, connection->errcode TSRMLS_CC);
586 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
587 0 : return 1;
588 : }
589 :
590 113 : if (php_oci_temp_lob_close(descriptor TSRMLS_CC)) {
591 0 : return 1;
592 : }
593 :
594 113 : return 0;
595 : } /* }}} */
596 :
597 : /* {{{ php_oci_temp_lob_close()
598 : Close Temporary LOB */
599 : int php_oci_temp_lob_close (php_oci_descriptor *descriptor TSRMLS_DC)
600 184810 : {
601 184810 : php_oci_connection *connection = descriptor->connection;
602 : int is_temporary;
603 :
604 184810 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobIsTemporary, (connection->env,connection->err, descriptor->descriptor, &is_temporary));
605 :
606 184810 : if (connection->errcode != OCI_SUCCESS) {
607 0 : php_oci_error(connection->err, connection->errcode TSRMLS_CC);
608 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
609 0 : return 1;
610 : }
611 :
612 184810 : if (is_temporary) {
613 3115 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobFreeTemporary, (connection->svc, connection->err, descriptor->descriptor));
614 :
615 3115 : if (connection->errcode != OCI_SUCCESS) {
616 0 : php_oci_error(connection->err, connection->errcode TSRMLS_CC);
617 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
618 0 : return 1;
619 : }
620 : }
621 184810 : return 0;
622 : } /* }}} */
623 :
624 : /* {{{ php_oci_lob_flush()
625 : Flush buffers for the LOB (only if they have been used) */
626 : int php_oci_lob_flush(php_oci_descriptor *descriptor, long flush_flag TSRMLS_DC)
627 5 : {
628 5 : OCILobLocator *lob = descriptor->descriptor;
629 5 : php_oci_connection *connection = descriptor->connection;
630 :
631 5 : if (!lob) {
632 0 : return 1;
633 : }
634 :
635 5 : switch (flush_flag) {
636 : case 0:
637 : case OCI_LOB_BUFFER_FREE:
638 : /* only these two are allowed */
639 : break;
640 : default:
641 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid flag value: %ld", flush_flag);
642 1 : return 1;
643 : break;
644 : }
645 :
646 : /* do not really flush buffer, but report success
647 : * to suppress OCI error when flushing not used buffer
648 : * */
649 4 : if (descriptor->buffering != PHP_OCI_LOB_BUFFER_USED) {
650 2 : return 0;
651 : }
652 :
653 2 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobFlushBuffer, (connection->svc, connection->err, lob, flush_flag));
654 :
655 2 : if (connection->errcode != OCI_SUCCESS) {
656 0 : php_oci_error(connection->err, connection->errcode TSRMLS_CC);
657 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
658 0 : return 1;
659 : }
660 :
661 : /* marking buffer as enabled and not used */
662 2 : descriptor->buffering = PHP_OCI_LOB_BUFFER_ENABLED;
663 2 : return 0;
664 : } /* }}} */
665 :
666 : /* {{{ php_oci_lob_free()
667 : Close LOB descriptor and free associated resources */
668 : void php_oci_lob_free (php_oci_descriptor *descriptor TSRMLS_DC)
669 183673 : {
670 183673 : if (!descriptor || !descriptor->connection) {
671 0 : return;
672 : }
673 :
674 183673 : if (descriptor->connection->descriptors) {
675 : /* delete descriptor from the hash */
676 183656 : zend_hash_apply_with_argument(descriptor->connection->descriptors, php_oci_descriptor_delete_from_hash, (void *)&descriptor->id TSRMLS_CC);
677 : }
678 :
679 : /* flushing Lobs & Files with buffering enabled */
680 183673 : if ((descriptor->type == OCI_DTYPE_FILE || descriptor->type == OCI_DTYPE_LOB) && descriptor->buffering == PHP_OCI_LOB_BUFFER_USED) {
681 0 : php_oci_lob_flush(descriptor, OCI_LOB_BUFFER_FREE TSRMLS_CC);
682 : }
683 :
684 : #ifdef HAVE_OCI8_TEMP_LOB
685 183673 : if (descriptor->type == OCI_DTYPE_LOB) {
686 183663 : php_oci_temp_lob_close(descriptor TSRMLS_CC);
687 : }
688 : #endif
689 :
690 183673 : PHP_OCI_CALL(OCIDescriptorFree, (descriptor->descriptor, descriptor->type));
691 :
692 183673 : zend_list_delete(descriptor->connection->rsrc_id);
693 183673 : efree(descriptor);
694 : } /* }}} */
695 :
696 : /* {{{ php_oci_lob_import()
697 : Import LOB contents from the given file */
698 : int php_oci_lob_import (php_oci_descriptor *descriptor, char *filename TSRMLS_DC)
699 6 : {
700 : int fp;
701 : ub4 loblen;
702 6 : OCILobLocator *lob = (OCILobLocator *)descriptor->descriptor;
703 6 : php_oci_connection *connection = descriptor->connection;
704 : char buf[8192];
705 6 : ub4 offset = 1;
706 :
707 6 : if ((PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(filename TSRMLS_CC)) {
708 0 : return 1;
709 : }
710 :
711 6 : if ((fp = VCWD_OPEN(filename, O_RDONLY|O_BINARY)) == -1) {
712 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't open file %s", filename);
713 2 : return 1;
714 : }
715 :
716 12 : while ((loblen = read(fp, &buf, sizeof(buf))) > 0) {
717 4 : PHP_OCI_CALL_RETURN(connection->errcode,
718 : OCILobWrite,
719 : (
720 : connection->svc,
721 : connection->err,
722 : lob,
723 : &loblen,
724 : offset,
725 : (dvoid *) &buf,
726 : loblen,
727 : OCI_ONE_PIECE,
728 : (dvoid *)0,
729 : (OCICallbackLobWrite) 0,
730 : (ub2) descriptor->charset_id,
731 : (ub1) descriptor->charset_form
732 : )
733 : );
734 :
735 4 : if (connection->errcode != OCI_SUCCESS) {
736 0 : php_oci_error(connection->err, connection->errcode TSRMLS_CC);
737 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
738 0 : close(fp);
739 0 : return 1;
740 : }
741 4 : offset += loblen;
742 : }
743 4 : close(fp);
744 :
745 4 : return 0;
746 : } /* }}} */
747 :
748 : /* {{{ php_oci_lob_append()
749 : Append data to the end of the LOB */
750 : int php_oci_lob_append (php_oci_descriptor *descriptor_dest, php_oci_descriptor *descriptor_from TSRMLS_DC)
751 2 : {
752 2 : php_oci_connection *connection = descriptor_dest->connection;
753 2 : OCILobLocator *lob_dest = descriptor_dest->descriptor;
754 2 : OCILobLocator *lob_from = descriptor_from->descriptor;
755 : ub4 dest_len, from_len;
756 :
757 2 : if (php_oci_lob_get_length(descriptor_dest, &dest_len TSRMLS_CC)) {
758 0 : return 1;
759 : }
760 :
761 2 : if (php_oci_lob_get_length(descriptor_from, &from_len TSRMLS_CC)) {
762 0 : return 1;
763 : }
764 :
765 2 : if (from_len <= 0) {
766 0 : return 0;
767 : }
768 :
769 2 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobAppend, (connection->svc, connection->err, lob_dest, lob_from));
770 :
771 2 : if (connection->errcode != OCI_SUCCESS) {
772 0 : php_oci_error(connection->err, connection->errcode TSRMLS_CC);
773 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
774 0 : return 1;
775 : }
776 2 : return 0;
777 : } /* }}} */
778 :
779 : /* {{{ php_oci_lob_truncate()
780 : Truncate LOB to the given length */
781 : int php_oci_lob_truncate (php_oci_descriptor *descriptor, long new_lob_length TSRMLS_DC)
782 10 : {
783 10 : php_oci_connection *connection = descriptor->connection;
784 10 : OCILobLocator *lob = descriptor->descriptor;
785 : ub4 lob_length;
786 :
787 10 : if (php_oci_lob_get_length(descriptor, &lob_length TSRMLS_CC)) {
788 0 : return 1;
789 : }
790 :
791 10 : if (lob_length <= 0) {
792 1 : return 0;
793 : }
794 :
795 9 : if (new_lob_length < 0) {
796 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Size must be greater than or equal to 0");
797 0 : return 1;
798 : }
799 :
800 9 : if (new_lob_length > lob_length) {
801 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Size must be less than or equal to the current LOB size");
802 1 : return 1;
803 : }
804 :
805 8 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobTrim, (connection->svc, connection->err, lob, new_lob_length));
806 :
807 8 : if (connection->errcode != OCI_SUCCESS) {
808 0 : php_oci_error(connection->err, connection->errcode TSRMLS_CC);
809 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
810 0 : return 1;
811 : }
812 :
813 8 : descriptor->lob_size = new_lob_length;
814 8 : return 0;
815 : } /* }}} */
816 :
817 : /* {{{ php_oci_lob_erase()
818 : Erase (or fill with whitespaces, depending on LOB type) the LOB (or its part) */
819 : int php_oci_lob_erase (php_oci_descriptor *descriptor, long offset, ub4 length, ub4 *bytes_erased TSRMLS_DC)
820 5 : {
821 5 : php_oci_connection *connection = descriptor->connection;
822 5 : OCILobLocator *lob = descriptor->descriptor;
823 : ub4 lob_length;
824 :
825 5 : *bytes_erased = 0;
826 :
827 5 : if (php_oci_lob_get_length(descriptor, &lob_length TSRMLS_CC)) {
828 0 : return 1;
829 : }
830 :
831 5 : if (offset == -1) {
832 2 : offset = descriptor->lob_current_position;
833 : }
834 :
835 5 : if (length == -1) {
836 2 : length = lob_length;
837 : }
838 :
839 5 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobErase, (connection->svc, connection->err, lob, (ub4 *)&length, offset+1));
840 :
841 5 : if (connection->errcode != OCI_SUCCESS) {
842 2 : php_oci_error(connection->err, connection->errcode TSRMLS_CC);
843 2 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
844 2 : return 1;
845 : }
846 :
847 3 : *bytes_erased = length;
848 3 : return 0;
849 : } /* }}} */
850 :
851 : /* {{{ php_oci_lob_is_equal()
852 : Compare two LOB descriptors and figure out if they are pointing to the same LOB */
853 : int php_oci_lob_is_equal (php_oci_descriptor *descriptor_first, php_oci_descriptor *descriptor_second, boolean *result TSRMLS_DC)
854 1 : {
855 1 : php_oci_connection *connection = descriptor_first->connection;
856 1 : OCILobLocator *first_lob = descriptor_first->descriptor;
857 1 : OCILobLocator *second_lob = descriptor_second->descriptor;
858 :
859 1 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobIsEqual, (connection->env, first_lob, second_lob, result));
860 :
861 1 : if (connection->errcode) {
862 0 : php_oci_error(connection->err, connection->errcode TSRMLS_CC);
863 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
864 0 : return 1;
865 : }
866 1 : return 0;
867 : } /* }}} */
868 :
869 : /* {{{ php_oci_lob_write_tmp()
870 : Create temporary LOB and write data to it */
871 : int php_oci_lob_write_tmp (php_oci_descriptor *descriptor, ub1 type, char *data, int data_len TSRMLS_DC)
872 113 : {
873 113 : php_oci_connection *connection = descriptor->connection;
874 113 : OCILobLocator *lob = descriptor->descriptor;
875 113 : ub4 bytes_written = 0;
876 :
877 113 : switch (type) {
878 : case OCI_TEMP_BLOB:
879 : case OCI_TEMP_CLOB:
880 : /* only these two are allowed */
881 : break;
882 : default:
883 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid temporary lob type: %d", type);
884 1 : return 1;
885 : break;
886 : }
887 :
888 112 : if (data_len < 0) {
889 0 : return 1;
890 : }
891 :
892 112 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobCreateTemporary,
893 : (
894 : connection->svc,
895 : connection->err,
896 : lob,
897 : OCI_DEFAULT,
898 : OCI_DEFAULT,
899 : type,
900 : OCI_ATTR_NOCACHE,
901 : OCI_DURATION_SESSION
902 : )
903 : );
904 :
905 112 : if (connection->errcode) {
906 0 : php_oci_error(connection->err, connection->errcode TSRMLS_CC);
907 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
908 0 : return 1;
909 : }
910 :
911 112 : PHP_OCI_CALL_RETURN(connection->errcode, OCILobOpen, (connection->svc, connection->err, lob, OCI_LOB_READWRITE));
912 :
913 112 : if (connection->errcode) {
914 0 : php_oci_error(connection->err, connection->errcode TSRMLS_CC);
915 0 : PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
916 0 : return 1;
917 : }
918 :
919 112 : descriptor->is_open = 1;
920 :
921 112 : return php_oci_lob_write(descriptor, 0, data, data_len, &bytes_written TSRMLS_CC);
922 : } /* }}} */
923 :
924 : #endif /* HAVE_OCI8 */
925 :
926 : /*
927 : * Local variables:
928 : * tab-width: 4
929 : * c-basic-offset: 4
930 : * End:
931 : * vim600: noet sw=4 ts=4 fdm=marker
932 : * vim<600: noet sw=4 ts=4
933 : */
|