Skip to content

Commit

Permalink
Add oci8.prefetch_lob_size
Browse files Browse the repository at this point in the history
  • Loading branch information
cjbj committed Nov 12, 2021
1 parent e96f980 commit 9cd7f41
Show file tree
Hide file tree
Showing 11 changed files with 226 additions and 23 deletions.
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ PHP NEWS
- Core:
. Fixed bug #81380 (Observer may not be initialized properly). (krakjoe)

- OCI8:
. Added oci8.prefetch_lob_size directive to tune LOB query performance

- Zip:
. add ZipArchive::clearError() method
. add ZipArchive::getStreamName() method
Expand Down
5 changes: 5 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ PHP 8.2 UPGRADE NOTES
. Added CURLINFO_EFFECTIVE_METHOD option and returning the effective
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:
. Added support for the "n" (NO_AUTO_CAPTURE) modifier, which makes simple
`(xyz)` groups non-capturing. Only named groups like `(?<name>xyz)` are
Expand Down
1 change: 1 addition & 0 deletions ext/oci8/oci8.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ PHP_INI_BEGIN()
#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)
#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()
/* }}} */

Expand Down
22 changes: 11 additions & 11 deletions ext/oci8/oci8_statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ int php_oci_statement_fetch(php_oci_statement *statement, ub4 nrows)
if (errstatus == OCI_SUCCESS_WITH_INFO || errstatus == OCI_SUCCESS) {
statement->has_data = 1;

/* do the stuff needed for OCIDefineByName */
/* do the stuff needed for OCIDefineByPos */
for (i = 0; i < statement->ncolumns; i++) {
column = php_oci_statement_get_column(statement, i + 1, NULL, 0);
if (column == NULL) {
Expand Down Expand Up @@ -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) */
)
);

} else {
PHP_OCI_CALL_RETURN(errstatus,
OCIDefineByPos,
Expand All @@ -821,12 +820,19 @@ int php_oci_statement_execute(php_oci_statement *statement, ub4 mode)
return 1;
}

/* additional OCIDefineDynamic() call */
/* additional define setup */
switch (outcol->data_type) {
case SQLT_RSET:
case SQLT_RDD:
case SQLT_BLOB:
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:
PHP_OCI_CALL_RETURN(errstatus,
OCIDefineDynamic,
Expand Down Expand Up @@ -1483,12 +1489,6 @@ sb4 php_oci_bind_out_callback(
ZVAL_STRINGL(val, p, PHP_OCI_PIECE_SIZE);
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 */
*alenpp = (ub4*) &Z_STRLEN_P(val);
Expand Down
25 changes: 21 additions & 4 deletions ext/oci8/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin
<active>no</active>
</lead>

<date>2021-08-02</date>
<date>2021-11-15</date>
<time>12:00:00</time>

<version>
<release>3.1.0</release>
<api>3.1.0</api>
<release>3.2.0</release>
<api>3.2.0</api>
</version>
<stability>
<release>stable</release>
Expand All @@ -68,7 +68,7 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin
<notes>
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>
<contents>
<dir name="/">
Expand Down Expand Up @@ -448,6 +448,23 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin
</extsrcrelease>
<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>
<version>
<release>3.0.1</release>
Expand Down
2 changes: 1 addition & 1 deletion ext/oci8/php_oci8.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
*/
#undef PHP_OCI8_VERSION
#endif
#define PHP_OCI8_VERSION "3.1.0"
#define PHP_OCI8_VERSION "3.2.0"

extern zend_module_entry oci8_module_entry;
#define phpext_oci8_ptr &oci8_module_entry
Expand Down
2 changes: 1 addition & 1 deletion ext/oci8/php_oci8_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 statement_cache_size; /* statement cache size. used with 9i+ clients only*/
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 old_oci_close_semantics; /* old_oci_close_semantics flag (to determine the way oci_close() should behave) */

int shutdown; /* in shutdown flag */

OCIEnv *env; /* global environment handle */
Expand Down
6 changes: 3 additions & 3 deletions ext/oci8/tests/driver_name.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ function get_attr($conn)
?>
--EXPECT--
**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 **************
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()
The value of DRIVER_NAME is PHP OCI8 : 3.1.0
The value of DRIVER_NAME is PHP OCI8 : 3.2.0
Done
163 changes: 163 additions & 0 deletions ext/oci8/tests/lob_prefetch.phpt
Original file line number Diff line number Diff line change
@@ -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
11 changes: 9 additions & 2 deletions php.ini-development
Original file line number Diff line number Diff line change
Expand Up @@ -1254,7 +1254,7 @@ mysqlnd.collect_memory_statistics = On
;oci8.ping_interval = 60

; 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
; the same string for all web servers running the same application,
; the database pool must be configured, and the connection string must
Expand All @@ -1271,11 +1271,18 @@ mysqlnd.collect_memory_statistics = On
; https://php.net/oci8.statement-cache-size
;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

This comment has been minimized.

Copy link
@xPaw

xPaw Nov 30, 2021

Contributor

This comment change was missed from php.ini-production

This comment has been minimized.

Copy link
@cjbj

cjbj Dec 1, 2021

Author Contributor

Noted.

; rows that will be fetched automatically after statement execution.
; https://php.net/oci8.default-prefetch
;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
; oci_connect() and oci_new_connect() connections.
; https://php.net/oci8.old-oci-close-semantics
Expand Down
9 changes: 8 additions & 1 deletion php.ini-production
Original file line number Diff line number Diff line change
Expand Up @@ -1256,7 +1256,7 @@ mysqlnd.collect_memory_statistics = Off
;oci8.ping_interval = 60

; 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
; the same string for all web servers running the same application,
; the database pool must be configured, and the connection string must
Expand All @@ -1278,6 +1278,13 @@ mysqlnd.collect_memory_statistics = Off
; https://php.net/oci8.default-prefetch
;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
; oci_connect() and oci_new_connect() connections.
; https://php.net/oci8.old-oci-close-semantics
Expand Down

0 comments on commit 9cd7f41

Please sign in to comment.