root/ext/oci8/oci8_lob.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_oci_lob_create
  2. php_oci_lob_get_length
  3. php_oci_lob_callback
  4. php_oci_lob_calculate_buffer
  5. php_oci_lob_read
  6. php_oci_lob_write
  7. php_oci_lob_set_buffering
  8. php_oci_lob_get_buffering
  9. php_oci_lob_copy
  10. php_oci_lob_close
  11. php_oci_temp_lob_close
  12. php_oci_lob_flush
  13. php_oci_lob_free
  14. php_oci_lob_import
  15. php_oci_lob_append
  16. php_oci_lob_truncate
  17. php_oci_lob_erase
  18. php_oci_lob_is_equal
  19. php_oci_lob_write_tmp

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   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 */
  54 php_oci_descriptor *php_oci_lob_create (php_oci_connection *connection, zend_long type)
  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, E_WARNING, "Unknown descriptor type %pd", type);
  67                         return NULL;
  68                         break;
  69         }
  70 
  71         descriptor = ecalloc(1, sizeof(php_oci_descriptor));
  72         descriptor->type = (ub4) type;
  73         descriptor->connection = connection;
  74         ++GC_REFCOUNT(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);
  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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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) */
 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: %pd", 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 */
 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 */
 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_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 3) || (PHP_MAJOR_VERSION > 5)
 720         /* Safe mode has been removed in PHP 5.4 */
 721         if (php_check_open_basedir(filename)) {
 722 #else
 723         if ((PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(filename)) {
 724 #endif
 725                 return 1;
 726         }
 727         
 728         if ((fp = VCWD_OPEN(filename, O_RDONLY|O_BINARY)) == -1) {
 729                 php_error_docref(NULL, E_WARNING, "Can't open file %s", filename);
 730                 return 1;
 731         }
 732 
 733         while ((loblen = read(fp, &buf, sizeof(buf))) > 0) {    
 734                 PHP_OCI_CALL_RETURN(errstatus,
 735                                 OCILobWrite,
 736                                 (
 737                                         connection->svc,
 738                                         connection->err,
 739                                         lob,
 740                                         &loblen,
 741                                         offset,
 742                                         (dvoid *) &buf,
 743                                         loblen,
 744                                         OCI_ONE_PIECE,
 745                                         (dvoid *)0,
 746                                         (OCICallbackLobWrite) 0,
 747                                         (ub2) descriptor->charset_id,
 748                                         (ub1) descriptor->charset_form
 749                                 )
 750                 );
 751 
 752                 if (errstatus != OCI_SUCCESS) {
 753                         connection->errcode = php_oci_error(connection->err, errstatus);
 754                         PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
 755                         close(fp);
 756                         return 1;
 757                 } else {
 758                         connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
 759                 }
 760                 offset += loblen;
 761         }
 762         close(fp);
 763         
 764         return 0;
 765 }
 766         /* }}} */
 767 
 768 /* {{{ php_oci_lob_append()
 769  Append data to the end of the LOB */
 770 int php_oci_lob_append (php_oci_descriptor *descriptor_dest, php_oci_descriptor *descriptor_from)
 771 {
 772         php_oci_connection *connection = descriptor_dest->connection;
 773         OCILobLocator *lob_dest = descriptor_dest->descriptor;
 774         OCILobLocator *lob_from = descriptor_from->descriptor;
 775         ub4 dest_len, from_len;
 776         sword errstatus;
 777 
 778         if (php_oci_lob_get_length(descriptor_dest, &dest_len)) {
 779                 return 1;
 780         }
 781         
 782         if (php_oci_lob_get_length(descriptor_from, &from_len)) {
 783                 return 1;
 784         }
 785 
 786         if (from_len <= 0) {
 787                 return 0;
 788         }
 789 
 790         PHP_OCI_CALL_RETURN(errstatus, OCILobAppend, (connection->svc, connection->err, lob_dest, lob_from));
 791 
 792         if (errstatus != OCI_SUCCESS) {
 793                 connection->errcode = php_oci_error(connection->err, errstatus);
 794                 PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
 795                 return 1;
 796         }
 797         connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
 798         return 0;
 799 }
 800 /* }}} */
 801 
 802 /* {{{ php_oci_lob_truncate()
 803  Truncate LOB to the given length */
 804 int php_oci_lob_truncate (php_oci_descriptor *descriptor, zend_long new_lob_length)
 805 {
 806         php_oci_connection *connection = descriptor->connection;
 807         OCILobLocator *lob = descriptor->descriptor;
 808         ub4 lob_length;
 809         sword errstatus;
 810         
 811         if (php_oci_lob_get_length(descriptor, &lob_length)) {
 812                 return 1;
 813         }
 814         
 815         if (lob_length <= 0) {
 816                 return 0;
 817         }
 818 
 819         if (new_lob_length < 0) {
 820                 php_error_docref(NULL, E_WARNING, "Size must be greater than or equal to 0");
 821                 return 1;
 822         }
 823 
 824         if (new_lob_length > lob_length) {
 825                 php_error_docref(NULL, E_WARNING, "Size must be less than or equal to the current LOB size");
 826                 return 1;
 827         }
 828         
 829         PHP_OCI_CALL_RETURN(errstatus, OCILobTrim, (connection->svc, connection->err, lob, (ub4) new_lob_length));
 830 
 831         if (errstatus != OCI_SUCCESS) {
 832                 connection->errcode = php_oci_error(connection->err, errstatus);
 833                 PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
 834                 return 1;
 835         }
 836         
 837         descriptor->lob_size = (ub4) new_lob_length;
 838         connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
 839 
 840         return 0;
 841 }
 842 /* }}} */
 843 
 844 /* {{{ php_oci_lob_erase()
 845  Erase (or fill with whitespaces, depending on LOB type) the LOB (or its part) */
 846 int php_oci_lob_erase (php_oci_descriptor *descriptor, zend_long offset, ub4 length, ub4 *bytes_erased)
 847 {
 848         php_oci_connection *connection = descriptor->connection;
 849         OCILobLocator *lob = descriptor->descriptor;
 850         ub4 lob_length;
 851         sword errstatus;
 852 
 853         *bytes_erased = 0;
 854         
 855         if (php_oci_lob_get_length(descriptor, &lob_length)) {
 856                 return 1;
 857         }
 858         
 859         if (offset == -1) {
 860                 offset = descriptor->lob_current_position;
 861         }
 862 
 863         if (length == -1) {
 864                 length = lob_length;
 865         }
 866         
 867         PHP_OCI_CALL_RETURN(errstatus, OCILobErase, (connection->svc, connection->err, lob, (ub4 *)&length, (ub4) offset+1));
 868 
 869         if (errstatus != OCI_SUCCESS) {
 870                 connection->errcode = php_oci_error(connection->err, errstatus);
 871                 PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
 872                 return 1;
 873         }
 874         
 875         *bytes_erased = length;
 876         connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
 877         return 0;
 878 }
 879 /* }}} */
 880 
 881 /* {{{ php_oci_lob_is_equal()
 882  Compare two LOB descriptors and figure out if they are pointing to the same LOB */
 883 int php_oci_lob_is_equal (php_oci_descriptor *descriptor_first, php_oci_descriptor *descriptor_second, boolean *result)
 884 {
 885         php_oci_connection *connection = descriptor_first->connection;
 886         OCILobLocator *first_lob   = descriptor_first->descriptor;
 887         OCILobLocator *second_lob  = descriptor_second->descriptor;
 888         sword errstatus;
 889 
 890         PHP_OCI_CALL_RETURN(errstatus, OCILobIsEqual, (connection->env, first_lob, second_lob, result));
 891 
 892         if (errstatus) {
 893                 connection->errcode = php_oci_error(connection->err, errstatus);
 894                 PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
 895                 return 1;
 896         }
 897         connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
 898         return 0;
 899 }
 900 /* }}} */
 901 
 902 /* {{{ php_oci_lob_write_tmp()
 903  Create temporary LOB and write data to it */
 904 int php_oci_lob_write_tmp (php_oci_descriptor *descriptor, zend_long type, char *data, int data_len)
 905 {
 906         php_oci_connection *connection = descriptor->connection;
 907         OCILobLocator *lob                 = descriptor->descriptor;
 908         ub4 bytes_written = 0;
 909         sword errstatus;
 910         
 911         switch (type) {
 912                 case OCI_TEMP_BLOB:
 913                 case OCI_TEMP_CLOB:
 914                         /* only these two are allowed */
 915                         break;
 916                 default:
 917                         php_error_docref(NULL, E_WARNING, "Invalid temporary lob type: %pd", type);
 918                         return 1;
 919                         break;
 920         }
 921 
 922         if (data_len < 0) {
 923                 return 1;
 924         }
 925 
 926         PHP_OCI_CALL_RETURN(errstatus, OCILobCreateTemporary,
 927                         (
 928                          connection->svc,
 929                          connection->err,
 930                          lob,
 931                          OCI_DEFAULT,
 932                          OCI_DEFAULT,
 933                          (ub1)type,
 934                          OCI_ATTR_NOCACHE,
 935                          OCI_DURATION_SESSION
 936                         )
 937         );
 938 
 939         if (errstatus) {
 940                 connection->errcode = php_oci_error(connection->err, errstatus);
 941                 PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
 942                 return 1;
 943         }
 944 
 945         PHP_OCI_CALL_RETURN(errstatus, OCILobOpen, (connection->svc, connection->err, lob, OCI_LOB_READWRITE));
 946 
 947         if (errstatus) {
 948                 connection->errcode = php_oci_error(connection->err, errstatus);
 949                 PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
 950                 return 1;
 951         }
 952 
 953         descriptor->is_open = 1;
 954         connection->errcode = 0; /* retain backwards compat with OCI8 1.4 */
 955 
 956         return php_oci_lob_write(descriptor, 0, data, data_len, &bytes_written);
 957 }
 958 /* }}} */
 959 
 960 #endif /* HAVE_OCI8 */
 961 
 962 /*
 963  * Local variables:
 964  * tab-width: 4
 965  * c-basic-offset: 4
 966  * End:
 967  * vim600: noet sw=4 ts=4 fdm=marker
 968  * vim<600: noet sw=4 ts=4
 969  */

/* [<][>][^][v][top][bottom][index][help] */