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