Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/adodb/drivers/adodb-oci8.inc.php
Go to the documentation of this file.
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 ?>
 All Data Structures Namespaces Files Functions Variables Enumerations