tony2001                Wed Jun  7 13:36:19 2006 UTC

  Modified files:              
    /php-src/ext/oci8   oci8_lob.c php_oci8_int.h 
  Log:
  happy birthday commit, yay =)
  this patch should fix Unicode LOB problems using callbacks to read LOBs
  the patch also includes an optimization: using chunk_size*X buffer should 
speed up LOB reading a bit
  
  many thanks to Massimo Squillace <msquillace at sogei dot it> for the patch.
  
  
http://cvs.php.net/viewcvs.cgi/php-src/ext/oci8/oci8_lob.c?r1=1.13&r2=1.14&diff_format=u
Index: php-src/ext/oci8/oci8_lob.c
diff -u php-src/ext/oci8/oci8_lob.c:1.13 php-src/ext/oci8/oci8_lob.c:1.14
--- php-src/ext/oci8/oci8_lob.c:1.13    Sat May 20 13:46:41 2006
+++ php-src/ext/oci8/oci8_lob.c Wed Jun  7 13:36:19 2006
@@ -25,7 +25,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: oci8_lob.c,v 1.13 2006/05/20 13:46:41 tony2001 Exp $ */
+/* $Id: oci8_lob.c,v 1.14 2006/06/07 13:36:19 tony2001 Exp $ */
 
 
 
@@ -144,25 +144,92 @@
        return 0;       
 } /* }}} */
 
