Add oci8.prefetch_lob_size

This commit is contained in:
Christopher Jones 2021-11-12 17:59:22 +11:00
parent e96f980fcc
commit 9cd7f41fac
No known key found for this signature in database
GPG key ID: F3DF7046B54073C9
11 changed files with 226 additions and 23 deletions

3
NEWS
View file

@ -8,6 +8,9 @@ PHP NEWS
- Core: - Core:
. Fixed bug #81380 (Observer may not be initialized properly). (krakjoe) . Fixed bug #81380 (Observer may not be initialized properly). (krakjoe)
- OCI8:
. Added oci8.prefetch_lob_size directive to tune LOB query performance
- Zip: - Zip:
. add ZipArchive::clearError() method . add ZipArchive::clearError() method
. add ZipArchive::getStreamName() method . add ZipArchive::getStreamName() method

View file

@ -27,6 +27,11 @@ PHP 8.2 UPGRADE NOTES
. Added CURLINFO_EFFECTIVE_METHOD option and returning the effective . Added CURLINFO_EFFECTIVE_METHOD option and returning the effective
HTTP method in curl_getinfo() return value. HTTP method in curl_getinfo() return value.
- OCI8:
. Added an oci8.prefetch_lob_size directive to tune LOB query performance
by reducing the number of round-trips between PHP and Oracle Database when
fetching LOBS. This is usable with Oracle Database 12.2 or later.
- PCRE: - PCRE:
. Added support for the "n" (NO_AUTO_CAPTURE) modifier, which makes simple . Added support for the "n" (NO_AUTO_CAPTURE) modifier, which makes simple
`(xyz)` groups non-capturing. Only named groups like `(?<name>xyz)` are `(xyz)` groups non-capturing. Only named groups like `(?<name>xyz)` are

View file

@ -174,6 +174,7 @@ PHP_INI_BEGIN()
#if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2))) #if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2)))
STD_PHP_INI_BOOLEAN("oci8.events", "0", PHP_INI_SYSTEM, OnUpdateBool, events, zend_oci_globals, oci_globals) STD_PHP_INI_BOOLEAN("oci8.events", "0", PHP_INI_SYSTEM, OnUpdateBool, events, zend_oci_globals, oci_globals)
#endif #endif
STD_PHP_INI_ENTRY( "oci8.prefetch_lob_size", "0", PHP_INI_ALL, OnUpdateLong, prefetch_lob_size, zend_oci_globals, oci_globals)
PHP_INI_END() PHP_INI_END()
/* }}} */ /* }}} */

View file

