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