+/* {{{ php_oci_lob_callback()
+   Append LOB portion to a memory buffer */
+#if defined(HAVE_OCI_LOB_READ2)
+sb4 php_oci_lob_callback (dvoid *ctxp, CONST dvoid *bufxp, oraub8 len, ub1 
piece, dvoid **changed_bufpp, oraub8 *changed_lenp)
+#else
+sb4 php_oci_lob_callback (dvoid *ctxp, CONST dvoid *bufxp, ub4 len, ub1 piece)
+#endif
+{
+       ub4 lenp = (ub4) len;
+       php_oci_lob_ctx *ctx = (php_oci_lob_ctx *)ctxp;
+
+       switch (piece)
+       {
+               case OCI_LAST_PIECE:
+                       *(ctx->lob_data) = erealloc(*(ctx->lob_data), (size_t) 
(*(ctx->lob_len) + lenp + 1));
+                       memcpy(*(ctx->lob_data) + *(ctx->lob_len), bufxp, 
(size_t) lenp);
+                       *(ctx->lob_len) += lenp;
+                       *(*(ctx->lob_data) + *(ctx->lob_len)) = 0x00;
+                       return OCI_CONTINUE;
+
+               case OCI_FIRST_PIECE:
+               case OCI_NEXT_PIECE:
+                       *(ctx->lob_data) = erealloc(*(ctx->lob_data), (size_t) 
(*(ctx->lob_len) + lenp));
+                       memcpy(*(ctx->lob_data) + *(ctx->lob_len), bufxp, 
(size_t) lenp);
+                       *(ctx->lob_len) += lenp;
+                       return OCI_CONTINUE;
+
+               default: {
+                       TSRMLS_FETCH();
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unexpected 
LOB piece id received (value:%d)", piece);
+                       efree(*(ctx->lob_data));
+                       *(ctx->lob_data) = NULL;
+                       *(ctx->lob_len) = 0;
+                       return OCI_ERROR;
+               }
+       }
+}
+/* }}} */
+
+/* {{{ php_oci_lob_calculate_buffer() */
+static inline int php_oci_lob_calculate_buffer(php_oci_descriptor *descriptor, 
long read_length TSRMLS_DC)
+{
+       php_oci_connection *connection = descriptor->connection;
+       ub4 chunk_size;
+               
+       if (!descriptor->chunk_size) {
+               connection->errcode = PHP_OCI_CALL(OCILobGetChunkSize, 
(connection->svc, connection->err, descriptor->descriptor, &chunk_size));
+
+               if (connection->errcode != OCI_SUCCESS) {
+                       php_oci_error(connection->err, connection->errcode 
TSRMLS_CC);
+                       PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+                       return read_length; /* we have to return original 
length here */
+               }
+               descriptor->chunk_size = chunk_size;
+       }
+       
+       if ((read_length % descriptor->chunk_size) != 0) {
+               return descriptor->chunk_size * ((read_length / 
descriptor->chunk_size) + 1);
+       }
+       return read_length;
+}
+/* }}} */
+
 /* {{{ php_oci_lob_read() 
  Read specified portion of the LOB into the buffer */
 int php_oci_lob_read (php_oci_descriptor *descriptor, long read_length, long 
initial_offset, char **data, ub4 *data_len TSRMLS_DC)
 {
        php_oci_connection *connection = descriptor->connection;
        ub4 length = 0;
+       int buffer_size = PHP_OCI_LOB_BUFFER_SIZE;
+       php_oci_lob_ctx ctx;
+       ub1 *bufp;
 #if defined(HAVE_OCI_LOB_READ2)
-       oraub8 bytes_read, bytes_total = 0, offset = 0;
+       oraub8 bytes_read, offset = 0;
        oraub8 requested_len = read_length; /* this is by default */
        oraub8 chars_read = 0;
+       int is_clob = 0;
 #else
-       int bytes_read, bytes_total = 0, offset = 0;
+       int bytes_read, offset = 0;
        int requested_len = read_length; /* this is by default */
-       int chars_read = 0;
 #endif
-       int is_clob = 0;
 
        *data_len = 0;
        *data = NULL;
+       ctx.lob_len = data_len;
+       ctx.lob_data = data;
 
        if (php_oci_lob_get_length(descriptor, &length TSRMLS_CC)) {
                return 1;
@@ -188,6 +255,8 @@
        if (requested_len <= 0) {
                return 0;
        }
+       
+       offset = initial_offset;
 
        if (descriptor->type == OCI_DTYPE_FILE) {
                connection->errcode = PHP_OCI_CALL(OCILobFileOpen, 
(connection->svc, connection->err, descriptor->descriptor, OCI_FILE_READONLY));
@@ -214,82 +283,70 @@
                        is_clob = 1;
                }
        }
-#endif
 
-       *data = (char *)emalloc(requested_len + 1);
-       bytes_read = requested_len;
-       offset = initial_offset;
-               
-       /* TODO
-        * We need to make sure this function works with Unicode LOBs
-        * */
-
-#if defined(HAVE_OCI_LOB_READ2)
-
-       do {
+       if (is_clob) {
+               chars_read = requested_len;
+               bytes_read = 0;
+       } else {
                chars_read = 0;
-               connection->errcode = PHP_OCI_CALL(OCILobRead2, 
-                       (
-                               connection->svc, 
-                               connection->err, 
-                               descriptor->descriptor, 
-                               (oraub8 *)&bytes_read,                          
                                /* IN/OUT bytes toread/read */
-                               (oraub8 *)&chars_read,
-                               (oraub8) offset + 1,                            
                                /* offset (starts with 1) */ 
-                               (dvoid *) ((char *) *data + *data_len), 
-                               (oraub8) requested_len,                         
                                        /* size of buffer */ 
-                               0, 
-                               NULL,
-                               (OCICallbackLobRead2) 0,                        
                /* callback... */ 
-                               (ub2) connection->charset,      /* The 
character set ID of the buffer data. */ 
-                               (ub1) SQLCS_IMPLICIT                            
        /* The character set form of the buffer data. */
-                       )
-               );
+               bytes_read = requested_len;
+       }
 
-               bytes_total += bytes_read;
-               if (is_clob) {
-                       offset += chars_read;
-               } else {
-                       offset += bytes_read;
-               }
-               
-               *data_len += bytes_read;
-               
-               if (connection->errcode != OCI_NEED_DATA) {
-                       break;
-               }
-               *data = erealloc(*data, *data_len + PHP_OCI_LOB_BUFFER_SIZE + 
1);       
-       } while (connection->errcode == OCI_NEED_DATA);
+       buffer_size = (requested_len < buffer_size ) ? requested_len : 
buffer_size;             /* optimize buffer size */
+       buffer_size = php_oci_lob_calculate_buffer(descriptor, buffer_size 
TSRMLS_CC);  /* use chunk size */
+
+       bufp = (ub1 *) ecalloc(1, buffer_size);
+       connection->errcode = PHP_OCI_CALL(OCILobRead2,
+               (
+                       connection->svc,
+                       connection->err,
+                       descriptor->descriptor,
+                       (oraub8 *)&bytes_read,                          /* 
IN/OUT bytes toread/read */
+                       (oraub8 *)&chars_read,                          /* 
IN/OUT chars toread/read */
+                       (oraub8) offset + 1,                            /* 
offset (starts with 1) */
+                       (dvoid *) bufp,
+                       (oraub8) buffer_size,                           /* size 
of buffer */
+                       OCI_FIRST_PIECE,
+                       (dvoid *)&ctx,
+                       (OCICallbackLobRead2) php_oci_lob_callback,             
/* callback... */
+                       (ub2) connection->charset,              /* The 
character set ID of the buffer data. */
+                       (ub1) SQLCS_IMPLICIT                    /* The 
character set form of the buffer data. */
+               )
+       );
+       
+       efree(bufp);
+       
+       if (is_clob) {
+               offset = descriptor->lob_current_position + chars_read;
+       } else {
+               offset = descriptor->lob_current_position + bytes_read;
+       }
 
 #else
 
-       do {
-               connection->errcode = PHP_OCI_CALL(OCILobRead, 
-                       (
-                               connection->svc, 
-                               connection->err, 
-                               descriptor->descriptor, 
-                               &bytes_read,                                    
                        /* IN/OUT bytes toread/read */ 
-                               offset + 1,                                     
                        /* offset (starts with 1) */ 
-                               (dvoid *) ((char *) *data + *data_len), 
-                               requested_len,                                  
                                /* size of buffer */ 
-                               (dvoid *)0, 
-                               (OCICallbackLobRead) 0,                         
        /* callback... */ 
-                               (ub2) connection->charset,      /* The 
character set ID of the buffer data. */ 
-                               (ub1) SQLCS_IMPLICIT                            
        /* The character set form of the buffer data. */
-                       )
-               );
+       bytes_read = requested_len;
+       buffer_size = (requested_len < buffer_size ) ? requested_len : 
buffer_size;             /* optimize buffer size */
+       buffer_size = php_oci_lob_calculate_buffer(descriptor, buffer_size 
TSRMLS_CC);  /* use chunk size */
 
-               bytes_total += bytes_read;
-               offset += bytes_read;
-               
-               *data_len += bytes_read;
-               
-               if (connection->errcode != OCI_NEED_DATA) {
-                       break;
-               }
-               *data = erealloc(*data, *data_len + PHP_OCI_LOB_BUFFER_SIZE + 
1);       
-       } while (connection->errcode == OCI_NEED_DATA);
+       bufp = (ub1 *) ecalloc(1, buffer_size);
+       connection->errcode = PHP_OCI_CALL(OCILobRead,
+               (
+                        connection->svc,
+                        connection->err,
+                        descriptor->descriptor,
+                        &bytes_read,                                /* IN/OUT 
bytes toread/read */
+                        offset + 1,                             /* offset 
(starts with 1) */
+                        (dvoid *) bufp,
+                        (ub4) buffer_size,                          /* size of 
buffer */
+                        (dvoid *)&ctx,
+                        (OCICallbackLobRead) php_oci_lob_callback,             
 /* callback... */
+                        (ub2) connection->charset,              /* The 
character set ID of the buffer data. */
+                        (ub1) SQLCS_IMPLICIT                    /* The 
character set form of the buffer data. */
+               )
+       );
+       
+       efree(bufp);
+       offset = descriptor->lob_current_position + bytes_read;
 
 #endif
        
@@ -298,10 +355,11 @@
                PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
                efree(*data);
                *data = NULL;
+               *data_len = 0;
                return 1;
        }
        
