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