"TYPO3 4.0.1: typo3_src-4.0.1/typo3/sysext/adodb/adodb/drivers/adodb-oci8.inc.php Source File", "datetime" => "Sat Dec 2 19:22:26 2006", "date" => "2 Dec 2006", "doxygenversion" => "1.4.6", "projectname" => "TYPO3 4.0.1", "projectnumber" => "4.0.1" ); get_header($doxygen_vars); ?>

adodb-oci8.inc.php

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