-       descriptor->lob_current_position = offset; 
+       descriptor->lob_current_position = (int)offset; 
 
        if (descriptor->type == OCI_DTYPE_FILE) {
                connection->errcode = PHP_OCI_CALL(OCILobFileClose, 
(connection->svc, connection->err, descriptor->descriptor));
@@ -311,13 +369,11 @@
                        PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
                        efree(*data);
                        *data = NULL;
+                       *data_len = 0;
                        return 1;
                }
        }
 
-       *data = erealloc(*data, *data_len + 1);
-       (*data)[ *data_len ] = 0;
-
        return 0;
 } /* }}} */
 
http://cvs.php.net/viewcvs.cgi/php-src/ext/oci8/php_oci8_int.h?r1=1.15&r2=1.16&diff_format=u
Index: php-src/ext/oci8/php_oci8_int.h
diff -u php-src/ext/oci8/php_oci8_int.h:1.15 
php-src/ext/oci8/php_oci8_int.h:1.16
--- php-src/ext/oci8/php_oci8_int.h:1.15        Wed Apr  5 14:07:16 2006
+++ php-src/ext/oci8/php_oci8_int.h     Wed Jun  7 13:36:19 2006
@@ -25,7 +25,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: php_oci8_int.h,v 1.15 2006/04/05 14:07:16 tony2001 Exp $ */
+/* $Id: php_oci8_int.h,v 1.16 2006/06/07 13:36:19 tony2001 Exp $ */
 
 #if HAVE_OCI8
 # ifndef PHP_OCI8_INT_H
