summaryrefslogtreecommitdiff
path: root/ext/oci8
diff options
context:
space:
mode:
Diffstat (limited to 'ext/oci8')
-rw-r--r--ext/oci8/oci8.c15
-rw-r--r--ext/oci8/oci8_lob.c28
-rw-r--r--ext/oci8/php_oci8_int.h1
-rw-r--r--ext/oci8/tests/bug43497.phpt294
4 files changed, 327 insertions, 11 deletions
diff --git a/ext/oci8/oci8.c b/ext/oci8/oci8.c
index 01cc89b555..10731944b3 100644
--- a/ext/oci8/oci8.c
+++ b/ext/oci8/oci8.c
@@ -1645,7 +1645,10 @@ int php_oci_column_to_zval(php_oci_out_column *column, zval *value, int mode TSR
php_oci_descriptor *descriptor;
ub4 lob_length;
int column_size;
- zstr lob_buffer, zstr_data = ZSTR(column->data);
+ int lob_fetch_status;
+ zstr lob_buffer;
+ zstr zstr_data = ZSTR(column->data);
+ php_oci_lob_type lob_type;
if (column->indicator == -1) { /* column is NULL */
ZVAL_NULL(value);
@@ -1674,17 +1677,15 @@ int php_oci_column_to_zval(php_oci_out_column *column, zval *value, int mode TSR
}
if (column->data_type != SQLT_RDD && (mode & PHP_OCI_RETURN_LOBS)) {
- php_oci_lob_type lob_type;
/* PHP_OCI_RETURN_LOBS means that we want the content of the LOB back instead of the locator */
- if (php_oci_lob_read(descriptor, -1, 0, &lob_buffer, &lob_length TSRMLS_CC)) {
+ lob_fetch_status = php_oci_lob_read(descriptor, -1, 0, &lob_buffer, &lob_length TSRMLS_CC);
+ lob_fetch_status |= (php_oci_lob_get_type(descriptor, &lob_type TSRMLS_CC) > 0);
+ php_oci_temp_lob_close(descriptor);
+ if (lob_fetch_status) {
ZVAL_FALSE(value);
return 1;
}
-
- if (php_oci_lob_get_type(descriptor, &lob_type TSRMLS_CC) > 0) {
- return 1;
- }
switch (lob_type) {
case OCI_IS_CLOB:
diff --git a/ext/oci8/oci8_lob.c b/ext/oci8/oci8_lob.c
index 5206188c76..ea4577231d 100644
--- a/ext/oci8/oci8_lob.c
+++ b/ext/oci8/oci8_lob.c
@@ -575,7 +575,6 @@ int php_oci_lob_copy (php_oci_descriptor *descriptor_dest, php_oci_descriptor *d
int php_oci_lob_close (php_oci_descriptor *descriptor TSRMLS_DC)
{
php_oci_connection *connection = descriptor->connection;
- int is_temporary;
PHP_OCI_CALL_RETURN(connection->errcode, OCILobClose, (connection->svc, connection->err, descriptor->descriptor));
@@ -584,7 +583,21 @@ int php_oci_lob_close (php_oci_descriptor *descriptor TSRMLS_DC)
PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
return 1;
}
+
+ if (php_oci_temp_lob_close(descriptor)) {
+ return 1;
+ }
+ return 0;
+} /* }}} */
+
+/* {{{ php_oci_temp_lob_close()
+ Close Temporary LOB */
+int php_oci_temp_lob_close (php_oci_descriptor *descriptor TSRMLS_DC)
+{
+ php_oci_connection *connection = descriptor->connection;
+ int is_temporary;
+
PHP_OCI_CALL_RETURN(connection->errcode, OCILobIsTemporary, (connection->env,connection->err, descriptor->descriptor, &is_temporary));
if (connection->errcode != OCI_SUCCESS) {
@@ -594,7 +607,6 @@ int php_oci_lob_close (php_oci_descriptor *descriptor TSRMLS_DC)
}
if (is_temporary) {
-
PHP_OCI_CALL_RETURN(connection->errcode, OCILobFreeTemporary, (connection->svc, connection->err, descriptor->descriptor));
if (connection->errcode != OCI_SUCCESS) {
@@ -606,6 +618,7 @@ int php_oci_lob_close (php_oci_descriptor *descriptor TSRMLS_DC)
return 0;
} /* }}} */
+
/* {{{ php_oci_lob_flush()
Flush buffers for the LOB (only if they have been used) */
int php_oci_lob_flush(php_oci_descriptor *descriptor, long flush_flag TSRMLS_DC)
@@ -652,7 +665,6 @@ int php_oci_lob_flush(php_oci_descriptor *descriptor, long flush_flag TSRMLS_DC)
Close LOB descriptor and free associated resources */
void php_oci_lob_free (php_oci_descriptor *descriptor TSRMLS_DC)
{
-
if (!descriptor || !descriptor->connection) {
return;
}
@@ -667,6 +679,12 @@ void php_oci_lob_free (php_oci_descriptor *descriptor TSRMLS_DC)
php_oci_lob_flush(descriptor, OCI_LOB_BUFFER_FREE TSRMLS_CC);
}
+#ifdef HAVE_OCI8_TEMP_LOB
+ if (descriptor->type == OCI_DTYPE_LOB) {
+ php_oci_temp_lob_close(descriptor);
+ }
+#endif
+
PHP_OCI_CALL(OCIDescriptorFree, (descriptor->descriptor, descriptor->type));
zend_list_delete(descriptor->connection->rsrc_id);
@@ -899,7 +917,9 @@ int php_oci_lob_write_tmp (php_oci_descriptor *descriptor, ub1 type, zstr data,
return php_oci_lob_write(descriptor, 0, data, data_len, &bytes_written TSRMLS_CC);
} /* }}} */
-int php_oci_lob_get_type(php_oci_descriptor *descriptor, php_oci_lob_type *lob_type TSRMLS_DC) /* {{{ */
+/* {{{ php_oci_lob_get_type()
+ Determine whether LOB is a CLOB or a BLOB */
+int php_oci_lob_get_type(php_oci_descriptor *descriptor, php_oci_lob_type *lob_type TSRMLS_DC)
{
php_oci_connection *connection = descriptor->connection;
diff --git a/ext/oci8/php_oci8_int.h b/ext/oci8/php_oci8_int.h
index fc947026e5..b58e9fab59 100644
--- a/ext/oci8/php_oci8_int.h
+++ b/ext/oci8/php_oci8_int.h
@@ -352,6 +352,7 @@ int php_oci_lob_get_buffering (php_oci_descriptor *);
int php_oci_lob_copy (php_oci_descriptor *, php_oci_descriptor *, long TSRMLS_DC);
#ifdef HAVE_OCI8_TEMP_LOB
int php_oci_lob_close (php_oci_descriptor * TSRMLS_DC);
+int php_oci_temp_lob_close (php_oci_descriptor * TSRMLS_DC);
int php_oci_lob_write_tmp (php_oci_descriptor *, ub1, zstr, int TSRMLS_DC);
#endif
void php_oci_lob_free(php_oci_descriptor * TSRMLS_DC);
diff --git a/ext/oci8/tests/bug43497.phpt b/ext/oci8/tests/bug43497.phpt
new file mode 100644
index 0000000000..908fe58972
--- /dev/null
+++ b/ext/oci8/tests/bug43497.phpt
@@ -0,0 +1,294 @@
+--TEST--
+Bug #43497 (OCI8 XML/getClobVal aka temporary LOBs leak UGA memory)
+--SKIPIF--
+<?php if (!extension_loaded('oci8')) die ("skip no oci8 extension"); ?>
+--FILE--
+<?php
+
+require dirname(__FILE__).'/connect.inc';
+
+function sessionid($c) // determines and returns current session ID
+{
+ $query = "select sid from v\$session where audsid = userenv('sessionid')";
+
+ $stmt = oci_parse($c, $query);
+
+ if (oci_execute($stmt, OCI_DEFAULT)) {
+ $row = oci_fetch($stmt);
+ return oci_result($stmt, 1);
+ }
+
+ return null;
+}
+
+
+function templobs($c, $sid) // returns number of temporary LOBs
+{
+ $query = "select abstract_lobs from v\$temporary_lobs where sid = " . $sid;
+
+ $stmt = oci_parse($c, $query);
+
+ if (oci_execute($stmt, OCI_DEFAULT)) {
+ $row = oci_fetch($stmt);
+ $val = oci_result($stmt, 1);
+ oci_free_statement($stmt);
+ return $val;
+ }
+ return null;
+}
+
+
+// Read all XML data using explicit LOB locator
+function readxmltab_ex($c)
+{
+ $stmt = oci_parse($c, "select extract(xml, '/').getclobval() from bug43497_tab");
+
+ $cntchk = 0;
+ if (oci_execute($stmt)) {
+ while ($result = oci_fetch_array($stmt, OCI_NUM)) {
+ $result[0]->free(); // cleanup properly
+ ++$cntchk;
+ }
+ }
+ echo "Loop count check = $cntchk\n";
+}
+
+// Read all XML data using explicit LOB locator but without freeing the temp lobs
+function readxmltab_ex_nofree($c)
+{
+ $stmt = oci_parse($c, "select extract(xml, '/').getclobval() from bug43497_tab");
+
+ $cntchk = 0;
+ if (oci_execute($stmt)) {
+ while ($result = oci_fetch_array($stmt, OCI_NUM)) {
+ ++$cntchk;
+ }
+ }
+ echo "Loop count check = $cntchk\n";
+}
+
+// Read all XML data using implicit LOB locator
+function readxmltab_im($c)
+{
+ $stmt = oci_parse($c, "select extract(xml, '/').getclobval() from bug43497_tab");
+
+ $cntchk = 0;
+ if (oci_execute($stmt)) {
+ while ($result = oci_fetch_array($stmt, OCI_NUM+OCI_RETURN_LOBS)) {
+ ++$cntchk;
+ }
+ }
+ echo "Loop count check = $cntchk\n";
+}
+
+function createxmltab($c) // create table w/ field of XML type
+{
+ @dropxmltab($c);
+ $stmt = oci_parse($c, "create table bug43497_tab (id number primary key, xml xmltype)");
+ oci_execute($stmt);
+}
+
+function dropxmltab($c) // delete table
+{
+ $stmt = oci_parse($c, "drop table bug43497_tab");
+ oci_execute($stmt);
+}
+
+
+function fillxmltab($c)
+{
+ for ($id = 1; $id <= 100; $id++) {
+
+ // create an XML element string with random data
+ $s = "<data>";
+ for ($j = 0; $j < 128; $j++) {
+ $s .= rand();
+ }
+ $s .= "</data>\n";
+ for ($j = 0; $j < 4; $j++) {
+ $s .= $s;
+ }
+ $data = "<?xml version=\"1.0\"?><records>" . $s . "</records>";
+
+ // insert XML data into database
+
+ $stmt = oci_parse($c, "insert into bug43497_tab(id, xml) values (:id, sys.xmltype.createxml(:xml))");
+ oci_bind_by_name($stmt, ":id", $id);
+ $clob = oci_new_descriptor($c, OCI_D_LOB);
+ oci_bind_by_name($stmt, ":xml", $clob, -1, OCI_B_CLOB);
+ $clob->writetemporary($data);
+ oci_execute($stmt);
+
+ $clob->close();
+ $clob->free();
+ }
+}
+
+
+// Initialize
+
+createxmltab($c);
+fillxmltab($c);
+
+// Run Test
+
+$sid = sessionid($c);
+
+echo "Explicit LOB use\n";
+for ($i = 1; $i <= 10; $i++) {
+ echo "\nRun = " . $i . "\n";
+ echo "Temporary LOBs = " . templobs($c, $sid) . "\n";
+ readxmltab_ex($c);
+}
+
+echo "\nImplicit LOB use\n";
+for ($i = 1; $i <= 10; $i++) {
+ echo "\nRun = " . $i . "\n";
+ echo "Temporary LOBs = " . templobs($c, $sid) . "\n";
+ readxmltab_im($c);
+}
+
+echo "\nExplicit LOB with no free (i.e. a temp lob leak)\n";
+for ($i = 1; $i <= 10; $i++) {
+ echo "\nRun = " . $i . "\n";
+ echo "Temporary LOBs = " . templobs($c, $sid) . "\n";
+ readxmltab_ex_nofree($c);
+}
+
+
+
+// Cleanup
+
+dropxmltab($c);
+
+oci_close($c);
+
+echo "Done\n";
+?>
+--EXPECT--
+Explicit LOB use
+
+Run = 1
+Temporary LOBs = 0
+Loop count check = 100
+
+Run = 2
+Temporary LOBs = 0
+Loop count check = 100
+
+Run = 3
+Temporary LOBs = 0
+Loop count check = 100
+
+Run = 4
+Temporary LOBs = 0
+Loop count check = 100
+
+Run = 5
+Temporary LOBs = 0
+Loop count check = 100
+
+Run = 6
+Temporary LOBs = 0
+Loop count check = 100
+
+Run = 7
+Temporary LOBs = 0
+Loop count check = 100
+
+Run = 8
+Temporary LOBs = 0
+Loop count check = 100
+
+Run = 9
+Temporary LOBs = 0
+Loop count check = 100
+
+Run = 10
+Temporary LOBs = 0
+Loop count check = 100
+
+Implicit LOB use
+
+Run = 1
+Temporary LOBs = 0
+Loop count check = 100
+
+Run = 2
+Temporary LOBs = 0
+Loop count check = 100
+
+Run = 3
+Temporary LOBs = 0
+Loop count check = 100
+
+Run = 4
+Temporary LOBs = 0
+Loop count check = 100
+
+Run = 5
+Temporary LOBs = 0
+Loop count check = 100
+
+Run = 6
+Temporary LOBs = 0
+Loop count check = 100
+
+Run = 7
+Temporary LOBs = 0
+Loop count check = 100
+
+Run = 8
+Temporary LOBs = 0
+Loop count check = 100
+
+Run = 9
+Temporary LOBs = 0
+Loop count check = 100
+
+Run = 10
+Temporary LOBs = 0
+Loop count check = 100
+
+Explicit LOB with no free (i.e. a temp lob leak)
+
+Run = 1
+Temporary LOBs = 0
+Loop count check = 100
+
+Run = 2
+Temporary LOBs = 99
+Loop count check = 100
+
+Run = 3
+Temporary LOBs = 198
+Loop count check = 100
+
+Run = 4
+Temporary LOBs = 297
+Loop count check = 100
+
+Run = 5
+Temporary LOBs = 396
+Loop count check = 100
+
+Run = 6
+Temporary LOBs = 495
+Loop count check = 100
+
+Run = 7
+Temporary LOBs = 594
+Loop count check = 100
+
+Run = 8
+Temporary LOBs = 693
+Loop count check = 100
+
+Run = 9
+Temporary LOBs = 792
+Loop count check = 100
+
+Run = 10
+Temporary LOBs = 891
+Loop count check = 100
+Done