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 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 */
  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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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) */
 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 */
 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 */
 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  */

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