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