Skip to content

Commit 9cd7f41

Browse files
committed
Add oci8.prefetch_lob_size
1 parent e96f980 commit 9cd7f41

11 files changed

+226
-23
lines changed

NEWS

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ PHP NEWS
88
- Core:
99
. Fixed bug #81380 (Observer may not be initialized properly). (krakjoe)
1010

11+
- OCI8:
12+
. Added oci8.prefetch_lob_size directive to tune LOB query performance
13+
1114
- Zip:
1215
. add ZipArchive::clearError() method
1316
. add ZipArchive::getStreamName() method

UPGRADING

+5
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ PHP 8.2 UPGRADE NOTES
2727
. Added CURLINFO_EFFECTIVE_METHOD option and returning the effective
2828
HTTP method in curl_getinfo() return value.
2929

30+
- OCI8:
31+
. Added an oci8.prefetch_lob_size directive to tune LOB query performance
32+
by reducing the number of round-trips between PHP and Oracle Database when
33+
fetching LOBS. This is usable with Oracle Database 12.2 or later.
34+
3035
- PCRE:
3136
. Added support for the "n" (NO_AUTO_CAPTURE) modifier, which makes simple
3237
`(xyz)` groups non-capturing. Only named groups like `(?<name>xyz)` are

ext/oci8/oci8.c

+1
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ PHP_INI_BEGIN()
174174
#if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2)))
175175
STD_PHP_INI_BOOLEAN("oci8.events", "0", PHP_INI_SYSTEM, OnUpdateBool, events, zend_oci_globals, oci_globals)
176176
#endif
177+
STD_PHP_INI_ENTRY( "oci8.prefetch_lob_size", "0", PHP_INI_ALL, OnUpdateLong, prefetch_lob_size, zend_oci_globals, oci_globals)
177178
PHP_INI_END()
178179
/* }}} */
179180

ext/oci8/oci8_statement.c

