Documentation TYPO3 par Ameos

adodb-oci8.inc.php

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


Généré par L'expert TYPO3 avec  doxygen 1.4.6