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