+11-11
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ int php_oci_statement_fetch(php_oci_statement *statement, ub4 nrows)
359359
if (errstatus == OCI_SUCCESS_WITH_INFO || errstatus == OCI_SUCCESS) {
360360
statement->has_data = 1;
361361

362-
/* do the stuff needed for OCIDefineByName */
362+
/* do the stuff needed for OCIDefineByPos */
363363
for (i = 0; i < statement->ncolumns; i++) {
364364
column = php_oci_statement_get_column(statement, i + 1, NULL, 0);
365365
if (column == NULL) {
@@ -794,7 +794,6 @@ int php_oci_statement_execute(php_oci_statement *statement, ub4 mode)
794794
OCI_DYNAMIC_FETCH /* IN mode (OCI_DEFAULT, OCI_DYNAMIC_FETCH) */
795795
)
796796
);
797-
798797
} else {
799798
PHP_OCI_CALL_RETURN(errstatus,
800799
OCIDefineByPos,
@@ -821,12 +820,19 @@ int php_oci_statement_execute(php_oci_statement *statement, ub4 mode)
821820
return 1;
822821
}
823822

824-
/* additional OCIDefineDynamic() call */
823+
/* additional define setup */
825824
switch (outcol->data_type) {
826-
case SQLT_RSET:
827-
case SQLT_RDD:
828825
case SQLT_BLOB:
829826
case SQLT_CLOB:
827+
if (OCI_G(prefetch_lob_size) > 0) {
828+
int get_lob_len = 1; /* == true */
829+
ub4 prefetch_size = OCI_G(prefetch_lob_size);
830+
PHP_OCI_CALL_RETURN(errstatus, OCIAttrSet, (outcol->oci_define, OCI_HTYPE_DEFINE, &get_lob_len, 0, OCI_ATTR_LOBPREFETCH_LENGTH, statement->err));
831+
PHP_OCI_CALL_RETURN(errstatus, OCIAttrSet, (outcol->oci_define, OCI_HTYPE_DEFINE, &prefetch_size, 0, OCI_ATTR_LOBPREFETCH_SIZE, statement->err));
832+
}
833+
ZEND_FALLTHROUGH;
834+
case SQLT_RSET:
835+
case SQLT_RDD:
830836
case SQLT_BFILE:
831837
PHP_OCI_CALL_RETURN(errstatus,
832838
OCIDefineDynamic,
@@ -1483,12 +1489,6 @@ sb4 php_oci_bind_out_callback(
14831489
ZVAL_STRINGL(val, p, PHP_OCI_PIECE_SIZE);
14841490
efree(p);
14851491
}
1486-
#if 0
1487-
Z_STRLEN_P(val) = PHP_OCI_PIECE_SIZE; /* 64K-1 is max XXX */
1488-
Z_STRVAL_P(val) = ecalloc(1, Z_STRLEN_P(val) + 1);
1489-
/* XXX is this right? */
1490-
ZVAL_STRINGL(val, NULL, Z_STRLEN(val) + 1);
1491-
#endif
14921492

14931493
/* XXX we assume that zend-zval len has 4 bytes */
14941494
*alenpp = (ub4*) &Z_STRLEN_P(val);

ext/oci8/package.xml

+21-4
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,12 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin
5353
<active>no</active>
5454
</lead>
5555

56-
<date>2021-08-02</date>
56+
<date>2021-11-15</date>
5757
<time>12:00:00</time>
5858

5959
<version>
60-
<release>3.1.0</release>
61-
<api>3.1.0</api>
60+
<release>3.2.0</release>
61+
<api>3.2.0</api>
6262
</version>
6363
<stability>
6464
<release>stable</release>
@@ -68,7 +68,7 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin
6868
<notes>
6969
This version is for PHP 8 only.
7070

71-
Deprecated directive oci8.old_oci_close_semantics
71+
Added oci8.prefetch_lob_size directive to improve LOB query performance.
7272
</notes>
7373
<contents>
7474
<dir name="/">
@@ -448,6 +448,23 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin
448448
</extsrcrelease>
449449
<changelog>
450450

451+
<release>
452+
<version>
453+
<release>3.1.0</release>
454+
<api>3.1.0</api>
455+
</version>
456+
<stability>
457+
<release>stable</release>
458+
<api>stable</api>
459+
</stability>
460+
<license uri="http://www.php.net/license">PHP</license>
461+
<notes>
462+
This version is for PHP 8 only.
463+
464+
Deprecated directive oci8.old_oci_close_semantics
465+
</notes>
466+
</release>
467+
451468
<release>
452469
<version>
453470
<release>3.0.1</release>

ext/oci8/php_oci8.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
*/
4242
#undef PHP_OCI8_VERSION
4343
#endif
44-
#define PHP_OCI8_VERSION "3.1.0"
44+
#define PHP_OCI8_VERSION "3.2.0"
4545

4646
extern zend_module_entry oci8_module_entry;
4747
#define phpext_oci8_ptr &oci8_module_entry

ext/oci8/php_oci8_int.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -519,9 +519,9 @@ ZEND_BEGIN_MODULE_GLOBALS(oci) /* {{{ Module globals */
519519
zend_long persistent_timeout; /* time period after which idle persistent connection is considered expired */
520520
zend_long statement_cache_size; /* statement cache size. used with 9i+ clients only*/
521521
zend_long default_prefetch; /* default prefetch setting */
522+
zend_long prefetch_lob_size; /* amount of LOB data to read when initially getting a LOB locator */
522523
bool privileged_connect; /* privileged connect flag (On/Off) */
523524
bool old_oci_close_semantics; /* old_oci_close_semantics flag (to determine the way oci_close() should behave) */
524-
525525
int shutdown; /* in shutdown flag */
526526

527527
OCIEnv *env; /* global environment handle */

ext/oci8/tests/driver_name.phpt

+3-3
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,11 @@ function get_attr($conn)
5757
?>
5858
--EXPECT--
5959
**Test 1.1 - Default values for the attribute **************
60-
The value of DRIVER_NAME is PHP OCI8 : 3.1.0
60+
The value of DRIVER_NAME is PHP OCI8 : 3.2.0
6161

6262
***Test 1.2 - Get the values from different connections **************
6363
Testing with oci_pconnect()
64-
The value of DRIVER_NAME is PHP OCI8 : 3.1.0
64+
The value of DRIVER_NAME is PHP OCI8 : 3.2.0
6565
Testing with oci_new_connect()
66-
The value of DRIVER_NAME is PHP OCI8 : 3.1.0
66+
The value of DRIVER_NAME is PHP OCI8 : 3.2.0
6767
Done

ext/oci8/tests/lob_prefetch.phpt

+163
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
--TEST--
2+
LOB prefetching
3+
--EXTENSIONS--
4+
oci8
5+
--SKIPIF--
6+
<?php
7+
$target_dbs = array('oracledb' => true, 'timesten' => false); // test runs on these DBs
8+
require(__DIR__.'/skipif.inc');
9+
?>
10+
--FILE--
11+
<?php
12+
13+
require __DIR__.'/connect.inc';
14+
require __DIR__.'/create_table.inc';
15+
16+
define("NUMROWS", 500);
17+
define("LOBSIZE", 64000);
18+
19+
$ora_sql =
20+
"declare
21+
c clob;
22+
b blob;
23+
numrows number := 500;
24+
dest_offset integer := 1;
25+
src_offset integer := 1;
26+
warn integer;
27+
ctx integer := dbms_lob.default_lang_ctx;
28+
begin
29+
for j in 1..numrows
30+
loop
31+
c := DBMS_RANDOM.string('L',TRUNC(DBMS_RANDOM.value(1000,1000)));
32+
for i in 1..6
33+
loop
34+
c := c||c;
35+
end loop;
36+
dbms_lob.createtemporary(b, false);
37+
dbms_lob.converttoblob(b, c, dbms_lob.lobmaxsize, dest_offset, src_offset, dbms_lob.default_csid, ctx, warn);
38+
insert /*+ APPEND */ into ${schema}${table_name} (id, clob, blob) values (j, c, b);
39+
end loop;
40+
commit;
41+
end;";
42+
43+
$statement = oci_parse($c,$ora_sql);
44+
oci_execute($statement);
45+
46+
47+
function get_clob_loc($c, $sql) {
48+
$stid = oci_parse($c, $sql);
49+
oci_execute($stid);
50+
$l = [];
51+
while (($row = oci_fetch_array($stid, OCI_ASSOC)) != false) {
52+
$l[] = $row['CLOB']->load();
53+
$row['CLOB']->free();
54+
if (strlen($l[0]) != LOBSIZE) { print("strlen(l) failure" . strlen($l)); exit; }
55+
}
56+
return($l);
57+
}
58+
59+
function get_clob_inline($c, $sql) {
60+
$stid = oci_parse($c, $sql);
61+
oci_execute($stid);
62+
$l = [];
63+
while (($row = oci_fetch_array($stid, OCI_ASSOC+OCI_RETURN_LOBS)) != false) {
64+
$l[] = $row['CLOB'];
65+
if (strlen($l[0]) != LOBSIZE) { print("strlen(l) failure" . strlen($l)); exit; }
66+
}
67+
return($l);
68+
}
69+
70+
function check_clobs($locarr, $inlinearr) {
71+
print("Comparing CLOBS\n");
72+
for ($i = 0; $i < NUMROWS; ++$i) {
73+
if (strlen($locarr[$i]) != LOBSIZE) {
74+
trigger_error("size mismatch at $i " . strlen($locarr[$i]), E_USER_ERROR);
75+
exit;
76+
}
77+
if (strcmp($locarr[$i], $inlinearr[$i])) {
78+
trigger_error("data mismatch at $i " . strlen($locarr[$i]) . " " . strlen($inlinearr[$i]), E_USER_ERROR);
79+
exit;
80+
}
81+
}
82+
}
83+
84+
function get_blob_loc($c, $sql) {
85+
$stid = oci_parse($c, $sql);
86+
oci_execute($stid);
87+
$l = [];
88+
while (($row = oci_fetch_array($stid, OCI_ASSOC)) != false) {
89+
$l[] = $row['BLOB']->load();
90+
$row['BLOB']->free();
91+
if (strlen($l[0]) != LOBSIZE) { print("strlen(l) failure" . strlen($l)); exit; }
92+
}
93+
return($l);
94+
}
95+
96+
97+
print("Test 1\n");
98+
99+
$ig = ini_get("oci8.prefetch_lob_size");
100+
var_dump($ig);
101+
102+
$ig = ini_set("oci8.prefetch_lob_size", "100000");
103+
var_dump($ig);
104+
105+
$ig = ini_get("oci8.prefetch_lob_size");
106+
var_dump($ig);
107+
108+
print("Test 2 - CLOB prefetch_lob_size 100000\n");
109+
110+
$sql = "select clob from ${schema}${table_name}" . " order by id";
111+
$locarr = get_clob_loc($c, $sql);
112+
$inlinearr = get_clob_inline($c, $sql);
113+
114+
print(count($locarr) . "\n");
115+
print(count($inlinearr) . "\n");
116+
check_clobs($locarr, $inlinearr);
117+
118+
print("Test 3 - CLOB prefetch_lob_size 100\n");
119+
120+
ini_set("oci8.prefetch_lob_size", "100");
121+
$ig = ini_get("oci8.prefetch_lob_size");
122+
var_dump($ig);
123+
124+
$locarr = get_clob_loc($c, $sql);
125+
$inlinearr = get_clob_inline($c, $sql);
126+
127+
print(count($locarr) . "\n");
128+
print(count($inlinearr) . "\n");
129+
check_clobs($locarr, $inlinearr);
130+
131+
print("Test 4 - BLOB prefetch_lob_size 100000\n");
132+
133+
ini_set("oci8.prefetch_lob_size", "100000");
134+
$ig = ini_get("oci8.prefetch_lob_size");
135+
var_dump($ig);
136+
137+
$sql = "select blob from ${schema}${table_name}" . " order by id";
138+
$locarr = get_blob_loc($c, $sql);
139+
140+
print(count($locarr) . "\n");
141+
142+
require __DIR__.'/drop_table.inc';
143+
144+
?>
145+
DONE
146+
--EXPECTF--
147+
Test 1
148+
string(1) "0"
149+
string(1) "0"
150+
string(6) "100000"
151+
Test 2 - CLOB prefetch_lob_size 100000
152+
500
153+
500
154+
Comparing CLOBS
155+
Test 3 - CLOB prefetch_lob_size 100
156+
string(3) "100"
157+
500
158+
500
159+
Comparing CLOBS
160+
Test 4 - BLOB prefetch_lob_size 100000
161+
string(6) "100000"
162+
500
163+
DONE

php.ini-development

+9-2
Original file line numberDiff line numberDiff line change
@@ -1254,7 +1254,7 @@ mysqlnd.collect_memory_statistics = On
12541254
;oci8.ping_interval = 60
12551255

12561256
; Connection: Set this to a user chosen connection class to be used
1257-
; for all pooled server requests with Oracle 11g Database Resident
1257+
; for all pooled server requests with Oracle Database Resident
12581258
; Connection Pooling (DRCP). To use DRCP, this value should be set to
12591259
; the same string for all web servers running the same application,
12601260
; the database pool must be configured, and the connection string must
@@ -1271,11 +1271,18 @@ mysqlnd.collect_memory_statistics = On
12711271
; https://php.net/oci8.statement-cache-size
12721272
;oci8.statement_cache_size = 20
12731273

1274-
; Tuning: Enables statement prefetching and sets the default number of
1274+
; Tuning: Enables row prefetching and sets the default number of
12751275
; rows that will be fetched automatically after statement execution.
12761276
; https://php.net/oci8.default-prefetch
12771277
;oci8.default_prefetch = 100
12781278

1279+
; Tuning: Sets the amount of LOB data that is internally returned from
1280+
; Oracle Database when an Oracle LOB locator is initially retrieved as
1281+
; part of a query. Setting this can improve performance by reducing
1282+
; round-trips.
1283+
; https://php.net/oci8.prefetch-lob-size
1284+
; oci8.prefetch_lob_size = 0
1285+
12791286
; Compatibility. Using On means oci_close() will not close
12801287
; oci_connect() and oci_new_connect() connections.
12811288
; https://php.net/oci8.old-oci-close-semantics

php.ini-production

+8-1
Original file line numberDiff line numberDiff line change
@@ -1256,7 +1256,7 @@ mysqlnd.collect_memory_statistics = Off
12561256
;oci8.ping_interval = 60
12571257

12581258
; Connection: Set this to a user chosen connection class to be used
1259-
; for all pooled server requests with Oracle 11g Database Resident
1259+
; for all pooled server requests with Oracle Database Resident
12601260
; Connection Pooling (DRCP). To use DRCP, this value should be set to
12611261
; the same string for all web servers running the same application,
12621262
; the database pool must be configured, and the connection string must
@@ -1278,6 +1278,13 @@ mysqlnd.collect_memory_statistics = Off
12781278
; https://php.net/oci8.default-prefetch
12791279
;oci8.default_prefetch = 100
12801280

1281+
; Tuning: Sets the amount of LOB data that is internally returned from
1282+
; Oracle Database when an Oracle LOB locator is initially retrieved as
1283+
; part of a query. Setting this can improve performance by reducing
1284+
; round-trips.
1285+
; https://php.net/oci8.prefetch-lob-size
1286+
; oci8.prefetch_lob_size = 0
1287+
12811288
; Compatibility. Using On means oci_close() will not close
12821289
; oci_connect() and oci_new_connect() connections.
12831290
; https://php.net/oci8.old-oci-close-semantics

0 commit comments

Comments
 (0)