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