"TYPO3 4.0.1: typo3_src-4.0.1/typo3/sysext/adodb/adodb/drivers/adodb-oci8.inc.php Source File", "datetime" => "Sat Dec 2 19:22:26 2006", "date" => "2 Dec 2006", "doxygenversion" => "1.4.6", "projectname" => "TYPO3 4.0.1", "projectnumber" => "4.0.1" ); get_header($doxygen_vars); ?>
00001 <?php 00002 /* 00003 00004 version V4.90 8 June 2006 (c) 2000-2006 John Lim. All rights reserved. 00005 00006 Released under both BSD license and Lesser GPL library license. 00007 Whenever there is any discrepancy between the two licenses, 00008 the BSD license will take precedence. 00009 00010 Latest version is available at http://adodb.sourceforge.net 00011 00012 Code contributed by George Fourlanos <fou@infomap.gr> 00013 00014 13 Nov 2000 jlim - removed all ora_* references. 00015 */ 00016 00017 // security - hide paths 00018 if (!defined('ADODB_DIR')) die(); 00019 00020 /* 00021 NLS_Date_Format 00022 Allows you to use a date format other than the Oracle Lite default. When a literal 00023 character string appears where a date value is expected, the Oracle Lite database 00024 tests the string to see if it matches the formats of Oracle, SQL-92, or the value 00025 specified for this parameter in the POLITE.INI file. Setting this parameter also 00026 defines the default format used in the TO_CHAR or TO_DATE functions when no 00027 other format string is supplied. 00028 00029 For Oracle the default is dd-mon-yy or dd-mon-yyyy, and for SQL-92 the default is 00030 yy-mm-dd or yyyy-mm-dd. 00031 00032 Using 'RR' in the format forces two-digit years less than or equal to 49 to be 00033 interpreted as years in the 21st century (2000–2049), and years over 50 as years in 00034 the 20th century (1950–1999). Setting the RR format as the default for all two-digit 00035 year entries allows you to become year-2000 compliant. For example: 00036 NLS_DATE_FORMAT='RR-MM-DD' 00037 00038 You can also modify the date format using the ALTER SESSION command. 00039 */ 00040 00041 # define the LOB descriptor type for the given type 00042 # returns false if no LOB descriptor 00043 function oci_lob_desc($type) { 00044 switch ($type) { 00045 case OCI_B_BFILE: $result = OCI_D_FILE; break; 00046 case OCI_B_CFILEE: $result = OCI_D_FILE; break; 00047 case OCI_B_CLOB: $result = OCI_D_LOB; break; 00048 case OCI_B_BLOB: $result = OCI_D_LOB; break; 00049 case OCI_B_ROWID: $result = OCI_D_ROWID; break; 00050 default: $result = false; break; 00051 } 00052 return $result; 00053 } 00054 00055 class ADODB_oci8 extends ADOConnection { 00056 var $databaseType = 'oci8'; 00057 var $dataProvider = 'oci8'; 00058 var $replaceQuote = "''"; // string to use to replace quotes 00059 var $concat_operator='||'; 00060 var $sysDate = "TRUNC(SYSDATE)"; 00061 var $sysTimeStamp = 'SYSDATE'; 00062 var $metaDatabasesSQL = "SELECT USERNAME FROM ALL_USERS WHERE USERNAME NOT IN ('SYS','SYSTEM','DBSNMP','OUTLN') ORDER BY 1"; 00063 var $_stmt; 00064 var $_commit = OCI_COMMIT_ON_SUCCESS; 00065 var $_initdate = true; // init date to YYYY-MM-DD 00066 var $metaTablesSQL = "select table_name,table_type from cat where table_type in ('TABLE','VIEW')"; 00067 var $metaColumnsSQL = "select cname,coltype,width, SCALE, PRECISION, NULLS, DEFAULTVAL from col where tname='%s' order by colno"; //changed by smondino@users.sourceforge. net 00068 var $_bindInputArray = true; 00069 var $hasGenID = true; 00070 var $_genIDSQL = "SELECT (%s.nextval) FROM DUAL"; 00071 var $_genSeqSQL = "CREATE SEQUENCE %s START WITH %s"; 00072 var $_dropSeqSQL = "DROP SEQUENCE %s"; 00073 var $hasAffectedRows = true; 00074 var $random = "abs(mod(DBMS_RANDOM.RANDOM,10000001)/10000000)"; 00075 var $noNullStrings = false; 00076 var $connectSID = false; 00077 var $_bind = false; 00078 var $_hasOCIFetchStatement = false; 00079 var $_getarray = false; // currently not working 00080 var $leftOuter = ''; // oracle wierdness, $col = $value (+) for LEFT OUTER, $col (+)= $value for RIGHT OUTER 00081 var $session_sharing_force_blob = false; // alter session on updateblob if set to true 00082 var $firstrows = true; // enable first rows optimization on SelectLimit() 00083 var $selectOffsetAlg1 = 100; // when to use 1st algorithm of selectlimit. 00084 var $NLS_DATE_FORMAT = 'YYYY-MM-DD'; // To include time, use 'RRRR-MM-DD HH24:MI:SS' 00085 var $useDBDateFormatForTextInput=false; 00086 var $datetime = false; // MetaType('DATE') returns 'D' (datetime==false) or 'T' (datetime == true) 00087 var $_refLOBs = array(); 00088 00089 // var $ansiOuter = true; // if oracle9 00090 00091 function ADODB_oci8() 00092 { 00093 $this->_hasOCIFetchStatement = ADODB_PHPVER >= 0x4200; 00094 if (defined('ADODB_EXTENSION')) $this->rsPrefix .= 'ext_'; 00095 } 00096 00097 /* Function &MetaColumns($table) added by smondino@users.sourceforge.net*/ 00098 function &MetaColumns($table) 00099 { 00100 global $ADODB_FETCH_MODE; 00101 00102 $false = false; 00103 $save = $ADODB_FETCH_MODE; 00104 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 00105 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false); 00106 00107 $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table)); 00108 00109 if (isset($savem)) $this->SetFetchMode($savem); 00110 $ADODB_FETCH_MODE = $save; 00111 if (!$rs) { 00112 return $false; 00113 } 00114 $retarr = array(); 00115 while (!$rs->EOF) { //print_r($rs->fields); 00116 $fld = new ADOFieldObject(); 00117 $fld->name = $rs->fields[0]; 00118 $fld->type = $rs->fields[1]; 00119 $fld->max_length = $rs->fields[2]; 00120 $fld->scale = $rs->fields[3]; 00121 if ($rs->fields[1] == 'NUMBER' && $rs->fields[3] == 0) { 00122 $fld->type ='INT'; 00123 $fld->max_length = $rs->fields[4]; 00124 } 00125 $fld->not_null = (strncmp($rs->fields[5], 'NOT',3) === 0); 00126 $fld->binary = (strpos($fld->type,'BLOB') !== false); 00127 $fld->default_value = $rs->fields[6]; 00128 00129 if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld; 00130 else $retarr[strtoupper($fld->name)] = $fld; 00131 $rs->MoveNext(); 00132 } 00133 $rs->Close(); 00134 if (empty($retarr)) 00135 return $false; 00136 else 00137 return $retarr; 00138 } 00139 00140 function Time() 00141 { 00142 $rs =& $this->Execute("select TO_CHAR($this->sysTimeStamp,'YYYY-MM-DD HH24:MI:SS') from dual"); 00143 if ($rs && !$rs->EOF) return $this->UnixTimeStamp(reset($rs->fields)); 00144 00145 return false; 00146 } 00147 00148 /* 00149 00150 Multiple modes of connection are supported: 00151 00152 a. Local Database 00153 $conn->Connect(false,'scott','tiger'); 00154 00155 b. From tnsnames.ora 00156 $conn->Connect(false,'scott','tiger',$tnsname); 00157 $conn->Connect($tnsname,'scott','tiger'); 00158 00159 c. Server + service name 00160 $conn->Connect($serveraddress,'scott,'tiger',$service_name); 00161 00162 d. Server + SID 00163 $conn->connectSID = true; 00164 $conn->Connect($serveraddress,'scott,'tiger',$SID); 00165 00166 00167 Example TNSName: 00168 --------------- 00169 NATSOFT.DOMAIN = 00170 (DESCRIPTION = 00171 (ADDRESS_LIST = 00172 (ADDRESS = (PROTOCOL = TCP)(HOST = kermit)(PORT = 1523)) 00173 ) 00174 (CONNECT_DATA = 00175 (SERVICE_NAME = natsoft.domain) 00176 ) 00177 ) 00178 00179 There are 3 connection modes, 0 = non-persistent, 1 = persistent, 2 = force new connection 00180 00181 */ 00182 function _connect($argHostname, $argUsername, $argPassword, $argDatabasename,$mode=0) 00183 { 00184 if (!function_exists('OCIPLogon')) return null; 00185 00186 00187 $this->_errorMsg = false; 00188 $this->_errorCode = false; 00189 00190 if($argHostname) { // added by Jorma Tuomainen <jorma.tuomainen@ppoy.fi> 00191 if (empty($argDatabasename)) $argDatabasename = $argHostname; 00192 else { 00193 if(strpos($argHostname,":")) { 00194 $argHostinfo=explode(":",$argHostname); 00195 $argHostname=$argHostinfo[0]; 00196 $argHostport=$argHostinfo[1]; 00197 } else { 00198 $argHostport = empty($this->port)? "1521" : $this->port; 00199 } 00200 00201 if ($this->connectSID) { 00202 $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname 00203 .")(PORT=$argHostport))(CONNECT_DATA=(SID=$argDatabasename)))"; 00204 } else 00205 $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname 00206 .")(PORT=$argHostport))(CONNECT_DATA=(SERVICE_NAME=$argDatabasename)))"; 00207 } 00208 } 00209 00210 //if ($argHostname) print "<p>Connect: 1st argument should be left blank for $this->databaseType</p>"; 00211 if ($mode==1) { 00212 $this->_connectionID = ($this->charSet) ? 00213 OCIPLogon($argUsername,$argPassword, $argDatabasename) 00214 : 00215 OCIPLogon($argUsername,$argPassword, $argDatabasename, $this->charSet) 00216 ; 00217 if ($this->_connectionID && $this->autoRollback) OCIrollback($this->_connectionID); 00218 } else if ($mode==2) { 00219 $this->_connectionID = ($this->charSet) ? 00220 OCINLogon($argUsername,$argPassword, $argDatabasename) 00221 : 00222 OCINLogon($argUsername,$argPassword, $argDatabasename, $this->charSet); 00223 00224 } else { 00225 $this->_connectionID = ($this->charSet) ? 00226 OCILogon($argUsername,$argPassword, $argDatabasename) 00227 : 00228 OCILogon($argUsername,$argPassword, $argDatabasename,$this->charSet); 00229 } 00230 if (!$this->_connectionID) return false; 00231 if ($this->_initdate) { 00232 $this->Execute("ALTER SESSION SET NLS_DATE_FORMAT='".$this->NLS_DATE_FORMAT."'"); 00233 } 00234 00235 // looks like: 00236 // Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production With the Partitioning option JServer Release 8.1.7.0.0 - Production 00237 // $vers = OCIServerVersion($this->_connectionID); 00238 // if (strpos($vers,'8i') !== false) $this->ansiOuter = true; 00239 return true; 00240 } 00241 00242 function ServerInfo() 00243 { 00244 $arr['compat'] = $this->GetOne('select value from sys.database_compatible_level'); 00245 $arr['description'] = @OCIServerVersion($this->_connectionID); 00246 $arr['version'] = ADOConnection::_findvers($arr['description']); 00247 return $arr; 00248 } 00249 // returns true or false 00250 function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) 00251 { 00252 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,1); 00253 } 00254 00255 // returns true or false 00256 function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename) 00257 { 00258 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,2); 00259 } 00260 00261 function _affectedrows() 00262 { 00263 if (is_resource($this->_stmt)) return @OCIRowCount($this->_stmt); 00264 return 0; 00265 } 00266 00267 function IfNull( $field, $ifNull ) 00268 { 00269 return " NVL($field, $ifNull) "; // if Oracle 00270 } 00271 00272 // format and return date string in database date format 00273 function DBDate($d) 00274 { 00275 if (empty($d) && $d !== 0) return 'null'; 00276 00277 if (is_string($d)) $d = ADORecordSet::UnixDate($d); 00278 return "TO_DATE(".adodb_date($this->fmtDate,$d).",'".$this->NLS_DATE_FORMAT."')"; 00279 } 00280 00281 function BindDate($d) 00282 { 00283 $d = ADOConnection::DBDate($d); 00284 if (strncmp($d,"'",1)) return $d; 00285 00286 return substr($d,1,strlen($d)-2); 00287 } 00288 00289 function BindTimeStamp($d) 00290 { 00291 $d = ADOConnection::DBTimeStamp($d); 00292 if (strncmp($d,"'",1)) return $d; 00293 00294 return substr($d,1,strlen($d)-2); 00295 } 00296 00297 // format and return date string in database timestamp format 00298 function DBTimeStamp($ts) 00299 { 00300 if (empty($ts) && $ts !== 0) return 'null'; 00301 if (is_string($ts)) $ts = ADORecordSet::UnixTimeStamp($ts); 00302 return 'TO_DATE('.adodb_date($this->fmtTimeStamp,$ts).",'RRRR-MM-DD, HH:MI:SS AM')"; 00303 } 00304 00305 function RowLock($tables,$where,$flds='1 as ignore') 00306 { 00307 if ($this->autoCommit) $this->BeginTrans(); 00308 return $this->GetOne("select $flds from $tables where $where for update"); 00309 } 00310 00311 function &MetaTables($ttype=false,$showSchema=false,$mask=false) 00312 { 00313 if ($mask) { 00314 $save = $this->metaTablesSQL; 00315 $mask = $this->qstr(strtoupper($mask)); 00316 $this->metaTablesSQL .= " AND upper(table_name) like $mask"; 00317 } 00318 $ret =& ADOConnection::MetaTables($ttype,$showSchema); 00319 00320 if ($mask) { 00321 $this->metaTablesSQL = $save; 00322 } 00323 return $ret; 00324 } 00325 00326 // Mark Newnham 00327 function &MetaIndexes ($table, $primary = FALSE, $owner=false) 00328 { 00329 // save old fetch mode 00330 global $ADODB_FETCH_MODE; 00331 00332 $save = $ADODB_FETCH_MODE; 00333 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 00334 00335 if ($this->fetchMode !== FALSE) { 00336 $savem = $this->SetFetchMode(FALSE); 00337 } 00338 00339 // get index details 00340 $table = strtoupper($table); 00341 00342 // get Primary index 00343 $primary_key = ''; 00344 00345 $false = false; 00346 $rs = $this->Execute(sprintf("SELECT * FROM ALL_CONSTRAINTS WHERE UPPER(TABLE_NAME)='%s' AND CONSTRAINT_TYPE='P'",$table)); 00347 if ($row = $rs->FetchRow()) 00348 $primary_key = $row[1]; //constraint_name 00349 00350 if ($primary==TRUE && $primary_key=='') { 00351 if (isset($savem)) 00352 $this->SetFetchMode($savem); 00353 $ADODB_FETCH_MODE = $save; 00354 return $false; //There is no primary key 00355 } 00356 00357 $rs = $this->Execute(sprintf("SELECT ALL_INDEXES.INDEX_NAME, ALL_INDEXES.UNIQUENESS, ALL_IND_COLUMNS.COLUMN_POSITION, ALL_IND_COLUMNS.COLUMN_NAME FROM ALL_INDEXES,ALL_IND_COLUMNS WHERE UPPER(ALL_INDEXES.TABLE_NAME)='%s' AND ALL_IND_COLUMNS.INDEX_NAME=ALL_INDEXES.INDEX_NAME",$table)); 00358 00359 00360 if (!is_object($rs)) { 00361 if (isset($savem)) 00362 $this->SetFetchMode($savem); 00363 $ADODB_FETCH_MODE = $save; 00364 return $false; 00365 } 00366 00367 $indexes = array (); 00368 // parse index data into array 00369 00370 while ($row = $rs->FetchRow()) { 00371 if ($primary && $row[0] != $primary_key) continue; 00372 if (!isset($indexes[$row[0]])) { 00373 $indexes[$row[0]] = array( 00374 'unique' => ($row[1] == 'UNIQUE'), 00375 'columns' => array() 00376 ); 00377 } 00378 $indexes[$row[0]]['columns'][$row[2] - 1] = $row[3]; 00379 } 00380 00381 // sort columns by order in the index 00382 foreach ( array_keys ($indexes) as $index ) { 00383 ksort ($indexes[$index]['columns']); 00384 } 00385 00386 if (isset($savem)) { 00387 $this->SetFetchMode($savem); 00388 $ADODB_FETCH_MODE = $save; 00389 } 00390 return $indexes; 00391 } 00392 00393 function BeginTrans() 00394 { 00395 if ($this->transOff) return true; 00396 $this->transCnt += 1; 00397 $this->autoCommit = false; 00398 $this->_commit = OCI_DEFAULT; 00399 00400 if ($this->_transmode) $this->Execute("SET TRANSACTION ".$this->_transmode); 00401 return true; 00402 } 00403 00404 function CommitTrans($ok=true) 00405 { 00406 if ($this->transOff) return true; 00407 if (!$ok) return $this->RollbackTrans(); 00408 00409 if ($this->transCnt) $this->transCnt -= 1; 00410 $ret = OCIcommit($this->_connectionID); 00411 $this->_commit = OCI_COMMIT_ON_SUCCESS; 00412 $this->autoCommit = true; 00413 return $ret; 00414 } 00415 00416 function RollbackTrans() 00417 { 00418 if ($this->transOff) return true; 00419 if ($this->transCnt) $this->transCnt -= 1; 00420 $ret = OCIrollback($this->_connectionID); 00421 $this->_commit = OCI_COMMIT_ON_SUCCESS; 00422 $this->autoCommit = true; 00423 return $ret; 00424 } 00425 00426 00427 function SelectDB($dbName) 00428 { 00429 return false; 00430 } 00431 00432 function ErrorMsg() 00433 { 00434 if ($this->_errorMsg !== false) return $this->_errorMsg; 00435 00436 if (is_resource($this->_stmt)) $arr = @OCIerror($this->_stmt); 00437 if (empty($arr)) { 00438 $arr = @OCIerror($this->_connectionID); 00439 if ($arr === false) $arr = @OCIError(); 00440 if ($arr === false) return ''; 00441 } 00442 $this->_errorMsg = $arr['message']; 00443 $this->_errorCode = $arr['code']; 00444 return $this->_errorMsg; 00445 } 00446 00447 function ErrorNo() 00448 { 00449 if ($this->_errorCode !== false) return $this->_errorCode; 00450 00451 if (is_resource($this->_stmt)) $arr = @OCIError($this->_stmt); 00452 if (empty($arr)) { 00453 $arr = @OCIError($this->_connectionID); 00454 if ($arr == false) $arr = @OCIError(); 00455 if ($arr == false) return ''; 00456 } 00457 00458 $this->_errorMsg = $arr['message']; 00459 $this->_errorCode = $arr['code']; 00460 00461 return $arr['code']; 00462 } 00463 00464 // Format date column in sql string given an input format that understands Y M D 00465 function SQLDate($fmt, $col=false) 00466 { 00467 if (!$col) $col = $this->sysTimeStamp; 00468 $s = 'TO_CHAR('.$col.",'"; 00469 00470 $len = strlen($fmt); 00471 for ($i=0; $i < $len; $i++) { 00472 $ch = $fmt[$i]; 00473 switch($ch) { 00474 case 'Y': 00475 case 'y': 00476 $s .= 'YYYY'; 00477 break; 00478 case 'Q': 00479 case 'q': 00480 $s .= 'Q'; 00481 break; 00482 00483 case 'M': 00484 $s .= 'Mon'; 00485 break; 00486 00487 case 'm': 00488 $s .= 'MM'; 00489 break; 00490 case 'D': 00491 case 'd': 00492 $s .= 'DD'; 00493 break; 00494 00495 case 'H': 00496 $s.= 'HH24'; 00497 break; 00498 00499 case 'h': 00500 $s .= 'HH'; 00501 break; 00502 00503 case 'i': 00504 $s .= 'MI'; 00505 break; 00506 00507 case 's': 00508 $s .= 'SS'; 00509 break; 00510 00511 case 'a': 00512 case 'A': 00513 $s .= 'AM'; 00514 break; 00515 00516 case 'w': 00517 $s .= 'D'; 00518 break; 00519 00520 case 'l': 00521 $s .= 'DAY'; 00522 break; 00523 00524 case 'W': 00525 $s .= 'WW'; 00526 break; 00527 00528 default: 00529 // handle escape characters... 00530 if ($ch == '\\') { 00531 $i++; 00532 $ch = substr($fmt,$i,1); 00533 } 00534 if (strpos('-/.:;, ',$ch) !== false) $s .= $ch; 00535 else $s .= '"'.$ch.'"'; 00536 00537 } 00538 } 00539 return $s. "')"; 00540 } 00541 00542 00543 /* 00544 This algorithm makes use of 00545 00546 a. FIRST_ROWS hint 00547 The FIRST_ROWS hint explicitly chooses the approach to optimize response time, 00548 that is, minimum resource usage to return the first row. Results will be returned 00549 as soon as they are identified. 00550 00551 b. Uses rownum tricks to obtain only the required rows from a given offset. 00552 As this uses complicated sql statements, we only use this if the $offset >= 100. 00553 This idea by Tomas V V Cox. 00554 00555 This implementation does not appear to work with oracle 8.0.5 or earlier. Comment 00556 out this function then, and the slower SelectLimit() in the base class will be used. 00557 */ 00558 function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0) 00559 { 00560 // seems that oracle only supports 1 hint comment in 8i 00561 if ($this->firstrows) { 00562 if (strpos($sql,'/*+') !== false) 00563 $sql = str_replace('/*+ ','/*+FIRST_ROWS ',$sql); 00564 else 00565 $sql = preg_replace('/^[ \t\n]*select/i','SELECT /*+FIRST_ROWS*/',$sql); 00566 } 00567 00568 if ($offset < $this->selectOffsetAlg1) { 00569 if ($nrows > 0) { 00570 if ($offset > 0) $nrows += $offset; 00571 //$inputarr['adodb_rownum'] = $nrows; 00572 if ($this->databaseType == 'oci8po') { 00573 $sql = "select * from (".$sql.") where rownum <= ?"; 00574 } else { 00575 $sql = "select * from (".$sql.") where rownum <= :adodb_offset"; 00576 } 00577 $inputarr['adodb_offset'] = $nrows; 00578 $nrows = -1; 00579 } 00580 // note that $nrows = 0 still has to work ==> no rows returned 00581 00582 $rs =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); 00583 return $rs; 00584 00585 } else { 00586 // Algorithm by Tomas V V Cox, from PEAR DB oci8.php 00587 00588 // Let Oracle return the name of the columns 00589 $q_fields = "SELECT * FROM (".$sql.") WHERE NULL = NULL"; 00590 00591 $false = false; 00592 if (! $stmt_arr = $this->Prepare($q_fields)) { 00593 return $false; 00594 } 00595 $stmt = $stmt_arr[1]; 00596 00597 if (is_array($inputarr)) { 00598 foreach($inputarr as $k => $v) { 00599 if (is_array($v)) { 00600 if (sizeof($v) == 2) // suggested by g.giunta@libero. 00601 OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]); 00602 else 00603 OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1],$v[2]); 00604 } else { 00605 $len = -1; 00606 if ($v === ' ') $len = 1; 00607 if (isset($bindarr)) { // is prepared sql, so no need to ocibindbyname again 00608 $bindarr[$k] = $v; 00609 } else { // dynamic sql, so rebind every time 00610 OCIBindByName($stmt,":$k",$inputarr[$k],$len); 00611 } 00612 } 00613 } 00614 } 00615 00616 if (!OCIExecute($stmt, OCI_DEFAULT)) { 00617 OCIFreeStatement($stmt); 00618 return $false; 00619 } 00620 00621 $ncols = OCINumCols($stmt); 00622 for ( $i = 1; $i <= $ncols; $i++ ) { 00623 $cols[] = '"'.OCIColumnName($stmt, $i).'"'; 00624 } 00625 $result = false; 00626 00627 OCIFreeStatement($stmt); 00628 $fields = implode(',', $cols); 00629 $nrows += $offset; 00630 $offset += 1; // in Oracle rownum starts at 1 00631 00632 if ($this->databaseType == 'oci8po') { 00633 $sql = "SELECT $fields FROM". 00634 "(SELECT rownum as adodb_rownum, $fields FROM". 00635 " ($sql) WHERE rownum <= ?". 00636 ") WHERE adodb_rownum >= ?"; 00637 } else { 00638 $sql = "SELECT $fields FROM". 00639 "(SELECT rownum as adodb_rownum, $fields FROM". 00640 " ($sql) WHERE rownum <= :adodb_nrows". 00641 ") WHERE adodb_rownum >= :adodb_offset"; 00642 } 00643 $inputarr['adodb_nrows'] = $nrows; 00644 $inputarr['adodb_offset'] = $offset; 00645 00646 if ($secs2cache>0) $rs =& $this->CacheExecute($secs2cache, $sql,$inputarr); 00647 else $rs =& $this->Execute($sql,$inputarr); 00648 return $rs; 00649 } 00650 00651 } 00652 00673 function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB') 00674 { 00675 00676 //if (strlen($val) < 4000) return $this->Execute("UPDATE $table SET $column=:blob WHERE $where",array('blob'=>$val)) != false; 00677 00678 switch(strtoupper($blobtype)) { 00679 default: ADOConnection::outp("<b>UpdateBlob</b>: Unknown blobtype=$blobtype"); return false; 00680 case 'BLOB': $type = OCI_B_BLOB; break; 00681 case 'CLOB': $type = OCI_B_CLOB; break; 00682 } 00683 00684 if ($this->databaseType == 'oci8po') 00685 $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO ?"; 00686 else 00687 $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO :blob"; 00688 00689 $desc = OCINewDescriptor($this->_connectionID, OCI_D_LOB); 00690 $arr['blob'] = array($desc,-1,$type); 00691 if ($this->session_sharing_force_blob) $this->Execute('ALTER SESSION SET CURSOR_SHARING=EXACT'); 00692 $commit = $this->autoCommit; 00693 if ($commit) $this->BeginTrans(); 00694 $rs = $this->_Execute($sql,$arr); 00695 if ($rez = !empty($rs)) $desc->save($val); 00696 $desc->free(); 00697 if ($commit) $this->CommitTrans(); 00698 if ($this->session_sharing_force_blob) $this->Execute('ALTER SESSION SET CURSOR_SHARING=FORCE'); 00699 00700 if ($rez) $rs->Close(); 00701 return $rez; 00702 } 00703 00707 function UpdateBlobFile($table,$column,$val,$where,$blobtype='BLOB') 00708 { 00709 switch(strtoupper($blobtype)) { 00710 default: ADOConnection::outp( "<b>UpdateBlob</b>: Unknown blobtype=$blobtype"); return false; 00711 case 'BLOB': $type = OCI_B_BLOB; break; 00712 case 'CLOB': $type = OCI_B_CLOB; break; 00713 } 00714 00715 if ($this->databaseType == 'oci8po') 00716 $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO ?"; 00717 else 00718 $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO :blob"; 00719 00720 $desc = OCINewDescriptor($this->_connectionID, OCI_D_LOB); 00721 $arr['blob'] = array($desc,-1,$type); 00722 00723 $this->BeginTrans(); 00724 $rs = ADODB_oci8::Execute($sql,$arr); 00725 if ($rez = !empty($rs)) $desc->savefile($val); 00726 $desc->free(); 00727 $this->CommitTrans(); 00728 00729 if ($rez) $rs->Close(); 00730 return $rez; 00731 } 00732 00740 function &Execute($sql,$inputarr=false) 00741 { 00742 if ($this->fnExecute) { 00743 $fn = $this->fnExecute; 00744 $ret =& $fn($this,$sql,$inputarr); 00745 if (isset($ret)) return $ret; 00746 } 00747 if ($inputarr) { 00748 #if (!is_array($inputarr)) $inputarr = array($inputarr); 00749 00750 $element0 = reset($inputarr); 00751 00752 # is_object check because oci8 descriptors can be passed in 00753 if (is_array($element0) && !is_object(reset($element0))) { 00754 if (is_string($sql)) 00755 $stmt = $this->Prepare($sql); 00756 else 00757 $stmt = $sql; 00758 00759 foreach($inputarr as $arr) { 00760 $ret =& $this->_Execute($stmt,$arr); 00761 if (!$ret) return $ret; 00762 } 00763 } else { 00764 $ret =& $this->_Execute($sql,$inputarr); 00765 } 00766 00767 } else { 00768 $ret =& $this->_Execute($sql,false); 00769 } 00770 00771 return $ret; 00772 } 00773 00774 /* 00775 Example of usage: 00776 00777 $stmt = $this->Prepare('insert into emp (empno, ename) values (:empno, :ename)'); 00778 */ 00779 function Prepare($sql,$cursor=false) 00780 { 00781 static $BINDNUM = 0; 00782 00783 $stmt = OCIParse($this->_connectionID,$sql); 00784 00785 if (!$stmt) return false; 00786 00787 $BINDNUM += 1; 00788 00789 $sttype = @OCIStatementType($stmt); 00790 if ($sttype == 'BEGIN' || $sttype == 'DECLARE') { 00791 return array($sql,$stmt,0,$BINDNUM, ($cursor) ? OCINewCursor($this->_connectionID) : false); 00792 } 00793 return array($sql,$stmt,0,$BINDNUM); 00794 } 00795 00796 /* 00797 Call an oracle stored procedure and returns a cursor variable as a recordset. 00798 Concept by Robert Tuttle robert@ud.com 00799 00800 Example: 00801 Note: we return a cursor variable in :RS2 00802 $rs = $db->ExecuteCursor("BEGIN adodb.open_tab(:RS2); END;",'RS2'); 00803 00804 $rs = $db->ExecuteCursor( 00805 "BEGIN :RS2 = adodb.getdata(:VAR1); END;", 00806 'RS2', 00807 array('VAR1' => 'Mr Bean')); 00808 00809 */ 00810 function &ExecuteCursor($sql,$cursorName='rs',$params=false) 00811 { 00812 if (is_array($sql)) $stmt = $sql; 00813 else $stmt = ADODB_oci8::Prepare($sql,true); # true to allocate OCINewCursor 00814 00815 if (is_array($stmt) && sizeof($stmt) >= 5) { 00816 $hasref = true; 00817 $ignoreCur = false; 00818 $this->Parameter($stmt, $ignoreCur, $cursorName, false, -1, OCI_B_CURSOR); 00819 if ($params) { 00820 foreach($params as $k => $v) { 00821 $this->Parameter($stmt,$params[$k], $k); 00822 } 00823 } 00824 } else 00825 $hasref = false; 00826 00827 $rs =& $this->Execute($stmt); 00828 if ($rs) { 00829 if ($rs->databaseType == 'array') OCIFreeCursor($stmt[4]); 00830 else if ($hasref) $rs->_refcursor = $stmt[4]; 00831 } 00832 return $rs; 00833 } 00834 00835 /* 00836 Bind a variable -- very, very fast for executing repeated statements in oracle. 00837 Better than using 00838 for ($i = 0; $i < $max; $i++) { 00839 $p1 = ?; $p2 = ?; $p3 = ?; 00840 $this->Execute("insert into table (col0, col1, col2) values (:0, :1, :2)", 00841 array($p1,$p2,$p3)); 00842 } 00843 00844 Usage: 00845 $stmt = $DB->Prepare("insert into table (col0, col1, col2) values (:0, :1, :2)"); 00846 $DB->Bind($stmt, $p1); 00847 $DB->Bind($stmt, $p2); 00848 $DB->Bind($stmt, $p3); 00849 for ($i = 0; $i < $max; $i++) { 00850 $p1 = ?; $p2 = ?; $p3 = ?; 00851 $DB->Execute($stmt); 00852 } 00853 00854 Some timings: 00855 ** Test table has 3 cols, and 1 index. Test to insert 1000 records 00856 Time 0.6081s (1644.60 inserts/sec) with direct OCIParse/OCIExecute 00857 Time 0.6341s (1577.16 inserts/sec) with ADOdb Prepare/Bind/Execute 00858 Time 1.5533s ( 643.77 inserts/sec) with pure SQL using Execute 00859 00860 Now if PHP only had batch/bulk updating like Java or PL/SQL... 00861 00862 Note that the order of parameters differs from OCIBindByName, 00863 because we default the names to :0, :1, :2 00864 */ 00865 function Bind(&$stmt,&$var,$size=4000,$type=false,$name=false,$isOutput=false) 00866 { 00867 00868 if (!is_array($stmt)) return false; 00869 00870 if (($type == OCI_B_CURSOR) && sizeof($stmt) >= 5) { 00871 return OCIBindByName($stmt[1],":".$name,$stmt[4],$size,$type); 00872 } 00873 00874 if ($name == false) { 00875 if ($type !== false) $rez = OCIBindByName($stmt[1],":".$stmt[2],$var,$size,$type); 00876 else $rez = OCIBindByName($stmt[1],":".$stmt[2],$var,$size); // +1 byte for null terminator 00877 $stmt[2] += 1; 00878 } else if (oci_lob_desc($type)) { 00879 if ($this->debug) { 00880 ADOConnection::outp("<b>Bind</b>: name = $name"); 00881 } 00882 //we have to create a new Descriptor here 00883 $numlob = count($this->_refLOBs); 00884 $this->_refLOBs[$numlob]['LOB'] = OCINewDescriptor($this->_connectionID, oci_lob_desc($type)); 00885 $this->_refLOBs[$numlob]['TYPE'] = $isOutput; 00886 00887 $tmp = &$this->_refLOBs[$numlob]['LOB']; 00888 $rez = OCIBindByName($stmt[1], ":".$name, $tmp, -1, $type); 00889 if ($this->debug) { 00890 ADOConnection::outp("<b>Bind</b>: descriptor has been allocated, var (".$name.") binded"); 00891 } 00892 00893 // if type is input then write data to lob now 00894 if ($isOutput == false) { 00895 $var = $this->BlobEncode($var); 00896 $tmp->WriteTemporary($var); 00897 $this->_refLOBs[$numlob]['VAR'] = &$var; 00898 if ($this->debug) { 00899 ADOConnection::outp("<b>Bind</b>: LOB has been written to temp"); 00900 } 00901 } else { 00902 $this->_refLOBs[$numlob]['VAR'] = &$var; 00903 } 00904 $rez = $tmp; 00905 } else { 00906 if ($this->debug) 00907 ADOConnection::outp("<b>Bind</b>: name = $name"); 00908 00909 if ($type !== false) $rez = OCIBindByName($stmt[1],":".$name,$var,$size,$type); 00910 else $rez = OCIBindByName($stmt[1],":".$name,$var,$size); // +1 byte for null terminator 00911 } 00912 00913 return $rez; 00914 } 00915 00916 function Param($name,$type=false) 00917 { 00918 return ':'.$name; 00919 } 00920 00921 /* 00922 Usage: 00923 $stmt = $db->Prepare('select * from table where id =:myid and group=:group'); 00924 $db->Parameter($stmt,$id,'myid'); 00925 $db->Parameter($stmt,$group,'group'); 00926 $db->Execute($stmt); 00927 00928 @param $stmt Statement returned by Prepare() or PrepareSP(). 00929 @param $var PHP variable to bind to 00930 @param $name Name of stored procedure variable name to bind to. 00931 @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8. 00932 @param [$maxLen] Holds an maximum length of the variable. 00933 @param [$type] The data type of $var. Legal values depend on driver. 00934 00935 See OCIBindByName documentation at php.net. 00936 */ 00937 function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false) 00938 { 00939 if ($this->debug) { 00940 $prefix = ($isOutput) ? 'Out' : 'In'; 00941 $ztype = (empty($type)) ? 'false' : $type; 00942 ADOConnection::outp( "{$prefix}Parameter(\$stmt, \$php_var='$var', \$name='$name', \$maxLen=$maxLen, \$type=$ztype);"); 00943 } 00944 return $this->Bind($stmt,$var,$maxLen,$type,$name,$isOutput); 00945 } 00946 00947 /* 00948 returns query ID if successful, otherwise false 00949 this version supports: 00950 00951 1. $db->execute('select * from table'); 00952 00953 2. $db->prepare('insert into table (a,b,c) values (:0,:1,:2)'); 00954 $db->execute($prepared_statement, array(1,2,3)); 00955 00956 3. $db->execute('insert into table (a,b,c) values (:a,:b,:c)',array('a'=>1,'b'=>2,'c'=>3)); 00957 00958 4. $db->prepare('insert into table (a,b,c) values (:0,:1,:2)'); 00959 $db->bind($stmt,1); $db->bind($stmt,2); $db->bind($stmt,3); 00960 $db->execute($stmt); 00961 */ 00962 function _query($sql,$inputarr) 00963 { 00964 if (is_array($sql)) { // is prepared sql 00965 $stmt = $sql[1]; 00966 00967 // we try to bind to permanent array, so that OCIBindByName is persistent 00968 // and carried out once only - note that max array element size is 4000 chars 00969 if (is_array($inputarr)) { 00970 $bindpos = $sql[3]; 00971 if (isset($this->_bind[$bindpos])) { 00972 // all tied up already 00973 $bindarr = &$this->_bind[$bindpos]; 00974 } else { 00975 // one statement to bind them all 00976 $bindarr = array(); 00977 foreach($inputarr as $k => $v) { 00978 $bindarr[$k] = $v; 00979 OCIBindByName($stmt,":$k",$bindarr[$k],is_string($v) && strlen($v)>4000 ? -1 : 4000); 00980 } 00981 $this->_bind[$bindpos] = &$bindarr; 00982 } 00983 } 00984 } else { 00985 $stmt=OCIParse($this->_connectionID,$sql); 00986 } 00987 00988 $this->_stmt = $stmt; 00989 if (!$stmt) return false; 00990 00991 if (defined('ADODB_PREFETCH_ROWS')) @OCISetPrefetch($stmt,ADODB_PREFETCH_ROWS); 00992 00993 if (is_array($inputarr)) { 00994 foreach($inputarr as $k => $v) { 00995 if (is_array($v)) { 00996 if (sizeof($v) == 2) // suggested by g.giunta@libero. 00997 OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]); 00998 else 00999 OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1],$v[2]); 01000 01001 if ($this->debug==99) echo "name=:$k",' var='.$inputarr[$k][0],' len='.$v[1],' type='.$v[2],'<br>'; 01002 } else { 01003 $len = -1; 01004 if ($v === ' ') $len = 1; 01005 if (isset($bindarr)) { // is prepared sql, so no need to ocibindbyname again 01006 $bindarr[$k] = $v; 01007 } else { // dynamic sql, so rebind every time 01008 OCIBindByName($stmt,":$k",$inputarr[$k],$len); 01009 } 01010 } 01011 } 01012 } 01013 01014 $this->_errorMsg = false; 01015 $this->_errorCode = false; 01016 if (OCIExecute($stmt,$this->_commit)) { 01017 //OCIInternalDebug(1); 01018 if (count($this -> _refLOBs) > 0) { 01019 01020 foreach ($this -> _refLOBs as $key => $value) { 01021 if ($this -> _refLOBs[$key]['TYPE'] == true) { 01022 $tmp = $this -> _refLOBs[$key]['LOB'] -> load(); 01023 if ($this -> debug) { 01024 ADOConnection::outp("<b>OUT LOB</b>: LOB has been loaded. <br>"); 01025 } 01026 //$_GLOBALS[$this -> _refLOBs[$key]['VAR']] = $tmp; 01027 $this -> _refLOBs[$key]['VAR'] = $tmp; 01028 } else { 01029 $this->_refLOBs[$key]['LOB']->save($this->_refLOBs[$key]['VAR']); 01030 $this -> _refLOBs[$key]['LOB']->free(); 01031 unset($this -> _refLOBs[$key]); 01032 if ($this->debug) { 01033 ADOConnection::outp("<b>IN LOB</b>: LOB has been saved. <br>"); 01034 } 01035 } 01036 } 01037 } 01038 01039 switch (@OCIStatementType($stmt)) { 01040 case "SELECT": 01041 return $stmt; 01042 01043 case 'DECLARE': 01044 case "BEGIN": 01045 if (is_array($sql) && !empty($sql[4])) { 01046 $cursor = $sql[4]; 01047 if (is_resource($cursor)) { 01048 $ok = OCIExecute($cursor); 01049 return $cursor; 01050 } 01051 return $stmt; 01052 } else { 01053 if (is_resource($stmt)) { 01054 OCIFreeStatement($stmt); 01055 return true; 01056 } 01057 return $stmt; 01058 } 01059 break; 01060 default : 01061 // ociclose -- no because it could be used in a LOB? 01062 return true; 01063 } 01064 } 01065 return false; 01066 } 01067 01068 // returns true or false 01069 function _close() 01070 { 01071 if (!$this->_connectionID) return; 01072 01073 if (!$this->autoCommit) OCIRollback($this->_connectionID); 01074 if (count($this->_refLOBs) > 0) { 01075 foreach ($this ->_refLOBs as $key => $value) { 01076 $this->_refLOBs[$key]['LOB']->free(); 01077 unset($this->_refLOBs[$key]); 01078 } 01079 } 01080 OCILogoff($this->_connectionID); 01081 01082 $this->_stmt = false; 01083 $this->_connectionID = false; 01084 } 01085 01086 function MetaPrimaryKeys($table, $owner=false,$internalKey=false) 01087 { 01088 if ($internalKey) return array('ROWID'); 01089 01090 // tested with oracle 8.1.7 01091 $table = strtoupper($table); 01092 if ($owner) { 01093 $owner_clause = "AND ((a.OWNER = b.OWNER) AND (a.OWNER = UPPER('$owner')))"; 01094 $ptab = 'ALL_'; 01095 } else { 01096 $owner_clause = ''; 01097 $ptab = 'USER_'; 01098 } 01099 $sql = " 01100 SELECT /*+ RULE */ distinct b.column_name 01101 FROM {$ptab}CONSTRAINTS a 01102 , {$ptab}CONS_COLUMNS b 01103 WHERE ( UPPER(b.table_name) = ('$table')) 01104 AND (UPPER(a.table_name) = ('$table') and a.constraint_type = 'P') 01105 $owner_clause 01106 AND (a.constraint_name = b.constraint_name)"; 01107 01108 $rs = $this->Execute($sql); 01109 if ($rs && !$rs->EOF) { 01110 $arr =& $rs->GetArray(); 01111 $a = array(); 01112 foreach($arr as $v) { 01113 $a[] = reset($v); 01114 } 01115 return $a; 01116 } 01117 else return false; 01118 } 01119 01120 // http://gis.mit.edu/classes/11.521/sqlnotes/referential_integrity.html 01121 function MetaForeignKeys($table, $owner=false) 01122 { 01123 global $ADODB_FETCH_MODE; 01124 01125 $save = $ADODB_FETCH_MODE; 01126 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 01127 $table = $this->qstr(strtoupper($table)); 01128 if (!$owner) { 01129 $owner = $this->user; 01130 $tabp = 'user_'; 01131 } else 01132 $tabp = 'all_'; 01133 01134 $owner = ' and owner='.$this->qstr(strtoupper($owner)); 01135 01136 $sql = 01137 "select constraint_name,r_owner,r_constraint_name 01138 from {$tabp}constraints 01139 where constraint_type = 'R' and table_name = $table $owner"; 01140 01141 $constraints =& $this->GetArray($sql); 01142 $arr = false; 01143 foreach($constraints as $constr) { 01144 $cons = $this->qstr($constr[0]); 01145 $rowner = $this->qstr($constr[1]); 01146 $rcons = $this->qstr($constr[2]); 01147 $cols = $this->GetArray("select column_name from {$tabp}cons_columns where constraint_name=$cons $owner order by position"); 01148 $tabcol = $this->GetArray("select table_name,column_name from {$tabp}cons_columns where owner=$rowner and constraint_name=$rcons order by position"); 01149 01150 if ($cols && $tabcol) 01151 for ($i=0, $max=sizeof($cols); $i < $max; $i++) { 01152 $arr[$tabcol[$i][0]] = $cols[$i][0].'='.$tabcol[$i][1]; 01153 } 01154 } 01155 $ADODB_FETCH_MODE = $save; 01156 01157 return $arr; 01158 } 01159 01160 01161 function CharMax() 01162 { 01163 return 4000; 01164 } 01165 01166 function TextMax() 01167 { 01168 return 4000; 01169 } 01170 01181 function qstr($s,$magic_quotes=false) 01182 { 01183 //$nofixquotes=false; 01184 01185 if ($this->noNullStrings && strlen($s)==0)$s = ' '; 01186 if (!$magic_quotes) { 01187 if ($this->replaceQuote[0] == '\\'){ 01188 $s = str_replace('\\','\\\\',$s); 01189 } 01190 return "'".str_replace("'",$this->replaceQuote,$s)."'"; 01191 } 01192 01193 // undo magic quotes for " 01194 $s = str_replace('\\"','"',$s); 01195 01196 $s = str_replace('\\\\','\\',$s); 01197 return "'".str_replace("\\'",$this->replaceQuote,$s)."'"; 01198 01199 } 01200 01201 } 01202 01203 /*-------------------------------------------------------------------------------------- 01204 Class Name: Recordset 01205 --------------------------------------------------------------------------------------*/ 01206 01207 class ADORecordset_oci8 extends ADORecordSet { 01208 01209 var $databaseType = 'oci8'; 01210 var $bind=false; 01211 var $_fieldobjs; 01212 01213 //var $_arr = false; 01214 01215 function ADORecordset_oci8($queryID,$mode=false) 01216 { 01217 if ($mode === false) { 01218 global $ADODB_FETCH_MODE; 01219 $mode = $ADODB_FETCH_MODE; 01220 } 01221 switch ($mode) 01222 { 01223 case ADODB_FETCH_ASSOC:$this->fetchMode = OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break; 01224 case ADODB_FETCH_DEFAULT: 01225 case ADODB_FETCH_BOTH:$this->fetchMode = OCI_NUM+OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break; 01226 case ADODB_FETCH_NUM: 01227 default: 01228 $this->fetchMode = OCI_NUM+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break; 01229 } 01230 01231 $this->adodbFetchMode = $mode; 01232 $this->_queryID = $queryID; 01233 } 01234 01235 01236 function Init() 01237 { 01238 if ($this->_inited) return; 01239 01240 $this->_inited = true; 01241 if ($this->_queryID) { 01242 01243 $this->_currentRow = 0; 01244 @$this->_initrs(); 01245 $this->EOF = !$this->_fetch(); 01246 01247 /* 01248 // based on idea by Gaetano Giunta to detect unusual oracle errors 01249 // see http://phplens.com/lens/lensforum/msgs.php?id=6771 01250 $err = OCIError($this->_queryID); 01251 if ($err && $this->connection->debug) ADOConnection::outp($err); 01252 */ 01253 01254 if (!is_array($this->fields)) { 01255 $this->_numOfRows = 0; 01256 $this->fields = array(); 01257 } 01258 } else { 01259 $this->fields = array(); 01260 $this->_numOfRows = 0; 01261 $this->_numOfFields = 0; 01262 $this->EOF = true; 01263 } 01264 } 01265 01266 function _initrs() 01267 { 01268 $this->_numOfRows = -1; 01269 $this->_numOfFields = OCInumcols($this->_queryID); 01270 if ($this->_numOfFields>0) { 01271 $this->_fieldobjs = array(); 01272 $max = $this->_numOfFields; 01273 for ($i=0;$i<$max; $i++) $this->_fieldobjs[] = $this->_FetchField($i); 01274 } 01275 } 01276 01277 /* Returns: an object containing field information. 01278 Get column information in the Recordset object. fetchField() can be used in order to obtain information about 01279 fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by 01280 fetchField() is retrieved. */ 01281 01282 function &_FetchField($fieldOffset = -1) 01283 { 01284 $fld = new ADOFieldObject; 01285 $fieldOffset += 1; 01286 $fld->name =OCIcolumnname($this->_queryID, $fieldOffset); 01287 $fld->type = OCIcolumntype($this->_queryID, $fieldOffset); 01288 $fld->max_length = OCIcolumnsize($this->_queryID, $fieldOffset); 01289 if ($fld->type == 'NUMBER') { 01290 $p = OCIColumnPrecision($this->_queryID, $fieldOffset); 01291 $sc = OCIColumnScale($this->_queryID, $fieldOffset); 01292 if ($p != 0 && $sc == 0) $fld->type = 'INT'; 01293 //echo " $this->name ($p.$sc) "; 01294 } 01295 return $fld; 01296 } 01297 01298 /* For some reason, OCIcolumnname fails when called after _initrs() so we cache it */ 01299 function &FetchField($fieldOffset = -1) 01300 { 01301 return $this->_fieldobjs[$fieldOffset]; 01302 } 01303 01304 01305 /* 01306 // 10% speedup to move MoveNext to child class 01307 function _MoveNext() 01308 { 01309 //global $ADODB_EXTENSION;if ($ADODB_EXTENSION) return @adodb_movenext($this); 01310 01311 if ($this->EOF) return false; 01312 01313 $this->_currentRow++; 01314 if(@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) 01315 return true; 01316 $this->EOF = true; 01317 01318 return false; 01319 } */ 01320 01321 01322 function MoveNext() 01323 { 01324 if (@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) { 01325 $this->_currentRow += 1; 01326 return true; 01327 } 01328 if (!$this->EOF) { 01329 $this->_currentRow += 1; 01330 $this->EOF = true; 01331 } 01332 return false; 01333 } 01334 01335 /* 01336 # does not work as first record is retrieved in _initrs(), so is not included in GetArray() 01337 function &GetArray($nRows = -1) 01338 { 01339 global $ADODB_OCI8_GETARRAY; 01340 01341 if (true || !empty($ADODB_OCI8_GETARRAY)) { 01342 # does not support $ADODB_ANSI_PADDING_OFF 01343 01344 //OCI_RETURN_NULLS and OCI_RETURN_LOBS is set by OCIfetchstatement 01345 switch($this->adodbFetchMode) { 01346 case ADODB_FETCH_NUM: 01347 01348 $ncols = @OCIfetchstatement($this->_queryID, $results, 0, $nRows, OCI_FETCHSTATEMENT_BY_ROW+OCI_NUM); 01349 $results = array_merge(array($this->fields),$results); 01350 return $results; 01351 01352 case ADODB_FETCH_ASSOC: 01353 if (ADODB_ASSOC_CASE != 2 || $this->databaseType != 'oci8') break; 01354 01355 $ncols = @OCIfetchstatement($this->_queryID, $assoc, 0, $nRows, OCI_FETCHSTATEMENT_BY_ROW); 01356 $results =& array_merge(array($this->fields),$assoc); 01357 return $results; 01358 01359 default: 01360 break; 01361 } 01362 } 01363 01364 $results =& ADORecordSet::GetArray($nRows); 01365 return $results; 01366 01367 } */ 01368 01369 /* Optimize SelectLimit() by using OCIFetch() instead of OCIFetchInto() */ 01370 function &GetArrayLimit($nrows,$offset=-1) 01371 { 01372 if ($offset <= 0) { 01373 $arr =& $this->GetArray($nrows); 01374 return $arr; 01375 } 01376 for ($i=1; $i < $offset; $i++) 01377 if (!@OCIFetch($this->_queryID)) return array(); 01378 01379 if (!@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) return array(); 01380 $results = array(); 01381 $cnt = 0; 01382 while (!$this->EOF && $nrows != $cnt) { 01383 $results[$cnt++] = $this->fields; 01384 $this->MoveNext(); 01385 } 01386 01387 return $results; 01388 } 01389 01390 01391 /* Use associative array to get fields array */ 01392 function Fields($colname) 01393 { 01394 if (!$this->bind) { 01395 $this->bind = array(); 01396 for ($i=0; $i < $this->_numOfFields; $i++) { 01397 $o = $this->FetchField($i); 01398 $this->bind[strtoupper($o->name)] = $i; 01399 } 01400 } 01401 01402 return $this->fields[$this->bind[strtoupper($colname)]]; 01403 } 01404 01405 01406 01407 function _seek($row) 01408 { 01409 return false; 01410 } 01411 01412 function _fetch() 01413 { 01414 return @OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode); 01415 } 01416 01417 /* close() only needs to be called if you are worried about using too much memory while your script 01418 is running. All associated result memory for the specified result identifier will automatically be freed. */ 01419 01420 function _close() 01421 { 01422 if ($this->connection->_stmt === $this->_queryID) $this->connection->_stmt = false; 01423 if (!empty($this->_refcursor)) { 01424 OCIFreeCursor($this->_refcursor); 01425 $this->_refcursor = false; 01426 } 01427 @OCIFreeStatement($this->_queryID); 01428 $this->_queryID = false; 01429 01430 } 01431 01432 function MetaType($t,$len=-1) 01433 { 01434 if (is_object($t)) { 01435 $fieldobj = $t; 01436 $t = $fieldobj->type; 01437 $len = $fieldobj->max_length; 01438 } 01439 switch (strtoupper($t)) { 01440 case 'VARCHAR': 01441 case 'VARCHAR2': 01442 case 'CHAR': 01443 case 'VARBINARY': 01444 case 'BINARY': 01445 case 'NCHAR': 01446 case 'NVARCHAR': 01447 case 'NVARCHAR2': 01448 if (isset($this) && $len <= $this->blobSize) return 'C'; 01449 01450 case 'NCLOB': 01451 case 'LONG': 01452 case 'LONG VARCHAR': 01453 case 'CLOB': 01454 return 'X'; 01455 01456 case 'LONG RAW': 01457 case 'LONG VARBINARY': 01458 case 'BLOB': 01459 return 'B'; 01460 01461 case 'DATE': 01462 return ($this->connection->datetime) ? 'T' : 'D'; 01463 01464 01465 case 'TIMESTAMP': return 'T'; 01466 01467 case 'INT': 01468 case 'SMALLINT': 01469 case 'INTEGER': 01470 return 'I'; 01471 01472 default: return 'N'; 01473 } 01474 } 01475 } 01476 01477 class ADORecordSet_ext_oci8 extends ADORecordSet_oci8 { 01478 function ADORecordSet_ext_oci8($queryID,$mode=false) 01479 { 01480 if ($mode === false) { 01481 global $ADODB_FETCH_MODE; 01482 $mode = $ADODB_FETCH_MODE; 01483 } 01484 switch ($mode) 01485 { 01486 case ADODB_FETCH_ASSOC:$this->fetchMode = OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break; 01487 case ADODB_FETCH_DEFAULT: 01488 case ADODB_FETCH_BOTH:$this->fetchMode = OCI_NUM+OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break; 01489 case ADODB_FETCH_NUM: 01490 default: $this->fetchMode = OCI_NUM+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break; 01491 } 01492 $this->adodbFetchMode = $mode; 01493 $this->_queryID = $queryID; 01494 } 01495 01496 function MoveNext() 01497 { 01498 return adodb_movenext($this); 01499 } 01500 } 01501 ?>