@ -359,7 +359,7 @@ int php_oci_statement_fetch(php_oci_statement *statement, ub4 nrows)
if (errstatus == OCI_SUCCESS_WITH_INFO || errstatus == OCI_SUCCESS) { if (errstatus == OCI_SUCCESS_WITH_INFO || errstatus == OCI_SUCCESS) {
statement->has_data = 1; statement->has_data = 1;
/* do the stuff needed for OCIDefineByName */ /* do the stuff needed for OCIDefineByPos */
for (i = 0; i < statement->ncolumns; i++) { for (i = 0; i < statement->ncolumns; i++) {
column = php_oci_statement_get_column(statement, i + 1, NULL, 0); column = php_oci_statement_get_column(statement, i + 1, NULL, 0);
if (column == NULL) { if (column == NULL) {
@ -794,7 +794,6 @@ int php_oci_statement_execute(php_oci_statement *statement, ub4 mode)
OCI_DYNAMIC_FETCH /* IN mode (OCI_DEFAULT, OCI_DYNAMIC_FETCH) */ OCI_DYNAMIC_FETCH /* IN mode (OCI_DEFAULT, OCI_DYNAMIC_FETCH) */
) )
); );
} else { } else {
PHP_OCI_CALL_RETURN(errstatus, PHP_OCI_CALL_RETURN(errstatus,
OCIDefineByPos, OCIDefineByPos,
@ -821,12 +820,19 @@ int php_oci_statement_execute(php_oci_statement *statement, ub4 mode)
return 1; return 1;
} }
/* additional OCIDefineDynamic() call */ /* additional define setup */
switch (outcol->data_type) { switch (outcol->data_type) {
case SQLT_RSET:
case SQLT_RDD:
case SQLT_BLOB: case SQLT_BLOB:
case SQLT_CLOB: case SQLT_CLOB:
if (OCI_G(prefetch_lob_size) > 0) {
int get_lob_len = 1; /* == true */
ub4 prefetch_size = OCI_G(prefetch_lob_size);
PHP_OCI_CALL_RETURN(errstatus, OCIAttrSet, (outcol->oci_define, OCI_HTYPE_DEFINE, &get_lob_len, 0, OCI_ATTR_LOBPREFETCH_LENGTH, statement->err));
PHP_OCI_CALL_RETURN(errstatus, OCIAttrSet, (outcol->oci_define, OCI_HTYPE_DEFINE, &prefetch_size, 0, OCI_ATTR_LOBPREFETCH_SIZE, statement->err));
}
ZEND_FALLTHROUGH;
case SQLT_RSET:
case SQLT_RDD:
case SQLT_BFILE: case SQLT_BFILE:
PHP_OCI_CALL_RETURN(errstatus, PHP_OCI_CALL_RETURN(errstatus,
OCIDefineDynamic, OCIDefineDynamic,
@ -1483,12 +1489,6 @@ sb4 php_oci_bind_out_callback(
ZVAL_STRINGL(val, p, PHP_OCI_PIECE_SIZE); ZVAL_STRINGL(val, p, PHP_OCI_PIECE_SIZE);
efree(p); efree(p);
} }
#if 0
Z_STRLEN_P(val) = PHP_OCI_PIECE_SIZE; /* 64K-1 is max XXX */
Z_STRVAL_P(val) = ecalloc(1, Z_STRLEN_P(val) + 1);
/* XXX is this right? */
ZVAL_STRINGL(val, NULL, Z_STRLEN(val) + 1);
#endif
/* XXX we assume that zend-zval len has 4 bytes */ /* XXX we assume that zend-zval len has 4 bytes */
*alenpp = (ub4*) &Z_STRLEN_P(val); *alenpp = (ub4*) &Z_STRLEN_P(val);

View file

@ -53,12 +53,12 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin
<active>no</active> <active>no</active>
</lead> </lead>
<date>2021-08-02</date> <date>2021-11-15</date>
<time>12:00:00</time> <time>12:00:00</time>
<version> <version>
<release>3.1.0</release> <release>3.2.0</release>
<api>3.1.0</api> <api>3.2.0</api>
</version> </version>
<stability> <stability>
<release>stable</release> <release>stable</release>
@ -68,7 +68,7 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin
<notes> <notes>
This version is for PHP 8 only. This version is for PHP 8 only.
Deprecated directive oci8.old_oci_close_semantics Added oci8.prefetch_lob_size directive to improve LOB query performance.
</notes> </notes>
<contents> <contents>
<dir name="/"> <dir name="/">
@ -448,6 +448,23 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin
</extsrcrelease> </extsrcrelease>
<changelog> <changelog>
<release>
<version>
<release>3.1.0</release>
<api>3.1.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://www.php.net/license">PHP</license>
<notes>
This version is for PHP 8 only.
Deprecated directive oci8.old_oci_close_semantics
</notes>
</release>
<release> <release>
<version> <version>
<release>3.0.1</release> <release>3.0.1</release>

View file

@ -41,7 +41,7 @@
*/ */
#undef PHP_OCI8_VERSION #undef PHP_OCI8_VERSION
#endif #endif
#define PHP_OCI8_VERSION "3.1.0" #define PHP_OCI8_VERSION "3.2.0"
extern zend_module_entry oci8_module_entry; extern zend_module_entry oci8_module_entry;
#define phpext_oci8_ptr &oci8_module_entry #define phpext_oci8_ptr &oci8_module_entry

View file

@ -519,9 +519,9 @@ ZEND_BEGIN_MODULE_GLOBALS(oci) /* {{{ Module globals */
zend_long persistent_timeout; /* time period after which idle persistent connection is considered expired */ zend_long persistent_timeout; /* time period after which idle persistent connection is considered expired */
zend_long statement_cache_size; /* statement cache size. used with 9i+ clients only*/ zend_long statement_cache_size; /* statement cache size. used with 9i+ clients only*/
zend_long default_prefetch; /* default prefetch setting */ zend_long default_prefetch; /* default prefetch setting */
zend_long prefetch_lob_size; /* amount of LOB data to read when initially getting a LOB locator */
bool privileged_connect; /* privileged connect flag (On/Off) */ bool privileged_connect; /* privileged connect flag (On/Off) */
bool old_oci_close_semantics; /* old_oci_close_semantics flag (to determine the way oci_close() should behave) */ bool old_oci_close_semantics; /* old_oci_close_semantics flag (to determine the way oci_close() should behave) */
int shutdown; /* in shutdown flag */ int shutdown; /* in shutdown flag */
OCIEnv *env; /* global environment handle */ OCIEnv *env; /* global environment handle */

View file

@ -57,11 +57,11 @@ function get_attr($conn)
?> ?>
--EXPECT-- --EXPECT--
**Test 1.1 - Default values for the attribute ************** **Test 1.1 - Default values for the attribute **************
The value of DRIVER_NAME is PHP OCI8 : 3.1.0 The value of DRIVER_NAME is PHP OCI8 : 3.2.0
***Test 1.2 - Get the values from different connections ************** ***Test 1.2 - Get the values from different connections **************
Testing with oci_pconnect() Testing with oci_pconnect()
The value of DRIVER_NAME is PHP OCI8 : 3.1.0 The value of DRIVER_NAME is PHP OCI8 : 3.2.0
Testing with oci_new_connect() Testing with oci_new_connect()
The value of DRIVER_NAME is PHP OCI8 : 3.1.0 The value of DRIVER_NAME is PHP OCI8 : 3.2.0
Done Done

163
ext/oci8/tests/lob_prefetch.phpt Executable file
View file

@ -0,0 +1,163 @@
--TEST--
LOB prefetching
--EXTENSIONS--
oci8
--SKIPIF--
<?php
$target_dbs = array('oracledb' => true, 'timesten' => false); // test runs on these DBs
require(__DIR__.'/skipif.inc');
?>
--FILE--
<?php
require __DIR__.'/connect.inc';
require __DIR__.'/create_table.inc';
define("NUMROWS", 500);
define("LOBSIZE", 64000);
$ora_sql =
"declare
c clob;
b blob;
numrows number := 500;
dest_offset integer := 1;
src_offset integer := 1;
warn integer;
ctx integer := dbms_lob.default_lang_ctx;
begin
for j in 1..numrows
loop
c := DBMS_RANDOM.string('L',TRUNC(DBMS_RANDOM.value(1000,1000)));
for i in 1..6
loop
c := c||c;
end loop;
dbms_lob.createtemporary(b, false);
dbms_lob.converttoblob(b, c, dbms_lob.lobmaxsize, dest_offset, src_offset, dbms_lob.default_csid, ctx, warn);
insert /*+ APPEND */ into ${schema}${table_name} (id, clob, blob) values (j, c, b);
end loop;
commit;
end;";
$statement = oci_parse($c,$ora_sql);
oci_execute($statement);
function get_clob_loc($c, $sql) {
$stid = oci_parse($c, $sql);
oci_execute($stid);
$l = [];
while (($row = oci_fetch_array($stid, OCI_ASSOC)) != false) {
$l[] = $row['CLOB']->load();
$row['CLOB']->free();
if (strlen($l[0]) != LOBSIZE) { print("strlen(l) failure" . strlen($l)); exit; }
}
return($l);
}
function get_clob_inline($c, $sql) {
$stid = oci_parse($c, $sql);
oci_execute($stid);
$l = [];
while (($row = oci_fetch_array($stid, OCI_ASSOC+OCI_RETURN_LOBS)) != false) {
$l[] = $row['CLOB'];
if (strlen($l[0]) != LOBSIZE) { print("strlen(l) failure" . strlen($l)); exit; }
}
return($l);
}
function check_clobs($locarr, $inlinearr) {
print("Comparing CLOBS\n");
for ($i = 0; $i < NUMROWS; ++$i) {
if (strlen($locarr[$i]) != LOBSIZE) {
trigger_error("size mismatch at $i " . strlen($locarr[$i]), E_USER_ERROR);
exit;
}
if (strcmp($locarr[$i], $inlinearr[$i])) {
trigger_error("data mismatch at $i " . strlen($locarr[$i]) . " " . strlen($inlinearr[$i]), E_USER_ERROR);
exit;
}
}
}
function get_blob_loc($c, $sql) {
$stid = oci_parse($c, $sql);
oci_execute($stid);
$l = [];
while (($row = oci_fetch_array($stid, OCI_ASSOC)) != false) {
$l[] = $row['BLOB']->load();
$row['BLOB']->free();
if (strlen($l[0]) != LOBSIZE) { print("strlen(l) failure" . strlen($l)); exit; }
}
return($l);
}
print("Test 1\n");
$ig = ini_get("oci8.prefetch_lob_size");
var_dump($ig);
$ig = ini_set("oci8.prefetch_lob_size", "100000");
var_dump($ig);
$ig = ini_get("oci8.prefetch_lob_size");
var_dump($ig);
print("Test 2 - CLOB prefetch_lob_size 100000\n");
$sql = "select clob from ${schema}${table_name}" . " order by id";
$locarr = get_clob_loc($c, $sql);
$inlinearr = get_clob_inline($c, $sql);
print(count($locarr) . "\n");
print(count($inlinearr) . "\n");
check_clobs($locarr, $inlinearr);
print("Test 3 - CLOB prefetch_lob_size 100\n");
ini_set("oci8.prefetch_lob_size", "100");
$ig = ini_get("oci8.prefetch_lob_size");
var_dump($ig);
$locarr = get_clob_loc($c, $sql);
$inlinearr = get_clob_inline($c, $sql);
print(count($locarr) . "\n");
print(count($inlinearr) . "\n");
check_clobs($locarr, $inlinearr);
print("Test 4 - BLOB prefetch_lob_size 100000\n");
ini_set("oci8.prefetch_lob_size", "100000");
$ig = ini_get("oci8.prefetch_lob_size");
var_dump($ig);
$sql = "select blob from ${schema}${table_name}" . " order by id";
$locarr = get_blob_loc($c, $sql);
print(count($locarr) . "\n");
require __DIR__.'/drop_table.inc';
?>
DONE
--EXPECTF--
Test 1
string(1) "0"
string(1) "0"
string(6) "100000"
Test 2 - CLOB prefetch_lob_size 100000
500
500
Comparing CLOBS
Test 3 - CLOB prefetch_lob_size 100
string(3) "100"
500
500
Comparing CLOBS
Test 4 - BLOB prefetch_lob_size 100000
string(6) "100000"
500
DONE

View file

@ -1254,7 +1254,7 @@ mysqlnd.collect_memory_statistics = On
;oci8.ping_interval = 60 ;oci8.ping_interval = 60
; Connection: Set this to a user chosen connection class to be used ; Connection: Set this to a user chosen connection class to be used
; for all pooled server requests with Oracle 11g Database Resident ; for all pooled server requests with Oracle Database Resident
; Connection Pooling (DRCP). To use DRCP, this value should be set to ; Connection Pooling (DRCP). To use DRCP, this value should be set to
; the same string for all web servers running the same application, ; the same string for all web servers running the same application,
; the database pool must be configured, and the connection string must ; the database pool must be configured, and the connection string must
@ -1271,11 +1271,18 @@ mysqlnd.collect_memory_statistics = On
; https://php.net/oci8.statement-cache-size ; https://php.net/oci8.statement-cache-size
;oci8.statement_cache_size = 20 ;oci8.statement_cache_size = 20
; Tuning: Enables statement prefetching and sets the default number of ; Tuning: Enables row prefetching and sets the default number of
; rows that will be fetched automatically after statement execution. ; rows that will be fetched automatically after statement execution.
; https://php.net/oci8.default-prefetch ; https://php.net/oci8.default-prefetch
;oci8.default_prefetch = 100 ;oci8.default_prefetch = 100
; Tuning: Sets the amount of LOB data that is internally returned from
; Oracle Database when an Oracle LOB locator is initially retrieved as
; part of a query. Setting this can improve performance by reducing
; round-trips.
; https://php.net/oci8.prefetch-lob-size
; oci8.prefetch_lob_size = 0
; Compatibility. Using On means oci_close() will not close ; Compatibility. Using On means oci_close() will not close
; oci_connect() and oci_new_connect() connections. ; oci_connect() and oci_new_connect() connections.
; https://php.net/oci8.old-oci-close-semantics ; https://php.net/oci8.old-oci-close-semantics

View file

@ -1256,7 +1256,7 @@ mysqlnd.collect_memory_statistics = Off
;oci8.ping_interval = 60 ;oci8.ping_interval = 60
; Connection: Set this to a user chosen connection class to be used ; Connection: Set this to a user chosen connection class to be used
; for all pooled server requests with Oracle 11g Database Resident ; for all pooled server requests with Oracle Database Resident
; Connection Pooling (DRCP). To use DRCP, this value should be set to ; Connection Pooling (DRCP). To use DRCP, this value should be set to
; the same string for all web servers running the same application, ; the same string for all web servers running the same application,
; the database pool must be configured, and the connection string must ; the database pool must be configured, and the connection string must
@ -1278,6 +1278,13 @@ mysqlnd.collect_memory_statistics = Off
; https://php.net/oci8.default-prefetch ; https://php.net/oci8.default-prefetch
;oci8.default_prefetch = 100 ;oci8.default_prefetch = 100
; Tuning: Sets the amount of LOB data that is internally returned from
; Oracle Database when an Oracle LOB locator is initially retrieved as
; part of a query. Setting this can improve performance by reducing
; round-trips.
; https://php.net/oci8.prefetch-lob-size
; oci8.prefetch_lob_size = 0
; Compatibility. Using On means oci_close() will not close ; Compatibility. Using On means oci_close() will not close
; oci_connect() and oci_new_connect() connections. ; oci_connect() and oci_new_connect() connections.
; https://php.net/oci8.old-oci-close-semantics ; https://php.net/oci8.old-oci-close-semantics