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