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