|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2007-08-31 15:46 UTC] iddekingej at lycos dot com
Description:
------------
When a query contains 2 clob fields then the cursor is not closed after oci_free_statement.
I run the attached script with the following table
tblDocuments
(id number
,v1 clob
,v2 clob
)
After a while the script gives a ora-01000 (maximum number of open cursors).
When tblDocuments contains only one clob field, the script keeps running fine.
I can monitor opencursors with the following script:
select a.value, s.username, s.sid, s.serial#
from v$sesstat a, v$statname b, v$session s
where a.statistic# = b.statistic# and s.sid=a.sid
and b.name = 'opened cursors current
When I monitor the script and tblDocuments has 2 clobs, the opencursor increases until maximum number of cursors is reached and the script failes with a ora -0100.
When I momitor the script and tblDocument has 1 clob, the number of script stays about the same.
The versions are
Windows 2000 server
Oracle 10.2.0.2 on the same machine
PHP 5.2.4 (File downloaded from php site)
Apache 2.2
Maximum number of cursors is 500
Version 5.2.2 and 5.2.3 has the same problem.
When I enable debug I get the following information
OCI8 DEBUG: OCIHandleAlloc at (ext\oci8\oci8_statement.c:61)
OCI8 DEBUG: OCIStmtPrepare2 at (ext\oci8\oci8_statement.c:77)
OCI8 DEBUG: OCIAttrSet at (ext\oci8\oci8_statement.c:135)
OCI8 DEBUG: OCIAttrSet at (ext\oci8\oci8_statement.c:144)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:418)
OCI8 DEBUG: OCIStmtExecute at (ext\oci8\oci8_statement.c:442)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:471)
OCI8 DEBUG: OCIParamGet at (ext\oci8\oci8_statement.c:491)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:500)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:510)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:520)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:530)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:543)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:553)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:563)
OCI8 DEBUG: OCIDescriptorFree at (ext\oci8\oci8_statement.c:571)
OCI8 DEBUG: OCIDefineByPos at (ext\oci8\oci8_statement.c:694)
OCI8 DEBUG: OCIParamGet at (ext\oci8\oci8_statement.c:491)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:500)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:510)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:520)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:530)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:543)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:553)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:563)
OCI8 DEBUG: OCIDescriptorFree at (ext\oci8\oci8_statement.c:571)
OCI8 DEBUG: OCIDefineByPos at (ext\oci8\oci8_statement.c:676)
OCI8 DEBUG: OCIDefineDynamic at (ext\oci8\oci8_statement.c:719)
OCI8 DEBUG: OCIParamGet at (ext\oci8\oci8_statement.c:491)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:500)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:510)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:520)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:530)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:543)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:553)
OCI8 DEBUG: OCIAttrGet at (ext\oci8\oci8_statement.c:563)
OCI8 DEBUG: OCIDescriptorFree at (ext\oci8\oci8_statement.c:571)
OCI8 DEBUG: OCIDefineByPos at (ext\oci8\oci8_statement.c:676)
OCI8 DEBUG: OCIDefineDynamic at (ext\oci8\oci8_statement.c:719)
OCI8 DEBUG: OCIStmtFetch at (ext\oci8\oci8_statement.c:168)
OCI8 DEBUG: OCIStmtRelease at (ext\oci8\oci8_statement.c:746)
OCI8 DEBUG: OCIHandleFree at (ext\oci8\oci8_statement.c:757)
OCI8 DEBUG: OCISessionEnd at (ext\oci8\oci8.c:1523)
OCI8 DEBUG: OCIHandleFree at (ext\oci8\oci8.c:1527)
OCI8 DEBUG: OCIServerDetach at (ext\oci8\oci8.c:1531)
OCI8 DEBUG: OCIHandleFree at (ext\oci8\oci8.c:1535)
OCI8 DEBUG: OCIHandleFree at (ext\oci8\oci8.c:1539)
OCI8 DEBUG: OCIHandleFree at (ext\oci8\oci8.c:1543)
OCI8 DEBUG: OCIHandleFree at (ext\oci8\oci8.c:1547)
OCI8 DEBUG: OCIHandleFree at (ext\oci8\oci8.c:461)
OCI8 DEBUG: OCIHandleFree at (ext\oci8\oci8.c:466)
Reproduce code:
---------------
$l_res=oci_new_connect("<username>","<password>","<sid>");
oci_execute($l_st);
while(1){
$l_cnt++;
$l_st=oci_parse($l_res,"select * from tblDocuments where id=$l_cnt ");
oci_execute($l_st);
$l_row=oci_fetch_row($l_st);
oci_free_statement($l_st);
echo $l_cnt,':';print_r($l_row);
}
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Fri Oct 24 20:00:01 2025 UTC |
Sorry "$l_cnt=0" is missing from the code. It should read: $l_res=oci_new_connect("<username>","<password>","<sid>"); oci_execute($l_st); $l_cnt=0; while(1){ $l_cnt++; $l_st=oci_parse($l_res,"select * from tblDocuments where id=$l_cnt "); oci_execute($l_st); $l_row=oci_fetch_row($l_st); oci_free_statement($l_st); echo $l_cnt,':';print_r($l_row); }This was reproduced with 5.2.3 on Linux. Please try this patch AND LET US KNOW THE RESULT - thanks! In php_oci_define_callback function [oci8_statement.c], zend_list_addref is called for every lob column of each row. When we commented out this increment, the statements were destroyed and no cursor leaks were seen. case SQLT_RDD: case SQLT_BLOB: case SQLT_CLOB: case SQLT_BFILE: { ... descr = php_oci_lob_create(outcol->statement->connection, dtype TSRMLS_CC); if (!descr) { return OCI_ERROR; } /*zend_list_addref(outcol->statement->id); Commented out */I tried to remove "zend_list_addref(outcol->statement->id);" from SQLT_RSET in php_oci_define_callback function() as well, but that doesn't work really well. It seemed to work at first, but it creates problems when returning the cursor from a function, because it leads to "ORA-01001: invalid cursor" when i try to fetch from the returned cursor. Testcase: <?php $conn = ocilogon('user', 'pass', 'db'); function fetch($conn, $id) { $result = null; $stmt = ociparse($conn, 'select cursor(select * from dual) c from dual'); ociexecute($stmt, OCI_DEFAULT); ocifetchinto($stmt, $result, OCI_ASSOC); ociexecute($result['C'], OCI_DEFAULT); return $result['C']; } for ($id = 1; $id <= 300; $id++) { $cur = fetch($conn, $id); ocifetchinto($cur, $row, OCI_ASSOC); ocifreestatement($cur); } ?> When i run the code above without removing "zend_list_addref(outcol->statement->id);" from SQLT_RSET i have the problem, that i get an "ORA-01000: maximum open cursors exceeded", because the statement within the function doesn't get closed. I don't know if that can be implemented easily, but the best thing would be, that a cursor gets closed if it is already out of scope and therefore not accessible from the php-code anymore and all nested cursors got closed already.