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