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