Back to index

php5  5.3.10
oci8_lob.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Stig Sæther Bakken <ssb@php.net>                            |
00016    |          Thies C. Arntzen <thies@thieso.net>                         |
00017    |                                                                      |
00018    | Collection support by Andy Sautins <asautins@veripost.net>           |
00019    | Temporary LOB support by David Benson <dbenson@mancala.com>          |
00020    | ZTS per process OCIPLogon by Harald Radi <harald.radi@nme.at>        |
00021    |                                                                      |
00022    | Redesigned by: Antony Dovgal <antony@zend.com>                       |
00023    |                Andi Gutmans <andi@zend.com>                          |
00024    |                Wez Furlong <wez@omniti.com>                          |
00025    +----------------------------------------------------------------------+
00026 */
00027 
00028 /* $Id: oci8_lob.c 321634 2012-01-01 13:15:04Z felipe $ */
00029 
00030 
00031 
00032 #ifdef HAVE_CONFIG_H
00033 #include "config.h"
00034 #endif
00035 
00036 #include "php.h"
00037 #include "ext/standard/info.h"
00038 #include "php_ini.h"
00039 
00040 #if HAVE_OCI8
00041 
00042 #include "php_oci8.h"
00043 #include "php_oci8_int.h"
00044 
00045 /* for import/export functions */
00046 #include <fcntl.h>
00047 
00048 #ifndef O_BINARY
00049 #define O_BINARY 0
00050 #endif
00051 
00052 /* {{{ php_oci_lob_create()
00053  Create LOB descriptor and allocate all the resources needed */
00054 php_oci_descriptor *php_oci_lob_create (php_oci_connection *connection, long type TSRMLS_DC)
00055 {
00056        php_oci_descriptor *descriptor;
00057 
00058        switch (type) {
00059               case OCI_DTYPE_FILE:
00060               case OCI_DTYPE_LOB:
00061               case OCI_DTYPE_ROWID:
00062                      /* these three are allowed */
00063                      break;
00064               default:
00065                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown descriptor type %ld", type);
00066                      return NULL;
00067                      break;
00068        }
00069 
00070        descriptor = ecalloc(1, sizeof(php_oci_descriptor));
00071        descriptor->type = type;
00072        descriptor->connection = connection;
00073        zend_list_addref(descriptor->connection->rsrc_id);
00074 
00075        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIDescriptorAlloc, (connection->env, (dvoid*)&(descriptor->descriptor), descriptor->type, (size_t) 0, (dvoid **) 0));
00076 
00077        if (OCI_G(errcode) != OCI_SUCCESS) {
00078               OCI_G(errcode) = php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
00079               PHP_OCI_HANDLE_ERROR(connection, OCI_G(errcode));
00080               efree(descriptor);
00081               return NULL;
00082        }
00083 
00084        PHP_OCI_REGISTER_RESOURCE(descriptor, le_descriptor);
00085        
00086        descriptor->lob_current_position = 0;
00087        descriptor->lob_size = -1;                       /* we should set it to -1 to know, that it's just not initialized */
00088        descriptor->buffering = PHP_OCI_LOB_BUFFER_DISABLED;                         /* buffering is off by default */
00089        descriptor->charset_form = SQLCS_IMPLICIT;       /* default value */
00090        descriptor->charset_id = connection->charset;
00091        descriptor->is_open = 0;
00092 
00093        if (descriptor->type == OCI_DTYPE_LOB || descriptor->type == OCI_DTYPE_FILE) {
00094               /* add Lobs & Files to hash. we'll flush them at the end */
00095               if (!connection->descriptors) {
00096                      ALLOC_HASHTABLE(connection->descriptors);
00097                      zend_hash_init(connection->descriptors, 0, NULL, php_oci_descriptor_flush_hash_dtor, 0);
00098                      connection->descriptor_count = 0;
00099               }
00100               
00101               descriptor->index = (connection->descriptor_count)++;
00102               if (connection->descriptor_count == LONG_MAX) {
00103                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Internal descriptor counter has reached limit");
00104                      php_oci_connection_descriptors_free(connection TSRMLS_CC);
00105                      return NULL;
00106               }
00107 
00108               zend_hash_index_update(connection->descriptors,descriptor->index,&descriptor,sizeof(php_oci_descriptor *),NULL);
00109        }
00110        return descriptor;
00111 
00112 } /* }}} */
00113 
00114 /* {{{ php_oci_lob_get_length()
00115  Get length of the LOB. The length is cached so we don't need to ask Oracle every time */
00116 int php_oci_lob_get_length (php_oci_descriptor *descriptor, ub4 *length TSRMLS_DC)
00117 {
00118        php_oci_connection *connection = descriptor->connection;
00119 
00120        *length = 0;
00121        
00122        if (descriptor->lob_size >= 0) {
00123               *length = descriptor->lob_size;
00124               return 0;
00125        } else {
00126               if (descriptor->type == OCI_DTYPE_FILE) {
00127                      PHP_OCI_CALL_RETURN(connection->errcode, OCILobFileOpen, (connection->svc, connection->err, descriptor->descriptor, OCI_FILE_READONLY));
00128                      if (connection->errcode != OCI_SUCCESS) {
00129                             connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00130                             PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00131                             return 1;
00132                      }
00133               }
00134               
00135               PHP_OCI_CALL_RETURN(connection->errcode, OCILobGetLength, (connection->svc, connection->err, descriptor->descriptor, (ub4 *)length));
00136 
00137               if (connection->errcode != OCI_SUCCESS) {
00138                      connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00139                      PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00140                      return 1;
00141               }
00142 
00143               descriptor->lob_size = *length;
00144 
00145               if (descriptor->type == OCI_DTYPE_FILE) {
00146                      PHP_OCI_CALL_RETURN(connection->errcode, OCILobFileClose, (connection->svc, connection->err, descriptor->descriptor));
00147 
00148                      if (connection->errcode != OCI_SUCCESS) {
00149                             connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00150                             PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00151                             return 1;
00152                      }
00153               }
00154        }
00155        return 0;     
00156 } /* }}} */
00157 
00158 /* {{{ php_oci_lob_callback()
00159    Append LOB portion to a memory buffer */
00160 #if defined(HAVE_OCI_LOB_READ2)
00161 sb4 php_oci_lob_callback (dvoid *ctxp, CONST dvoid *bufxp, oraub8 len, ub1 piece, dvoid **changed_bufpp, oraub8 *changed_lenp)
00162 #else
00163 sb4 php_oci_lob_callback (dvoid *ctxp, CONST dvoid *bufxp, ub4 len, ub1 piece)
00164 #endif
00165 {
00166        ub4 lenp = (ub4) len;
00167        php_oci_lob_ctx *ctx = (php_oci_lob_ctx *)ctxp;
00168 
00169        switch (piece)
00170        {
00171               case OCI_LAST_PIECE:
00172                      if ((*(ctx->lob_len) + lenp) > (ctx->alloc_len)) {
00173                             /* this should not happen ever */
00174                             *(ctx->lob_data) = NULL;
00175                             *(ctx->lob_len) = 0;
00176                             return OCI_ERROR;
00177                      }
00178                      memcpy(*(ctx->lob_data) + *(ctx->lob_len), bufxp, (size_t) lenp);
00179                      *(ctx->lob_len) += lenp;
00180                      *(*(ctx->lob_data) + *(ctx->lob_len)) = 0x00;
00181                      return OCI_CONTINUE;
00182 
00183               case OCI_FIRST_PIECE:
00184               case OCI_NEXT_PIECE:
00185                      if ((*(ctx->lob_len) + lenp) > ctx->alloc_len) {
00186                             /* this should not happen ever */
00187                             *(ctx->lob_data) = NULL;
00188                             *(ctx->lob_len) = 0;
00189                             return OCI_ERROR;
00190                      }
00191                      memcpy(*(ctx->lob_data) + *(ctx->lob_len), bufxp, (size_t) lenp);
00192                      *(ctx->lob_len) += lenp;
00193                      return OCI_CONTINUE;
00194 
00195               default: {
00196                      TSRMLS_FETCH();
00197                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unexpected LOB piece id received (value:%d)", piece);
00198                      *(ctx->lob_data) = NULL;
00199                      *(ctx->lob_len) = 0;
00200                      return OCI_ERROR;
00201               }
00202        }
00203 }
00204 /* }}} */
00205 
00206 /* {{{ php_oci_lob_calculate_buffer() */
00207 static inline int php_oci_lob_calculate_buffer(php_oci_descriptor *descriptor, long read_length TSRMLS_DC)
00208 {
00209        php_oci_connection *connection = descriptor->connection;
00210        ub4 chunk_size;
00211 
00212        if (descriptor->type == OCI_DTYPE_FILE) {
00213               return read_length;
00214        }
00215 
00216        if (!descriptor->chunk_size) {
00217               PHP_OCI_CALL_RETURN(connection->errcode, OCILobGetChunkSize, (connection->svc, connection->err, descriptor->descriptor, &chunk_size));
00218 
00219               if (connection->errcode != OCI_SUCCESS) {
00220                      connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00221                      PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00222                      return read_length; /* we have to return original length here */
00223               }
00224               descriptor->chunk_size = chunk_size;
00225        }
00226        
00227        if ((read_length % descriptor->chunk_size) != 0) {
00228               return descriptor->chunk_size * ((read_length / descriptor->chunk_size) + 1);
00229        }
00230        return read_length;
00231 }
00232 /* }}} */
00233 
00234 /* {{{ php_oci_lob_read()
00235  Read specified portion of the LOB into the buffer */
00236 int php_oci_lob_read (php_oci_descriptor *descriptor, long read_length, long initial_offset, char **data, ub4 *data_len TSRMLS_DC)
00237 {
00238        php_oci_connection *connection = descriptor->connection;
00239        ub4 length = 0;
00240        int buffer_size = PHP_OCI_LOB_BUFFER_SIZE;
00241        php_oci_lob_ctx ctx;
00242        ub1 *bufp;
00243 #if defined(HAVE_OCI_LOB_READ2)
00244        oraub8 bytes_read, offset = 0;
00245        oraub8 requested_len = read_length; /* this is by default */
00246        oraub8 chars_read = 0;
00247 #else
00248        int bytes_read, offset = 0;
00249        int requested_len = read_length; /* this is by default */
00250 #endif
00251        int is_clob = 0;
00252        sb4 bytes_per_char = 1;
00253 
00254        *data_len = 0;
00255        *data = NULL;
00256 
00257        ctx.lob_len = data_len;
00258        ctx.lob_data = data;
00259        ctx.alloc_len = 0;
00260 
00261        if (php_oci_lob_get_length(descriptor, &length TSRMLS_CC)) {
00262               return 1;
00263        }
00264 
00265        if (length <= 0) {
00266               return 0;
00267        }
00268        
00269        if (initial_offset > length) {
00270               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset must be less than size of the LOB");
00271               return 1;
00272        }
00273               
00274        if (read_length == -1) {
00275               requested_len = length;
00276        }
00277        
00278        if (requested_len > (length - initial_offset)) {
00279               requested_len = length - initial_offset;
00280        }
00281        
00282        if (requested_len <= 0) {
00283               return 0;
00284        }
00285        
00286        offset = initial_offset;
00287 
00288        if (descriptor->type == OCI_DTYPE_FILE) {
00289               PHP_OCI_CALL_RETURN(connection->errcode, OCILobFileOpen, (connection->svc, connection->err, descriptor->descriptor, OCI_FILE_READONLY));
00290 
00291               if (connection->errcode != OCI_SUCCESS) {
00292                      connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00293                      PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00294                      return 1;
00295               }
00296        } else {
00297               ub2 charset_id = 0;
00298 
00299               PHP_OCI_CALL_RETURN(connection->errcode, OCILobCharSetId, (connection->env, connection->err, descriptor->descriptor, &charset_id));
00300 
00301               if (connection->errcode != OCI_SUCCESS) {
00302                      connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00303                      PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00304                      return 1;
00305               }
00306 
00307               if (charset_id > 0) { /* charset_id is always > 0 for [N]CLOBs */
00308                      is_clob = 1;
00309               }
00310        }
00311 
00312        if (is_clob) {
00313               PHP_OCI_CALL_RETURN(connection->errcode, OCINlsNumericInfoGet, (connection->env, connection->err, &bytes_per_char, OCI_NLS_CHARSET_MAXBYTESZ));
00314 
00315               if (connection->errcode != OCI_SUCCESS) {
00316                      connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00317                      PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00318                      return 1;
00319               }
00320        } else {
00321               /* BLOBs don't have encoding, so bytes_per_char == 1 */
00322        }
00323 
00324        ctx.alloc_len = (requested_len + 1) * bytes_per_char;
00325        *data = ecalloc(bytes_per_char, requested_len + 1);
00326 
00327 #ifdef HAVE_OCI_LOB_READ2
00328        if (is_clob) {
00329               chars_read = requested_len;
00330               bytes_read = 0;
00331        } else {
00332               chars_read = 0;
00333               bytes_read = requested_len;
00334        }
00335 
00336        buffer_size = (requested_len < buffer_size ) ? requested_len : buffer_size;         /* optimize buffer size */
00337        buffer_size = php_oci_lob_calculate_buffer(descriptor, buffer_size TSRMLS_CC);      /* use chunk size */
00338 
00339        bufp = (ub1 *) ecalloc(1, buffer_size);
00340        PHP_OCI_CALL_RETURN(connection->errcode, OCILobRead2,
00341               (
00342                      connection->svc,
00343                      connection->err,
00344                      descriptor->descriptor,
00345                      (oraub8 *)&bytes_read,                                                /* IN/OUT bytes toread/read */
00346                      (oraub8 *)&chars_read,                                                /* IN/OUT chars toread/read */
00347                      (oraub8) offset + 1,                                           /* offset (starts with 1) */
00348                      (dvoid *) bufp,
00349                      (oraub8) buffer_size,                                                 /* size of buffer */
00350                      OCI_FIRST_PIECE,
00351                      (dvoid *)&ctx,
00352                      (OCICallbackLobRead2) php_oci_lob_callback,                           /* callback... */
00353                      (ub2) descriptor->charset_id,                       /* The character set ID of the buffer data. */
00354                      (ub1) descriptor->charset_form                                   /* The character set form of the buffer data. */
00355               )
00356        );
00357        
00358        efree(bufp);
00359        
00360        if (is_clob) {
00361               offset = descriptor->lob_current_position + chars_read;
00362        } else {
00363               offset = descriptor->lob_current_position + bytes_read;
00364        }
00365 
00366 #else
00367 
00368        bytes_read = requested_len;
00369        buffer_size = (requested_len < buffer_size ) ? requested_len : buffer_size;         /* optimize buffer size */
00370        buffer_size = php_oci_lob_calculate_buffer(descriptor, buffer_size TSRMLS_CC);      /* use chunk size */
00371 
00372        bufp = (ub1 *) ecalloc(1, buffer_size);
00373        PHP_OCI_CALL_RETURN(connection->errcode, OCILobRead,
00374               (
00375                       connection->svc,
00376                       connection->err,
00377                       descriptor->descriptor,
00378                       &bytes_read,                                                   /* IN/OUT bytes toread/read */
00379                       offset + 1,                                             /* offset (starts with 1) */
00380                       (dvoid *) bufp,
00381                       (ub4) buffer_size,                                             /* size of buffer */
00382                       (dvoid *)&ctx,
00383                       (OCICallbackLobRead) php_oci_lob_callback,                            /* callback... */
00384                       (ub2) descriptor->charset_id,                          /* The character set ID of the buffer data. */
00385                       (ub1) descriptor->charset_form                                   /* The character set form of the buffer data. */
00386               )
00387        );
00388        
00389        efree(bufp);
00390        offset = descriptor->lob_current_position + bytes_read;
00391 
00392 #endif
00393        
00394        if (connection->errcode != OCI_SUCCESS) {
00395               connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00396               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00397               if (*data) {
00398                      efree(*data);
00399                      *data = NULL;
00400               }
00401               *data_len = 0;
00402               return 1;
00403        }
00404        
00405        descriptor->lob_current_position = (int)offset;
00406 
00407        if (descriptor->type == OCI_DTYPE_FILE) {
00408               PHP_OCI_CALL_RETURN(connection->errcode, OCILobFileClose, (connection->svc, connection->err, descriptor->descriptor));
00409 
00410               if (connection->errcode != OCI_SUCCESS) {
00411                      connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00412                      PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00413                      if (*data) {
00414                             efree(*data);
00415                             *data = NULL;
00416                      }
00417                      *data_len = 0;
00418                      return 1;
00419               }
00420        }
00421 
00422        return 0;
00423 } /* }}} */
00424 
00425 /* {{{ php_oci_lob_write()
00426  Write data to the LOB */
00427 int php_oci_lob_write (php_oci_descriptor *descriptor, ub4 offset, char *data, int data_len, ub4 *bytes_written TSRMLS_DC)
00428 {
00429        OCILobLocator *lob             = (OCILobLocator *) descriptor->descriptor;
00430        php_oci_connection *connection = (php_oci_connection *) descriptor->connection;
00431        ub4 lob_length;
00432        
00433        *bytes_written = 0;
00434        if (php_oci_lob_get_length(descriptor, &lob_length TSRMLS_CC)) {
00435               return 1;
00436        }
00437        
00438        if (!data || data_len <= 0) {
00439               return 0;
00440        }
00441        
00442        if (offset < 0) {
00443               offset = 0;
00444        }
00445        
00446        if (offset > descriptor->lob_current_position) {
00447               offset = descriptor->lob_current_position;
00448        }
00449        
00450        PHP_OCI_CALL_RETURN(connection->errcode, OCILobWrite,
00451                      (
00452                             connection->svc,
00453                             connection->err,
00454                             lob,
00455                             (ub4 *)&data_len,
00456                             (ub4) offset + 1,
00457                             (dvoid *) data,
00458                             (ub4) data_len,
00459                             OCI_ONE_PIECE,
00460                             (dvoid *)0,
00461                             (OCICallbackLobWrite) 0,
00462                             (ub2) descriptor->charset_id,
00463                             (ub1) descriptor->charset_form
00464                      )
00465               );
00466 
00467        if (connection->errcode) {
00468               connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00469               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00470               *bytes_written = 0;
00471               return 1;
00472        }
00473        *bytes_written = data_len;
00474        descriptor->lob_current_position += data_len;
00475        
00476        if (descriptor->lob_current_position > descriptor->lob_size) {
00477               descriptor->lob_size = descriptor->lob_current_position;
00478        }
00479        
00480        /* marking buffer as used */
00481        if (descriptor->buffering == PHP_OCI_LOB_BUFFER_ENABLED) {
00482               descriptor->buffering = PHP_OCI_LOB_BUFFER_USED;
00483        }
00484        
00485        return 0;
00486 } /* }}} */
00487 
00488 /* {{{ php_oci_lob_set_buffering()
00489  Turn buffering off/onn for this particular LOB */
00490 int php_oci_lob_set_buffering (php_oci_descriptor *descriptor, int on_off TSRMLS_DC)
00491 {
00492        php_oci_connection *connection = descriptor->connection;
00493 
00494        if (!on_off && descriptor->buffering == PHP_OCI_LOB_BUFFER_DISABLED) {
00495               /* disabling when it's already off */
00496               return 0;
00497        }
00498        
00499        if (on_off && descriptor->buffering != PHP_OCI_LOB_BUFFER_DISABLED) {
00500               /* enabling when it's already on */
00501               return 0;
00502        }
00503        
00504        if (on_off) {
00505               PHP_OCI_CALL_RETURN(connection->errcode, OCILobEnableBuffering, (connection->svc, connection->err, descriptor->descriptor));
00506        } else {
00507               PHP_OCI_CALL_RETURN(connection->errcode, OCILobDisableBuffering, (connection->svc, connection->err, descriptor->descriptor));
00508        }
00509 
00510        if (connection->errcode != OCI_SUCCESS) {
00511               connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00512               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00513               return 1;
00514        }
00515        descriptor->buffering = on_off ? PHP_OCI_LOB_BUFFER_ENABLED : PHP_OCI_LOB_BUFFER_DISABLED;
00516        return 0;
00517 } /* }}} */
00518 
00519 /* {{{ php_oci_lob_get_buffering()
00520  Return current buffering state for the LOB */
00521 int php_oci_lob_get_buffering (php_oci_descriptor *descriptor)
00522 {
00523        if (descriptor->buffering != PHP_OCI_LOB_BUFFER_DISABLED) {
00524               return 1;
00525        } else {
00526               return 0;
00527        }
00528 } /* }}} */
00529 
00530 /* {{{ php_oci_lob_copy()
00531  Copy one LOB (or its part) to another one */
00532 int php_oci_lob_copy (php_oci_descriptor *descriptor_dest, php_oci_descriptor *descriptor_from, long length TSRMLS_DC)
00533 {
00534        php_oci_connection *connection = descriptor_dest->connection;
00535        ub4 length_dest, length_from, copy_len;
00536        
00537        if (php_oci_lob_get_length(descriptor_dest, &length_dest TSRMLS_CC)) {
00538               return 1;
00539        }
00540        
00541        if (php_oci_lob_get_length(descriptor_from, &length_from TSRMLS_CC)) {
00542               return 1;
00543        }
00544 
00545        if (length == -1) {
00546               copy_len = length_from - descriptor_from->lob_current_position;
00547        } else {
00548               copy_len = length;
00549        }
00550 
00551        if ((int)copy_len <= 0) {
00552               /* silently fail, there is nothing to copy */
00553               return 1;
00554        }
00555 
00556        PHP_OCI_CALL_RETURN(connection->errcode, OCILobCopy,
00557                      (
00558                       connection->svc,
00559                       connection->err,
00560                       descriptor_dest->descriptor,
00561                       descriptor_from->descriptor,
00562                       copy_len,
00563                       descriptor_dest->lob_current_position+1,
00564                       descriptor_from->lob_current_position+1
00565                      )
00566        );
00567 
00568        if (connection->errcode != OCI_SUCCESS) {
00569               connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00570               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00571               return 1;
00572        }
00573        
00574        return 0;
00575 } /* }}} */
00576 
00577 /* {{{ php_oci_lob_close()
00578  Close LOB */
00579 int php_oci_lob_close (php_oci_descriptor *descriptor TSRMLS_DC)
00580 {
00581        php_oci_connection *connection = descriptor->connection;
00582        
00583        if (descriptor->is_open) {
00584               PHP_OCI_CALL_RETURN(connection->errcode, OCILobClose, (connection->svc, connection->err, descriptor->descriptor));
00585        }
00586 
00587        if (connection->errcode != OCI_SUCCESS) {
00588               connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00589               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00590               return 1;
00591        }
00592 
00593        if (php_oci_temp_lob_close(descriptor TSRMLS_CC)) {
00594               return 1;
00595        }
00596        
00597        return 0;
00598 } /* }}} */
00599 
00600 /* {{{ php_oci_temp_lob_close()
00601    Close Temporary LOB */
00602 int php_oci_temp_lob_close (php_oci_descriptor *descriptor TSRMLS_DC)
00603 {
00604        php_oci_connection *connection = descriptor->connection;
00605        int is_temporary;
00606 
00607        PHP_OCI_CALL_RETURN(connection->errcode, OCILobIsTemporary, (connection->env,connection->err, descriptor->descriptor, &is_temporary));
00608        
00609        if (connection->errcode != OCI_SUCCESS) {
00610               connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00611               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00612               return 1;
00613        }
00614        
00615        if (is_temporary) {
00616               PHP_OCI_CALL_RETURN(connection->errcode, OCILobFreeTemporary, (connection->svc, connection->err, descriptor->descriptor));
00617               
00618               if (connection->errcode != OCI_SUCCESS) {
00619                      connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00620                      PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00621                      return 1;
00622               }
00623        }
00624        return 0;
00625 } /* }}} */
00626 
00627 
00628 /* {{{ php_oci_lob_flush()
00629  Flush buffers for the LOB (only if they have been used) */
00630 int php_oci_lob_flush(php_oci_descriptor *descriptor, long flush_flag TSRMLS_DC)
00631 {
00632        OCILobLocator *lob = descriptor->descriptor;
00633        php_oci_connection *connection = descriptor->connection;
00634        
00635        if (!lob) {
00636               return 1;
00637        }
00638 
00639        switch (flush_flag) {
00640               case 0:
00641               case OCI_LOB_BUFFER_FREE:
00642                      /* only these two are allowed */
00643                      break;
00644               default:
00645                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid flag value: %ld", flush_flag);
00646                      return 1;
00647                      break;
00648        }
00649        
00650        /* do not really flush buffer, but report success
00651         * to suppress OCI error when flushing not used buffer
00652         * */
00653        if (descriptor->buffering != PHP_OCI_LOB_BUFFER_USED) {
00654               return 0;
00655        }
00656 
00657        PHP_OCI_CALL_RETURN(connection->errcode, OCILobFlushBuffer, (connection->svc, connection->err, lob, flush_flag));
00658 
00659        if (connection->errcode != OCI_SUCCESS) {
00660               connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00661               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00662               return 1;
00663        }
00664 
00665        /* marking buffer as enabled and not used */
00666        descriptor->buffering = PHP_OCI_LOB_BUFFER_ENABLED;
00667        return 0;
00668 } /* }}} */
00669 
00670 /* {{{ php_oci_lob_free()
00671  Close LOB descriptor and free associated resources */
00672 void php_oci_lob_free (php_oci_descriptor *descriptor TSRMLS_DC)
00673 {
00674        if (!descriptor || !descriptor->connection) {
00675               return;
00676        }
00677 
00678        if (descriptor->connection->descriptors) {
00679               /* delete descriptor from the hash */
00680               zend_hash_index_del(descriptor->connection->descriptors, descriptor->index);
00681               if (zend_hash_num_elements(descriptor->connection->descriptors) == 0) {
00682                      descriptor->connection->descriptor_count = 0;
00683               } else {
00684                      if (descriptor->index + 1 == descriptor->connection->descriptor_count) {
00685                             /* If the descriptor being freed is the end-most one
00686                              * allocated, then the descriptor_count is reduced so
00687                              * a future descriptor can reuse the hash table index.
00688                              * This can prevent the hash index range increasing in
00689                              * the common case that each descriptor is
00690                              * allocated/used/freed before another descriptor is
00691                              * needed.  However it is possible that a script frees
00692                              * descriptors in arbitrary order which would prevent
00693                              * descriptor_count ever being reduced to zero until
00694                              * zend_hash_num_elements() returns 0.
00695                              */
00696                             descriptor->connection->descriptor_count--;
00697                      }
00698               }
00699        }
00700        
00701        /* flushing Lobs & Files with buffering enabled */
00702        if ((descriptor->type == OCI_DTYPE_FILE || descriptor->type == OCI_DTYPE_LOB) && descriptor->buffering == PHP_OCI_LOB_BUFFER_USED) {
00703               php_oci_lob_flush(descriptor, OCI_LOB_BUFFER_FREE TSRMLS_CC);
00704        }
00705 
00706        if (descriptor->type == OCI_DTYPE_LOB) {
00707               php_oci_temp_lob_close(descriptor TSRMLS_CC);
00708        }
00709 
00710        PHP_OCI_CALL(OCIDescriptorFree, (descriptor->descriptor, descriptor->type));
00711 
00712        zend_list_delete(descriptor->connection->rsrc_id);
00713        efree(descriptor);
00714 } /* }}} */
00715 
00716 /* {{{ php_oci_lob_import()
00717  Import LOB contents from the given file */
00718 int php_oci_lob_import (php_oci_descriptor *descriptor, char *filename TSRMLS_DC)
00719 {
00720        int fp;
00721        ub4 loblen;
00722        OCILobLocator *lob = (OCILobLocator *)descriptor->descriptor;
00723        php_oci_connection *connection = descriptor->connection;
00724        char buf[8192];
00725        ub4 offset = 1;
00726        
00727 #if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 3) || (PHP_MAJOR_VERSION > 5)
00728        /* Safe mode has been removed in PHP 5.4 */
00729        if (php_check_open_basedir(filename TSRMLS_CC)) {
00730 #else
00731        if ((PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(filename TSRMLS_CC)) {
00732 #endif
00733               return 1;
00734        }
00735        
00736        if ((fp = VCWD_OPEN(filename, O_RDONLY|O_BINARY)) == -1) {
00737               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't open file %s", filename);
00738               return 1;
00739        }
00740 
00741        while ((loblen = read(fp, &buf, sizeof(buf))) > 0) {    
00742               PHP_OCI_CALL_RETURN(connection->errcode,
00743                             OCILobWrite,
00744                             (
00745                                    connection->svc,
00746                                    connection->err,
00747                                    lob,
00748                                    &loblen,
00749                                    offset,
00750                                    (dvoid *) &buf,
00751                                    loblen,
00752                                    OCI_ONE_PIECE,
00753                                    (dvoid *)0,
00754                                    (OCICallbackLobWrite) 0,
00755                                    (ub2) descriptor->charset_id,
00756                                    (ub1) descriptor->charset_form
00757                             )
00758               );
00759 
00760               if (connection->errcode != OCI_SUCCESS) {
00761                      connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00762                      PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00763                      close(fp);
00764                      return 1;
00765               }
00766               offset += loblen;
00767        }
00768        close(fp);
00769        
00770        return 0;
00771 } /* }}} */
00772 
00773 /* {{{ php_oci_lob_append()
00774  Append data to the end of the LOB */
00775 int php_oci_lob_append (php_oci_descriptor *descriptor_dest, php_oci_descriptor *descriptor_from TSRMLS_DC)
00776 {
00777        php_oci_connection *connection = descriptor_dest->connection;
00778        OCILobLocator *lob_dest = descriptor_dest->descriptor;
00779        OCILobLocator *lob_from = descriptor_from->descriptor;
00780        ub4 dest_len, from_len;
00781 
00782        if (php_oci_lob_get_length(descriptor_dest, &dest_len TSRMLS_CC)) {
00783               return 1;
00784        }
00785        
00786        if (php_oci_lob_get_length(descriptor_from, &from_len TSRMLS_CC)) {
00787               return 1;
00788        }
00789 
00790        if (from_len <= 0) {
00791               return 0;
00792        }
00793 
00794        PHP_OCI_CALL_RETURN(connection->errcode, OCILobAppend, (connection->svc, connection->err, lob_dest, lob_from));
00795 
00796        if (connection->errcode != OCI_SUCCESS) {
00797               connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00798               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00799               return 1;
00800        }
00801        return 0;
00802 } /* }}} */
00803 
00804 /* {{{ php_oci_lob_truncate()
00805  Truncate LOB to the given length */
00806 int php_oci_lob_truncate (php_oci_descriptor *descriptor, long new_lob_length TSRMLS_DC)
00807 {
00808        php_oci_connection *connection = descriptor->connection;
00809        OCILobLocator *lob = descriptor->descriptor;
00810        ub4 lob_length;
00811        
00812        if (php_oci_lob_get_length(descriptor, &lob_length TSRMLS_CC)) {
00813               return 1;
00814        }
00815        
00816        if (lob_length <= 0) {
00817               return 0;
00818        }
00819 
00820        if (new_lob_length < 0) {
00821               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Size must be greater than or equal to 0");
00822               return 1;
00823        }
00824 
00825        if (new_lob_length > lob_length) {
00826               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Size must be less than or equal to the current LOB size");
00827               return 1;
00828        }
00829        
00830        PHP_OCI_CALL_RETURN(connection->errcode, OCILobTrim, (connection->svc, connection->err, lob, new_lob_length));
00831 
00832        if (connection->errcode != OCI_SUCCESS) {
00833               connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00834               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00835               return 1;
00836        }
00837        
00838        descriptor->lob_size = new_lob_length;
00839        return 0;
00840 } /* }}} */
00841 
00842 /* {{{ php_oci_lob_erase()
00843  Erase (or fill with whitespaces, depending on LOB type) the LOB (or its part) */
00844 int php_oci_lob_erase (php_oci_descriptor *descriptor, long offset, ub4 length, ub4 *bytes_erased TSRMLS_DC)
00845 {
00846        php_oci_connection *connection = descriptor->connection;
00847        OCILobLocator *lob = descriptor->descriptor;
00848        ub4 lob_length;
00849 
00850        *bytes_erased = 0;
00851        
00852        if (php_oci_lob_get_length(descriptor, &lob_length TSRMLS_CC)) {
00853               return 1;
00854        }
00855        
00856        if (offset == -1) {
00857               offset = descriptor->lob_current_position;
00858        }
00859 
00860        if (length == -1) {
00861               length = lob_length;
00862        }
00863        
00864        PHP_OCI_CALL_RETURN(connection->errcode, OCILobErase, (connection->svc, connection->err, lob, (ub4 *)&length, offset+1));
00865 
00866        if (connection->errcode != OCI_SUCCESS) {
00867               connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00868               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00869               return 1;
00870        }
00871        
00872        *bytes_erased = length;
00873        return 0;
00874 } /* }}} */
00875 
00876 /* {{{ php_oci_lob_is_equal()
00877  Compare two LOB descriptors and figure out if they are pointing to the same LOB */
00878 int php_oci_lob_is_equal (php_oci_descriptor *descriptor_first, php_oci_descriptor *descriptor_second, boolean *result TSRMLS_DC)
00879 {
00880        php_oci_connection *connection = descriptor_first->connection;
00881        OCILobLocator *first_lob   = descriptor_first->descriptor;
00882        OCILobLocator *second_lob  = descriptor_second->descriptor;
00883 
00884        PHP_OCI_CALL_RETURN(connection->errcode, OCILobIsEqual, (connection->env, first_lob, second_lob, result));
00885 
00886        if (connection->errcode) {
00887               connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00888               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00889               return 1;
00890        }
00891        return 0;
00892 } /* }}} */
00893 
00894 /* {{{ php_oci_lob_write_tmp()
00895  Create temporary LOB and write data to it */
00896 int php_oci_lob_write_tmp (php_oci_descriptor *descriptor, long type, char *data, int data_len TSRMLS_DC)
00897 {
00898        php_oci_connection *connection = descriptor->connection;
00899        OCILobLocator *lob             = descriptor->descriptor;
00900        ub4 bytes_written = 0;
00901        
00902        switch (type) {
00903               case OCI_TEMP_BLOB:
00904               case OCI_TEMP_CLOB:
00905                      /* only these two are allowed */
00906                      break;
00907               default:
00908                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid temporary lob type: %ld", type);
00909                      return 1;
00910                      break;
00911        }
00912 
00913        if (data_len < 0) {
00914               return 1;
00915        }
00916 
00917        PHP_OCI_CALL_RETURN(connection->errcode, OCILobCreateTemporary,
00918                      (
00919                       connection->svc,
00920                       connection->err,
00921                       lob,
00922                       OCI_DEFAULT,
00923                       OCI_DEFAULT,
00924                       (ub1)type,
00925                       OCI_ATTR_NOCACHE,
00926                       OCI_DURATION_SESSION
00927                      )
00928        );
00929 
00930        if (connection->errcode) {
00931               connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00932               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00933               return 1;
00934        }
00935 
00936        PHP_OCI_CALL_RETURN(connection->errcode, OCILobOpen, (connection->svc, connection->err, lob, OCI_LOB_READWRITE));
00937 
00938        if (connection->errcode) {
00939               connection->errcode = php_oci_error(connection->err, connection->errcode TSRMLS_CC);
00940               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
00941               return 1;
00942        }
00943 
00944        descriptor->is_open = 1;
00945 
00946        return php_oci_lob_write(descriptor, 0, data, data_len, &bytes_written TSRMLS_CC);
00947 } /* }}} */
00948 
00949 #endif /* HAVE_OCI8 */
00950 
00951 /*
00952  * Local variables:
00953  * tab-width: 4
00954  * c-basic-offset: 4
00955  * End:
00956  * vim600: noet sw=4 ts=4 fdm=marker
00957  * vim<600: noet sw=4 ts=4
00958  */