@@ -78,7 +78,7 @@
 #define PHP_OCI_MAX_NAME_LEN  64
 #define PHP_OCI_MAX_DATA_SIZE INT_MAX
 #define PHP_OCI_PIECE_SIZE    (64*1024)-1
-#define PHP_OCI_LOB_BUFFER_SIZE 32768 
+#define PHP_OCI_LOB_BUFFER_SIZE 1048576l  /* 1Mb seems to be the most 
reasonable buffer size for LOB reading */
 
 #define PHP_OCI_ASSOC               1<<0
 #define PHP_OCI_NUM                 1<<1
@@ -126,8 +126,14 @@
        int lob_current_position;               /* LOB internal pointer */ 
        int lob_size;                                   /* cached LOB size. -1 
= Lob wasn't initialized yet */
        int buffering;                                  /* cached buffering 
flag. 0 - off, 1 - on, 2 - on and buffer was used */
+       ub4 chunk_size;                                 /* chunk size of the 
LOB. 0 - unknown */
 } php_oci_descriptor; /* }}} */
 
+typedef struct { /* php_oci_lob_ctx {{{ */
+       char **lob_data;            /* address of pointer to LOB data */
+       ub4 *lob_len;               /* address of LOB length variable (bytes) */
+} php_oci_lob_ctx; /* }}} */
+
 typedef struct { /* php_oci_collection {{{ */
        int id;
        php_oci_connection *connection; /* parent connection handle */
@@ -318,6 +324,11 @@
 int php_oci_lob_truncate (php_oci_descriptor *, long TSRMLS_DC);
 int php_oci_lob_erase (php_oci_descriptor *, long, long, ub4 * TSRMLS_DC);
 int php_oci_lob_is_equal (php_oci_descriptor *, php_oci_descriptor *, boolean 
* TSRMLS_DC);
+#if defined(HAVE_OCI_LOB_READ2)
+sb4 php_oci_lob_callback (dvoid *ctxp, CONST dvoid *bufxp, oraub8 len, ub1 
piece, dvoid **changed_bufpp, oraub8 *changed_lenp);
+#else
+sb4 php_oci_lob_callback (dvoid *ctxp, CONST dvoid *bufxp, ub4 len, ub1 piece);
+#endif
 
 /* }}} */
 

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to