[ Index ]

PHP Cross Reference of MantisBT

title

Body

[close]

/library/adodb/drivers/ -> adodb-oci8.inc.php (source)

   1  <?php
   2  /*
   3  
   4    version V5.11 5 May 2010  (c) 2000-2010 John Lim. All rights reserved.
   5  
   6    Released under both BSD license and Lesser GPL library license. 
   7    Whenever there is any discrepancy between the two licenses, 
   8    the BSD license will take precedence.
   9  
  10    Latest version is available at http://adodb.sourceforge.net
  11    
  12    Code contributed by George Fourlanos <fou@infomap.gr>
  13    
  14    13 Nov 2000 jlim - removed all ora_* references.
  15  */
  16  
  17  // security - hide paths
  18  if (!defined('ADODB_DIR')) die();
  19  
  20  /*
  21  NLS_Date_Format
  22  Allows you to use a date format other than the Oracle Lite default. When a literal
  23  character string appears where a date value is expected, the Oracle Lite database
  24  tests the string to see if it matches the formats of Oracle, SQL-92, or the value
  25  specified for this parameter in the POLITE.INI file. Setting this parameter also
  26  defines the default format used in the TO_CHAR or TO_DATE functions when no
  27  other format string is supplied.
  28  
  29  For Oracle the default is dd-mon-yy or dd-mon-yyyy, and for SQL-92 the default is
  30  yy-mm-dd or yyyy-mm-dd.
  31  
  32  Using 'RR' in the format forces two-digit years less than or equal to 49 to be
  33  interpreted as years in the 21st century (2000–2049), and years over 50 as years in
  34  the 20th century (1950–1999). Setting the RR format as the default for all two-digit
  35  year entries allows you to become year-2000 compliant. For example:
  36  NLS_DATE_FORMAT='RR-MM-DD'
  37  
  38  You can also modify the date format using the ALTER SESSION command. 
  39  */
  40  
  41  # define the LOB descriptor type for the given type
  42  # returns false if no LOB descriptor
  43  function oci_lob_desc($type) {
  44      switch ($type) {
  45          case OCI_B_BFILE: $result = OCI_D_FILE; break;
  46          case OCI_B_CFILEE: $result = OCI_D_FILE; break;
  47          case OCI_B_CLOB: $result = OCI_D_LOB; break;
  48          case OCI_B_BLOB: $result = OCI_D_LOB; break;
  49          case OCI_B_ROWID: $result = OCI_D_ROWID; break;
  50          default: $result = false; break;
  51      }
  52      return $result;
  53  }
  54  
  55  class ADODB_oci8 extends ADOConnection {
  56      var $databaseType = 'oci8';
  57      var $dataProvider = 'oci8';
  58      var $replaceQuote = "''"; // string to use to replace quotes
  59      var $concat_operator='||';
  60      var $sysDate = "TRUNC(SYSDATE)";
  61      var $sysTimeStamp = 'SYSDATE'; // requires oracle 9 or later, otherwise use SYSDATE
  62      var $metaDatabasesSQL = "SELECT USERNAME FROM ALL_USERS WHERE USERNAME NOT IN ('SYS','SYSTEM','DBSNMP','OUTLN') ORDER BY 1";
  63      var $_stmt;
  64      var $_commit = OCI_COMMIT_ON_SUCCESS;
  65      var $_initdate = true; // init date to YYYY-MM-DD
  66      var $metaTablesSQL = "select table_name,table_type from cat where table_type in ('TABLE','VIEW') and table_name not like 'BIN\$%'"; // bin$ tables are recycle bin tables
  67      var $metaColumnsSQL = "select cname,coltype,width, SCALE, PRECISION, NULLS, DEFAULTVAL from col where tname='%s' order by colno"; //changed by smondino@users.sourceforge. net
  68      var $metaColumnsSQL2 = "select column_name,data_type,data_length, data_scale, data_precision, 
  69      case when nullable = 'Y' then 'NULL'
  70      else 'NOT NULL' end as nulls,
  71      data_default from all_tab_cols 
  72    where owner='%s' and table_name='%s' order by column_id"; // when there is a schema
  73      var $_bindInputArray = true;
  74      var $hasGenID = true;
  75      var $_genIDSQL = "SELECT (%s.nextval) FROM DUAL";
  76      var $_genSeqSQL = "CREATE SEQUENCE %s START WITH %s";
  77      var $_dropSeqSQL = "DROP SEQUENCE %s";
  78      var $hasAffectedRows = true;
  79      var $random = "abs(mod(DBMS_RANDOM.RANDOM,10000001)/10000000)";
  80      var $noNullStrings = false;
  81      var $connectSID = false;
  82      var $_bind = false;
  83      var $_nestedSQL = true;
  84      var $_hasOCIFetchStatement = false;
  85      var $_getarray = false; // currently not working
  86      var $leftOuter = '';  // oracle wierdness, $col = $value (+) for LEFT OUTER, $col (+)= $value for RIGHT OUTER
  87      var $session_sharing_force_blob = false; // alter session on updateblob if set to true 
  88      var $firstrows = true; // enable first rows optimization on SelectLimit()
  89      var $selectOffsetAlg1 = 1000; // when to use 1st algorithm of selectlimit.
  90      var $NLS_DATE_FORMAT = 'YYYY-MM-DD';  // To include time, use 'RRRR-MM-DD HH24:MI:SS'
  91      var $dateformat = 'YYYY-MM-DD'; // DBDate format
  92       var $useDBDateFormatForTextInput=false;
  93      var $datetime = false; // MetaType('DATE') returns 'D' (datetime==false) or 'T' (datetime == true)
  94      var $_refLOBs = array();
  95          
  96      // var $ansiOuter = true; // if oracle9
  97      
  98  	function ADODB_oci8() 
  99      {
 100          $this->_hasOCIFetchStatement = ADODB_PHPVER >= 0x4200;
 101          if (defined('ADODB_EXTENSION')) $this->rsPrefix .= 'ext_';
 102      }
 103      
 104      /*  function MetaColumns($table, $normalize=true) added by smondino@users.sourceforge.net*/
 105  	function MetaColumns($table, $normalize=true) 
 106      {
 107      global $ADODB_FETCH_MODE;
 108          
 109          $schema = '';
 110          $this->_findschema($table, $schema);
 111          
 112          $false = false;
 113          $save = $ADODB_FETCH_MODE;
 114          $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
 115          if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
 116  
 117          if ($schema)
 118              $rs = $this->Execute(sprintf($this->metaColumnsSQL2, strtoupper($schema), strtoupper($table)));
 119          else
 120              $rs = $this->Execute(sprintf($this->metaColumnsSQL,strtoupper($table)));
 121          
 122          if (isset($savem)) $this->SetFetchMode($savem);
 123          $ADODB_FETCH_MODE = $save;
 124          if (!$rs) {
 125              return $false;
 126          }
 127          $retarr = array();
 128          while (!$rs->EOF) {
 129              $fld = new ADOFieldObject();
 130                 $fld->name = $rs->fields[0];
 131                 $fld->type = $rs->fields[1];
 132                 $fld->max_length = $rs->fields[2];
 133              $fld->scale = $rs->fields[3];
 134              if ($rs->fields[1] == 'NUMBER') {
 135                  if ($rs->fields[3] == 0) $fld->type = 'INT';
 136                   $fld->max_length = $rs->fields[4];
 137              }    
 138                 $fld->not_null = (strncmp($rs->fields[5], 'NOT',3) === 0);
 139              $fld->binary = (strpos($fld->type,'BLOB') !== false);
 140              $fld->default_value = $rs->fields[6];
 141              
 142              if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;    
 143              else $retarr[strtoupper($fld->name)] = $fld;
 144              $rs->MoveNext();
 145          }
 146          $rs->Close();
 147          if (empty($retarr))
 148              return  $false;
 149          else 
 150              return $retarr;
 151      }
 152      
 153  	function Time()
 154      {
 155          $rs = $this->Execute("select TO_CHAR($this->sysTimeStamp,'YYYY-MM-DD HH24:MI:SS') from dual");
 156          if ($rs && !$rs->EOF) return $this->UnixTimeStamp(reset($rs->fields));
 157          
 158          return false;
 159      }
 160   
 161  /*
 162  
 163    Multiple modes of connection are supported:
 164    
 165    a. Local Database
 166      $conn->Connect(false,'scott','tiger');
 167    
 168    b. From tnsnames.ora
 169      $conn->Connect(false,'scott','tiger',$tnsname); 
 170      $conn->Connect($tnsname,'scott','tiger'); 
 171    
 172    c. Server + service name
 173      $conn->Connect($serveraddress,'scott,'tiger',$service_name);
 174    
 175    d. Server + SID
 176        $conn->connectSID = true;
 177      $conn->Connect($serveraddress,'scott,'tiger',$SID);
 178  
 179  
 180  Example TNSName:
 181  ---------------
 182  NATSOFT.DOMAIN =
 183    (DESCRIPTION =
 184      (ADDRESS_LIST =
 185        (ADDRESS = (PROTOCOL = TCP)(HOST = kermit)(PORT = 1523))
 186      )
 187      (CONNECT_DATA =
 188        (SERVICE_NAME = natsoft.domain)
 189      )
 190    )
 191    
 192    There are 3 connection modes, 0 = non-persistent, 1 = persistent, 2 = force new connection
 193      
 194  */
 195  	function _connect($argHostname, $argUsername, $argPassword, $argDatabasename,$mode=0)
 196      {
 197          if (!function_exists('OCIPLogon')) return null;
 198          #adodb_backtrace(); 
 199          
 200          $this->_errorMsg = false;
 201          $this->_errorCode = false;
 202          
 203          if($argHostname) { // added by Jorma Tuomainen <jorma.tuomainen@ppoy.fi>
 204              if (empty($argDatabasename)) $argDatabasename = $argHostname;
 205              else {
 206                  if(strpos($argHostname,":")) {
 207                      $argHostinfo=explode(":",$argHostname);
 208                         $argHostname=$argHostinfo[0];
 209                      $argHostport=$argHostinfo[1];
 210                   } else {
 211                      $argHostport = empty($this->port)?  "1521" : $this->port;
 212                     }
 213                  
 214                  if (strncasecmp($argDatabasename,'SID=',4) == 0) {
 215                      $argDatabasename = substr($argDatabasename,4);
 216                      $this->connectSID = true;
 217                  }
 218                  
 219                  if ($this->connectSID) {
 220                      $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname
 221                      .")(PORT=$argHostport))(CONNECT_DATA=(SID=$argDatabasename)))";
 222                  } else
 223                      $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname
 224                      .")(PORT=$argHostport))(CONNECT_DATA=(SERVICE_NAME=$argDatabasename)))";
 225              }
 226          }
 227                  
 228           //if ($argHostname) print "<p>Connect: 1st argument should be left blank for $this->databaseType</p>";
 229          if ($mode==1) {
 230              $this->_connectionID = ($this->charSet) ? 
 231                  OCIPLogon($argUsername,$argPassword, $argDatabasename,$this->charSet)
 232                  :
 233                  OCIPLogon($argUsername,$argPassword, $argDatabasename)
 234                  ;
 235              if ($this->_connectionID && $this->autoRollback)  OCIrollback($this->_connectionID);
 236          } else if ($mode==2) {
 237              $this->_connectionID = ($this->charSet) ? 
 238                  OCINLogon($argUsername,$argPassword, $argDatabasename,$this->charSet)
 239                  :
 240                  OCINLogon($argUsername,$argPassword, $argDatabasename);
 241                  
 242          } else {
 243              $this->_connectionID = ($this->charSet) ? 
 244                  OCILogon($argUsername,$argPassword, $argDatabasename,$this->charSet)
 245                  :
 246                  OCILogon($argUsername,$argPassword, $argDatabasename);
 247          }
 248          if (!$this->_connectionID) return false;
 249          if ($this->_initdate) {
 250              $this->Execute("ALTER SESSION SET NLS_DATE_FORMAT='".$this->NLS_DATE_FORMAT."'");
 251          }
 252          
 253          // looks like: 
 254          // Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production With the Partitioning option JServer Release 8.1.7.0.0 - Production
 255          // $vers = OCIServerVersion($this->_connectionID);
 256          // if (strpos($vers,'8i') !== false) $this->ansiOuter = true;
 257          return true;
 258         }
 259      
 260  	function ServerInfo()
 261      {
 262          $arr['compat'] = $this->GetOne('select value from sys.database_compatible_level');
 263          $arr['description'] = @OCIServerVersion($this->_connectionID);
 264          $arr['version'] = ADOConnection::_findvers($arr['description']);
 265          return $arr;
 266      }
 267          // returns true or false
 268  	function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
 269      {
 270          return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,1);
 271      }
 272      
 273      // returns true or false
 274  	function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
 275      {
 276          return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,2);
 277      }
 278      
 279  	function _affectedrows()
 280      {
 281          if (is_resource($this->_stmt)) return @OCIRowCount($this->_stmt);
 282          return 0;
 283      }
 284      
 285  	function IfNull( $field, $ifNull ) 
 286      {
 287          return " NVL($field, $ifNull) "; // if Oracle
 288      }
 289      
 290      // format and return date string in database date format
 291  	function DBDate($d,$isfld=false)
 292      {
 293          if (empty($d) && $d !== 0) return 'null';
 294          if ($isfld) return 'TO_DATE('.$d.",'".$this->dateformat."')";
 295          
 296          if (is_string($d)) $d = ADORecordSet::UnixDate($d);
 297          
 298          if (is_object($d)) $ds = $d->format($this->fmtDate);
 299          else $ds = adodb_date($this->fmtDate,$d);
 300          
 301          return "TO_DATE(".$ds.",'".$this->dateformat."')";
 302      }
 303  
 304  	function BindDate($d)
 305      {
 306          $d = ADOConnection::DBDate($d);
 307          if (strncmp($d,"'",1)) return $d;
 308          
 309          return substr($d,1,strlen($d)-2);
 310      }
 311      
 312  	function BindTimeStamp($ts)
 313      {
 314          if (empty($ts) && $ts !== 0) return 'null';
 315          if (is_string($ts)) $ts = ADORecordSet::UnixTimeStamp($ts);
 316          
 317          if (is_object($ts)) $tss = $ts->format("'Y-m-d H:i:s'");
 318          else $tss = adodb_date("'Y-m-d H:i:s'",$ts);
 319          
 320          return $tss;
 321      }
 322      
 323      // format and return date string in database timestamp format
 324  	function DBTimeStamp($ts,$isfld=false)
 325      {
 326          if (empty($ts) && $ts !== 0) return 'null';
 327          if ($isfld) return 'TO_DATE(substr('.$ts.",1,19),'RRRR-MM-DD, HH24:MI:SS')";
 328          if (is_string($ts)) $ts = ADORecordSet::UnixTimeStamp($ts);
 329          
 330          if (is_object($ts)) $tss = $ts->format("'Y-m-d H:i:s'");
 331          else $tss = adodb_date("'Y-m-d H:i:s'",$ts);
 332          
 333          return 'TO_DATE('.$tss.",'RRRR-MM-DD, HH24:MI:SS')";
 334      }
 335      
 336  	function RowLock($tables,$where,$col='1 as adodbignore') 
 337      {
 338          if ($this->autoCommit) $this->BeginTrans();
 339          return $this->GetOne("select $col from $tables where $where for update");
 340      }
 341      
 342  	function MetaTables($ttype=false,$showSchema=false,$mask=false) 
 343      {
 344          if ($mask) {
 345              $save = $this->metaTablesSQL;
 346              $mask = $this->qstr(strtoupper($mask));
 347              $this->metaTablesSQL .= " AND upper(table_name) like $mask";
 348          }
 349          $ret = ADOConnection::MetaTables($ttype,$showSchema);
 350          
 351          if ($mask) {
 352              $this->metaTablesSQL = $save;
 353          }
 354          return $ret;
 355      }
 356      
 357      // Mark Newnham 
 358  	function MetaIndexes ($table, $primary = FALSE, $owner=false)
 359      {
 360          // save old fetch mode
 361          global $ADODB_FETCH_MODE;
 362  
 363          $save = $ADODB_FETCH_MODE;
 364          $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
 365  
 366          if ($this->fetchMode !== FALSE) {
 367                 $savem = $this->SetFetchMode(FALSE);
 368          }
 369  
 370          // get index details
 371          $table = strtoupper($table);
 372  
 373          // get Primary index
 374          $primary_key = '';
 375  
 376          $false = false;
 377          $rs = $this->Execute(sprintf("SELECT * FROM ALL_CONSTRAINTS WHERE UPPER(TABLE_NAME)='%s' AND CONSTRAINT_TYPE='P'",$table));
 378          if ($row = $rs->FetchRow())
 379             $primary_key = $row[1]; //constraint_name
 380  
 381          if ($primary==TRUE && $primary_key=='') {
 382               if (isset($savem)) 
 383                  $this->SetFetchMode($savem);
 384              $ADODB_FETCH_MODE = $save;
 385              return $false; //There is no primary key
 386          }
 387  
 388          $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));
 389  
 390          
 391          if (!is_object($rs)) {
 392              if (isset($savem)) 
 393                  $this->SetFetchMode($savem);
 394              $ADODB_FETCH_MODE = $save;
 395              return $false;
 396          }
 397  
 398          $indexes = array ();
 399          // parse index data into array
 400  
 401          while ($row = $rs->FetchRow()) {
 402              if ($primary && $row[0] != $primary_key) continue;
 403              if (!isset($indexes[$row[0]])) {
 404                  $indexes[$row[0]] = array(
 405                     'unique' => ($row[1] == 'UNIQUE'),
 406                     'columns' => array()
 407                  );
 408              }
 409              $indexes[$row[0]]['columns'][$row[2] - 1] = $row[3];
 410          }
 411  
 412          // sort columns by order in the index
 413          foreach ( array_keys ($indexes) as $index ) {
 414              ksort ($indexes[$index]['columns']);
 415          }
 416  
 417          if (isset($savem)) { 
 418              $this->SetFetchMode($savem);
 419              $ADODB_FETCH_MODE = $save;
 420          }
 421          return $indexes;
 422      }
 423      
 424  	function BeginTrans()
 425      {    
 426          if ($this->transOff) return true;
 427          $this->transCnt += 1;
 428          $this->autoCommit = false;
 429          $this->_commit = OCI_DEFAULT;
 430          
 431          if ($this->_transmode) $ok = $this->Execute("SET TRANSACTION ".$this->_transmode);
 432          else $ok = true;
 433          
 434          return $ok ? true : false;
 435      }
 436      
 437  	function CommitTrans($ok=true) 
 438      { 
 439          if ($this->transOff) return true;
 440          if (!$ok) return $this->RollbackTrans();
 441          
 442          if ($this->transCnt) $this->transCnt -= 1;
 443          $ret = OCIcommit($this->_connectionID);
 444          $this->_commit = OCI_COMMIT_ON_SUCCESS;
 445          $this->autoCommit = true;
 446          return $ret;
 447      }
 448      
 449  	function RollbackTrans()
 450      {
 451          if ($this->transOff) return true;
 452          if ($this->transCnt) $this->transCnt -= 1;
 453          $ret = OCIrollback($this->_connectionID);
 454          $this->_commit = OCI_COMMIT_ON_SUCCESS;
 455          $this->autoCommit = true;
 456          return $ret;
 457      }
 458      
 459      
 460  	function SelectDB($dbName) 
 461      {
 462          return false;
 463      }
 464  
 465  	function ErrorMsg() 
 466      {
 467          if ($this->_errorMsg !== false) return $this->_errorMsg;
 468  
 469          if (is_resource($this->_stmt)) $arr = @OCIError($this->_stmt);
 470          if (empty($arr)) {
 471              if (is_resource($this->_connectionID)) $arr = @OCIError($this->_connectionID);
 472              else $arr = @OCIError();
 473              if ($arr === false) return '';
 474          }
 475          $this->_errorMsg = $arr['message'];
 476          $this->_errorCode = $arr['code'];
 477          return $this->_errorMsg;
 478      }
 479  
 480  	function ErrorNo() 
 481      {
 482          if ($this->_errorCode !== false) return $this->_errorCode;
 483          
 484          if (is_resource($this->_stmt)) $arr = @OCIError($this->_stmt);
 485          if (empty($arr)) {
 486              $arr = @OCIError($this->_connectionID);
 487              if ($arr == false) $arr = @OCIError();
 488              if ($arr == false) return '';
 489          }
 490          
 491          $this->_errorMsg = $arr['message'];
 492          $this->_errorCode = $arr['code'];
 493          
 494          return $arr['code'];
 495      }
 496      
 497      // Format date column in sql string given an input format that understands Y M D
 498  	function SQLDate($fmt, $col=false)
 499      {    
 500          if (!$col) $col = $this->sysTimeStamp;
 501          $s = 'TO_CHAR('.$col.",'";
 502          
 503          $len = strlen($fmt);
 504          for ($i=0; $i < $len; $i++) {
 505              $ch = $fmt[$i];
 506              switch($ch) {
 507              case 'Y':
 508              case 'y':
 509                  $s .= 'YYYY';
 510                  break;
 511              case 'Q':
 512              case 'q':
 513                  $s .= 'Q';
 514                  break;
 515                  
 516              case 'M':
 517                  $s .= 'Mon';
 518                  break;
 519                  
 520              case 'm':
 521                  $s .= 'MM';
 522                  break;
 523              case 'D':
 524              case 'd':
 525                  $s .= 'DD';
 526                  break;
 527              
 528              case 'H':
 529                  $s.= 'HH24';
 530                  break;
 531                  
 532              case 'h':
 533                  $s .= 'HH';
 534                  break;
 535                  
 536              case 'i':
 537                  $s .= 'MI';
 538                  break;
 539              
 540              case 's':
 541                  $s .= 'SS';
 542                  break;
 543              
 544              case 'a':
 545              case 'A':
 546                  $s .= 'AM';
 547                  break;
 548                  
 549              case 'w':
 550                  $s .= 'D';
 551                  break;
 552                  
 553              case 'l':
 554                  $s .= 'DAY';
 555                  break;
 556                  
 557               case 'W':
 558                  $s .= 'WW';
 559                  break;
 560                  
 561              default:
 562              // handle escape characters...
 563                  if ($ch == '\\') {
 564                      $i++;
 565                      $ch = substr($fmt,$i,1);
 566                  }
 567                  if (strpos('-/.:;, ',$ch) !== false) $s .= $ch;
 568                  else $s .= '"'.$ch.'"';
 569                  
 570              }
 571          }
 572          return $s. "')";
 573      }
 574      
 575  	function GetRandRow($sql, $arr = false)
 576      {
 577          $sql = "SELECT * FROM ($sql ORDER BY dbms_random.value) WHERE rownum = 1";
 578          
 579          return $this->GetRow($sql,$arr);
 580      }
 581      
 582      /*
 583      This algorithm makes use of
 584      
 585      a. FIRST_ROWS hint
 586      The FIRST_ROWS hint explicitly chooses the approach to optimize response time, 
 587      that is, minimum resource usage to return the first row. Results will be returned 
 588      as soon as they are identified. 
 589  
 590      b. Uses rownum tricks to obtain only the required rows from a given offset.
 591       As this uses complicated sql statements, we only use this if the $offset >= 100. 
 592       This idea by Tomas V V Cox.
 593       
 594       This implementation does not appear to work with oracle 8.0.5 or earlier. Comment
 595       out this function then, and the slower SelectLimit() in the base class will be used.
 596      */
 597  	function SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
 598      {
 599          // seems that oracle only supports 1 hint comment in 8i
 600          if ($this->firstrows) {
 601              if (strpos($sql,'/*+') !== false)
 602                  $sql = str_replace('/*+ ','/*+FIRST_ROWS ',$sql);
 603              else
 604                  $sql = preg_replace('/^[ \t\n]*select/i','SELECT /*+FIRST_ROWS*/',$sql);
 605          }
 606          
 607          if ($offset == -1 || ($offset < $this->selectOffsetAlg1 && 0 < $nrows && $nrows < 1000)) {
 608              if ($nrows > 0) {    
 609                  if ($offset > 0) $nrows += $offset;
 610                  //$inputarr['adodb_rownum'] = $nrows;
 611                  if ($this->databaseType == 'oci8po') {
 612                      $sql = "select * from (".$sql.") where rownum <= ?";
 613                  } else {
 614                      $sql = "select * from (".$sql.") where rownum <= :adodb_offset";
 615                  } 
 616                  $inputarr['adodb_offset'] = $nrows;
 617                  $nrows = -1;
 618              }
 619              // note that $nrows = 0 still has to work ==> no rows returned
 620  
 621              $rs = ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
 622              return $rs;
 623              
 624          } else {
 625               // Algorithm by Tomas V V Cox, from PEAR DB oci8.php
 626              
 627               // Let Oracle return the name of the columns
 628              $q_fields = "SELECT * FROM (".$sql.") WHERE NULL = NULL";
 629          
 630              $false = false;
 631              if (! $stmt_arr = $this->Prepare($q_fields)) {
 632                  return $false;
 633              }
 634              $stmt = $stmt_arr[1];
 635               
 636              if (is_array($inputarr)) {
 637                   foreach($inputarr as $k => $v) {
 638                      if (is_array($v)) {
 639                          if (sizeof($v) == 2) // suggested by g.giunta@libero.
 640                              OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]);
 641                          else
 642                              OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1],$v[2]);
 643                      } else {
 644                          $len = -1;
 645                          if ($v === ' ') $len = 1;
 646                          if (isset($bindarr)) {    // is prepared sql, so no need to ocibindbyname again
 647                              $bindarr[$k] = $v;
 648                          } else {                 // dynamic sql, so rebind every time
 649                              OCIBindByName($stmt,":$k",$inputarr[$k],$len);
 650                              
 651                          }
 652                      }
 653                  }
 654              }
 655              
 656               if (!OCIExecute($stmt, OCI_DEFAULT)) {
 657                   OCIFreeStatement($stmt); 
 658                   return $false;
 659               }
 660               
 661               $ncols = OCINumCols($stmt);
 662               for ( $i = 1; $i <= $ncols; $i++ ) {
 663                   $cols[] = '"'.OCIColumnName($stmt, $i).'"';
 664               }
 665               $result = false;
 666              
 667               OCIFreeStatement($stmt); 
 668               $fields = implode(',', $cols);
 669               if ($nrows <= 0) $nrows = 999999999999;
 670               else $nrows += $offset;
 671               $offset += 1; // in Oracle rownum starts at 1
 672              
 673              if ($this->databaseType == 'oci8po') {
 674                       $sql = "SELECT /*+ FIRST_ROWS */ $fields FROM".
 675                        "(SELECT rownum as adodb_rownum, $fields FROM".
 676                        " ($sql) WHERE rownum <= ?".
 677                        ") WHERE adodb_rownum >= ?";
 678                  } else {
 679                       $sql = "SELECT /*+ FIRST_ROWS */ $fields FROM".
 680                        "(SELECT rownum as adodb_rownum, $fields FROM".
 681                        " ($sql) WHERE rownum <= :adodb_nrows".
 682                        ") WHERE adodb_rownum >= :adodb_offset";
 683                  } 
 684                  $inputarr['adodb_nrows'] = $nrows;
 685                  $inputarr['adodb_offset'] = $offset;
 686                  
 687              if ($secs2cache>0) $rs = $this->CacheExecute($secs2cache, $sql,$inputarr);
 688              else $rs = $this->Execute($sql,$inputarr);
 689              return $rs;
 690          }
 691      
 692      }
 693      
 694      /**
 695      * Usage:
 696      * Store BLOBs and CLOBs
 697      *
 698      * Example: to store $var in a blob
 699      *
 700      *    $conn->Execute('insert into TABLE (id,ablob) values(12,empty_blob())');
 701      *    $conn->UpdateBlob('TABLE', 'ablob', $varHoldingBlob, 'ID=12', 'BLOB');
 702      *    
 703      *    $blobtype supports 'BLOB' and 'CLOB', but you need to change to 'empty_clob()'.
 704      *
 705      *  to get length of LOB:
 706      *      select DBMS_LOB.GETLENGTH(ablob) from TABLE
 707      *
 708      * If you are using CURSOR_SHARING = force, it appears this will case a segfault
 709      * under oracle 8.1.7.0. Run:
 710      *     $db->Execute('ALTER SESSION SET CURSOR_SHARING=EXACT');
 711      * before UpdateBlob() then...
 712      */
 713  
 714  	function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
 715      {
 716          
 717          //if (strlen($val) < 4000) return $this->Execute("UPDATE $table SET $column=:blob WHERE $where",array('blob'=>$val)) != false;
 718          
 719          switch(strtoupper($blobtype)) {
 720          default: ADOConnection::outp("<b>UpdateBlob</b>: Unknown blobtype=$blobtype"); return false;
 721          case 'BLOB': $type = OCI_B_BLOB; break;
 722          case 'CLOB': $type = OCI_B_CLOB; break;
 723          }
 724          
 725          if ($this->databaseType == 'oci8po') 
 726              $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO ?";
 727          else 
 728              $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO :blob";
 729          
 730          $desc = OCINewDescriptor($this->_connectionID, OCI_D_LOB);
 731          $arr['blob'] = array($desc,-1,$type);
 732          if ($this->session_sharing_force_blob) $this->Execute('ALTER SESSION SET CURSOR_SHARING=EXACT');
 733          $commit = $this->autoCommit;
 734          if ($commit) $this->BeginTrans();
 735          $rs = $this->_Execute($sql,$arr);
 736          if ($rez = !empty($rs)) $desc->save($val);
 737          $desc->free();
 738          if ($commit) $this->CommitTrans();
 739          if ($this->session_sharing_force_blob) $this->Execute('ALTER SESSION SET CURSOR_SHARING=FORCE');
 740          
 741          if ($rez) $rs->Close();
 742          return $rez;
 743      }
 744      
 745      /**
 746      * Usage:  store file pointed to by $val in a blob
 747      */
 748  	function UpdateBlobFile($table,$column,$val,$where,$blobtype='BLOB')
 749      {
 750          switch(strtoupper($blobtype)) {
 751          default: ADOConnection::outp( "<b>UpdateBlob</b>: Unknown blobtype=$blobtype"); return false;
 752          case 'BLOB': $type = OCI_B_BLOB; break;
 753          case 'CLOB': $type = OCI_B_CLOB; break;
 754          }
 755          
 756          if ($this->databaseType == 'oci8po') 
 757              $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO ?";
 758          else 
 759              $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO :blob";
 760          
 761          $desc = OCINewDescriptor($this->_connectionID, OCI_D_LOB);
 762          $arr['blob'] = array($desc,-1,$type);
 763          
 764          $this->BeginTrans();
 765          $rs = ADODB_oci8::Execute($sql,$arr);
 766          if ($rez = !empty($rs)) $desc->savefile($val);
 767          $desc->free();
 768          $this->CommitTrans();
 769          
 770          if ($rez) $rs->Close();
 771          return $rez;
 772      }
 773  
 774          /**
 775       * Execute SQL 
 776       *
 777       * @param sql        SQL statement to execute, or possibly an array holding prepared statement ($sql[0] will hold sql text)
 778       * @param [inputarr]    holds the input data to bind to. Null elements will be set to null.
 779       * @return         RecordSet or false
 780       */
 781  	function Execute($sql,$inputarr=false) 
 782      {
 783          if ($this->fnExecute) {
 784              $fn = $this->fnExecute;
 785              $ret = $fn($this,$sql,$inputarr);
 786              if (isset($ret)) return $ret;
 787          }
 788          if ($inputarr) {
 789              #if (!is_array($inputarr)) $inputarr = array($inputarr);
 790              
 791              $element0 = reset($inputarr);
 792              
 793              if (!$this->_bindInputArray) {
 794              # is_object check because oci8 descriptors can be passed in
 795              if (is_array($element0) && !is_object(reset($element0))) {
 796                  if (is_string($sql))
 797                      $stmt = $this->Prepare($sql);
 798                  else
 799                      $stmt = $sql;
 800                      
 801                  foreach($inputarr as $arr) {
 802                      $ret = $this->_Execute($stmt,$arr);
 803                      if (!$ret) return $ret;
 804                  }
 805              } else {
 806                  $sqlarr = explode(':',$sql);
 807                  $sql = '';
 808                  $lastnomatch = -2;
 809                  #var_dump($sqlarr);echo "<hr>";var_dump($inputarr);echo"<hr>";
 810                  foreach($sqlarr as $k => $str) {
 811                          if ($k == 0) { $sql = $str; continue; }
 812                          // we need $lastnomatch because of the following datetime, 
 813                          // eg. '10:10:01', which causes code to think that there is bind param :10 and :1
 814                          $ok = preg_match('/^([0-9]*)/', $str, $arr); 
 815              
 816                          if (!$ok) $sql .= $str;
 817                          else {
 818                              $at = $arr[1];
 819                              if (isset($inputarr[$at]) || is_null($inputarr[$at])) {
 820                                  if ((strlen($at) == strlen($str) && $k < sizeof($arr)-1)) {
 821                                      $sql .= ':'.$str;
 822                                      $lastnomatch = $k;
 823                                  } else if ($lastnomatch == $k-1) {
 824                                      $sql .= ':'.$str;
 825                                  } else {
 826                                      if (is_null($inputarr[$at])) $sql .= 'null';
 827                                      else $sql .= $this->qstr($inputarr[$at]);
 828                                      $sql .= substr($str, strlen($at));
 829                                  }
 830                              } else {
 831                                  $sql .= ':'.$str;
 832                              }
 833                              
 834                          }
 835                      }
 836                      $inputarr = false;
 837                  }
 838              }
 839              $ret = $this->_Execute($sql,$inputarr);
 840              
 841              
 842          } else {
 843              $ret = $this->_Execute($sql,false);
 844          }
 845  
 846          return $ret;
 847      }
 848      
 849      /*
 850          Example of usage:
 851          
 852          $stmt = $this->Prepare('insert into emp (empno, ename) values (:empno, :ename)');
 853      */
 854  	function Prepare($sql,$cursor=false)
 855      {
 856      static $BINDNUM = 0;
 857      
 858          $stmt = OCIParse($this->_connectionID,$sql);
 859  
 860          if (!$stmt) {
 861              $this->_errorMsg = false;
 862              $this->_errorCode = false;
 863              $arr = @OCIError($this->_connectionID);
 864              if ($arr === false) return false;
 865          
 866              $this->_errorMsg = $arr['message'];
 867              $this->_errorCode = $arr['code'];
 868              return false;
 869          }
 870          
 871          $BINDNUM += 1;
 872          
 873          $sttype = @OCIStatementType($stmt);
 874          if ($sttype == 'BEGIN' || $sttype == 'DECLARE') {
 875              return array($sql,$stmt,0,$BINDNUM, ($cursor) ? OCINewCursor($this->_connectionID) : false);
 876          }
 877          return array($sql,$stmt,0,$BINDNUM);
 878      }
 879      
 880      /*
 881          Call an oracle stored procedure and returns a cursor variable as a recordset. 
 882          Concept by Robert Tuttle robert@ud.com
 883          
 884          Example:
 885              Note: we return a cursor variable in :RS2
 886              $rs = $db->ExecuteCursor("BEGIN adodb.open_tab(:RS2); END;",'RS2');
 887              
 888              $rs = $db->ExecuteCursor(
 889                  "BEGIN :RS2 = adodb.getdata(:VAR1); END;", 
 890                  'RS2',
 891                  array('VAR1' => 'Mr Bean'));
 892              
 893      */
 894  	function ExecuteCursor($sql,$cursorName='rs',$params=false)
 895      {
 896          if (is_array($sql)) $stmt = $sql;
 897          else $stmt = ADODB_oci8::Prepare($sql,true); # true to allocate OCINewCursor
 898      
 899          if (is_array($stmt) && sizeof($stmt) >= 5) {
 900              $hasref = true;
 901              $ignoreCur = false;
 902              $this->Parameter($stmt, $ignoreCur, $cursorName, false, -1, OCI_B_CURSOR);
 903              if ($params) {
 904                  foreach($params as $k => $v) {
 905                      $this->Parameter($stmt,$params[$k], $k);
 906                  }
 907              }
 908          } else
 909              $hasref = false;
 910              
 911          $rs = $this->Execute($stmt);
 912          if ($rs) {
 913              if ($rs->databaseType == 'array') OCIFreeCursor($stmt[4]);
 914              else if ($hasref) $rs->_refcursor = $stmt[4];
 915          }
 916          return $rs;
 917      }
 918      
 919      /*
 920          Bind a variable -- very, very fast for executing repeated statements in oracle. 
 921          Better than using
 922              for ($i = 0; $i < $max; $i++) {    
 923                  $p1 = ?; $p2 = ?; $p3 = ?;
 924                  $this->Execute("insert into table (col0, col1, col2) values (:0, :1, :2)", 
 925                      array($p1,$p2,$p3));
 926              }
 927          
 928          Usage:
 929              $stmt = $DB->Prepare("insert into table (col0, col1, col2) values (:0, :1, :2)");
 930              $DB->Bind($stmt, $p1);
 931              $DB->Bind($stmt, $p2);
 932              $DB->Bind($stmt, $p3);
 933              for ($i = 0; $i < $max; $i++) {    
 934                  $p1 = ?; $p2 = ?; $p3 = ?;
 935                  $DB->Execute($stmt);
 936              }
 937              
 938          Some timings:        
 939              ** Test table has 3 cols, and 1 index. Test to insert 1000 records
 940              Time 0.6081s (1644.60 inserts/sec) with direct OCIParse/OCIExecute
 941              Time 0.6341s (1577.16 inserts/sec) with ADOdb Prepare/Bind/Execute
 942              Time 1.5533s ( 643.77 inserts/sec) with pure SQL using Execute
 943              
 944          Now if PHP only had batch/bulk updating like Java or PL/SQL...
 945      
 946          Note that the order of parameters differs from OCIBindByName,
 947          because we default the names to :0, :1, :2
 948      */
 949  	function Bind(&$stmt,&$var,$size=4000,$type=false,$name=false,$isOutput=false)
 950      {
 951          
 952          if (!is_array($stmt)) return false;
 953          
 954          if (($type == OCI_B_CURSOR) && sizeof($stmt) >= 5) { 
 955              return OCIBindByName($stmt[1],":".$name,$stmt[4],$size,$type);
 956          }
 957          
 958          if ($name == false) {
 959              if ($type !== false) $rez = OCIBindByName($stmt[1],":".$stmt[2],$var,$size,$type);
 960              else $rez = OCIBindByName($stmt[1],":".$stmt[2],$var,$size); // +1 byte for null terminator
 961              $stmt[2] += 1;
 962          } else if (oci_lob_desc($type)) {
 963              if ($this->debug) {
 964                  ADOConnection::outp("<b>Bind</b>: name = $name");
 965              }
 966              //we have to create a new Descriptor here
 967              $numlob = count($this->_refLOBs);
 968              $this->_refLOBs[$numlob]['LOB'] = OCINewDescriptor($this->_connectionID, oci_lob_desc($type));
 969              $this->_refLOBs[$numlob]['TYPE'] = $isOutput;
 970              
 971              $tmp = $this->_refLOBs[$numlob]['LOB'];
 972              $rez = OCIBindByName($stmt[1], ":".$name, $tmp, -1, $type);
 973              if ($this->debug) {
 974                  ADOConnection::outp("<b>Bind</b>: descriptor has been allocated, var (".$name.") binded");
 975              }
 976              
 977              // if type is input then write data to lob now
 978              if ($isOutput == false) {
 979                  $var = $this->BlobEncode($var);
 980                  $tmp->WriteTemporary($var);
 981                  $this->_refLOBs[$numlob]['VAR'] = &$var;
 982                  if ($this->debug) {
 983                      ADOConnection::outp("<b>Bind</b>: LOB has been written to temp");
 984                  }
 985              } else {
 986                  $this->_refLOBs[$numlob]['VAR'] = &$var;
 987              }
 988              $rez = $tmp;
 989          } else {
 990              if ($this->debug) 
 991                  ADOConnection::outp("<b>Bind</b>: name = $name");
 992              
 993              if ($type !== false) $rez = OCIBindByName($stmt[1],":".$name,$var,$size,$type);
 994              else $rez = OCIBindByName($stmt[1],":".$name,$var,$size); // +1 byte for null terminator
 995          }
 996          
 997          return $rez;
 998      }
 999      
1000  	function Param($name,$type=false)
1001      {
1002          return ':'.$name;
1003      }
1004      
1005      /* 
1006      Usage:
1007          $stmt = $db->Prepare('select * from table where id =:myid and group=:group');
1008          $db->Parameter($stmt,$id,'myid');
1009          $db->Parameter($stmt,$group,'group');
1010          $db->Execute($stmt);
1011          
1012          @param $stmt Statement returned by Prepare() or PrepareSP().
1013          @param $var PHP variable to bind to
1014          @param $name Name of stored procedure variable name to bind to.
1015          @param [$isOutput] Indicates direction of parameter 0/false=IN  1=OUT  2= IN/OUT. This is ignored in oci8.
1016          @param [$maxLen] Holds an maximum length of the variable.
1017          @param [$type] The data type of $var. Legal values depend on driver.
1018          
1019          See OCIBindByName documentation at php.net.
1020      */
1021  	function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false)
1022      {
1023              if  ($this->debug) {
1024                  $prefix = ($isOutput) ? 'Out' : 'In';
1025                  $ztype = (empty($type)) ? 'false' : $type;
1026                  ADOConnection::outp( "{$prefix}Parameter(\$stmt, \$php_var='$var', \$name='$name', \$maxLen=$maxLen, \$type=$ztype);");
1027              }
1028              return $this->Bind($stmt,$var,$maxLen,$type,$name,$isOutput);
1029      }
1030      
1031      /*
1032      returns query ID if successful, otherwise false
1033      this version supports:
1034      
1035         1. $db->execute('select * from table');
1036         
1037         2. $db->prepare('insert into table (a,b,c) values (:0,:1,:2)');
1038            $db->execute($prepared_statement, array(1,2,3));
1039            
1040         3. $db->execute('insert into table (a,b,c) values (:a,:b,:c)',array('a'=>1,'b'=>2,'c'=>3));
1041         
1042         4. $db->prepare('insert into table (a,b,c) values (:0,:1,:2)');
1043            $db->bind($stmt,1); $db->bind($stmt,2); $db->bind($stmt,3); 
1044            $db->execute($stmt);
1045      */ 
1046  	function _query($sql,$inputarr=false)
1047      {
1048          if (is_array($sql)) { // is prepared sql
1049              $stmt = $sql[1];
1050              
1051              // we try to bind to permanent array, so that OCIBindByName is persistent
1052              // and carried out once only - note that max array element size is 4000 chars
1053              if (is_array($inputarr)) {
1054                  $bindpos = $sql[3];
1055                  if (isset($this->_bind[$bindpos])) {
1056                  // all tied up already
1057                      $bindarr = $this->_bind[$bindpos];
1058                  } else {
1059                  // one statement to bind them all
1060                      $bindarr = array();
1061                      foreach($inputarr as $k => $v) {
1062                          $bindarr[$k] = $v;
1063                          OCIBindByName($stmt,":$k",$bindarr[$k],is_string($v) && strlen($v)>4000 ? -1 : 4000);
1064                      }
1065                      $this->_bind[$bindpos] = $bindarr;
1066                  }
1067              }
1068          } else {
1069              $stmt=OCIParse($this->_connectionID,$sql);
1070          }
1071              
1072          $this->_stmt = $stmt;
1073          if (!$stmt) return false;
1074      
1075          if (defined('ADODB_PREFETCH_ROWS')) @OCISetPrefetch($stmt,ADODB_PREFETCH_ROWS);
1076              
1077          if (is_array($inputarr)) {
1078              foreach($inputarr as $k => $v) {
1079                  if (is_array($v)) {
1080                      if (sizeof($v) == 2) // suggested by g.giunta@libero.
1081                          OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]);
1082                      else
1083                          OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1],$v[2]);
1084                      
1085                      if ($this->debug==99) {
1086                          if (is_object($v[0])) 
1087                              echo "name=:$k",' len='.$v[1],' type='.$v[2],'<br>';
1088                          else
1089                              echo "name=:$k",' var='.$inputarr[$k][0],' len='.$v[1],' type='.$v[2],'<br>';
1090                          
1091                      }
1092                  } else {
1093                      $len = -1;
1094                      if ($v === ' ') $len = 1;
1095                      if (isset($bindarr)) {    // is prepared sql, so no need to ocibindbyname again
1096                          $bindarr[$k] = $v;
1097                      } else {                 // dynamic sql, so rebind every time
1098                          OCIBindByName($stmt,":$k",$inputarr[$k],$len);
1099                      }
1100                  }
1101              }
1102          }
1103          
1104          $this->_errorMsg = false;
1105          $this->_errorCode = false;
1106          if (OCIExecute($stmt,$this->_commit)) {
1107  //OCIInternalDebug(1);            
1108              if (count($this -> _refLOBs) > 0) {
1109          
1110                  foreach ($this -> _refLOBs as $key => $value) {
1111                      if ($this -> _refLOBs[$key]['TYPE'] == true) {
1112                          $tmp = $this -> _refLOBs[$key]['LOB'] -> load();
1113                          if ($this -> debug) {
1114                              ADOConnection::outp("<b>OUT LOB</b>: LOB has been loaded. <br>");
1115                          }
1116                          //$_GLOBALS[$this -> _refLOBs[$key]['VAR']] = $tmp;
1117                          $this -> _refLOBs[$key]['VAR'] = $tmp;
1118                      } else {
1119                          $this->_refLOBs[$key]['LOB']->save($this->_refLOBs[$key]['VAR']);
1120                          $this -> _refLOBs[$key]['LOB']->free();
1121                          unset($this -> _refLOBs[$key]);
1122                          if ($this->debug) {
1123                              ADOConnection::outp("<b>IN LOB</b>: LOB has been saved. <br>");
1124                          }
1125                      }                    
1126                  }
1127              }
1128          
1129              switch (@OCIStatementType($stmt)) {
1130                  case "SELECT":
1131                      return $stmt;
1132                  
1133                  case 'DECLARE':
1134                  case "BEGIN":
1135                      if (is_array($sql) && !empty($sql[4])) {
1136                          $cursor = $sql[4];
1137                          if (is_resource($cursor)) {
1138                              $ok = OCIExecute($cursor);    
1139                              return $cursor;
1140                          }
1141                          return $stmt;
1142                      } else {
1143                          if (is_resource($stmt)) {
1144                              OCIFreeStatement($stmt);
1145                              return true;
1146                          }
1147                          return $stmt;
1148                      }
1149                      break;
1150                  default :
1151                      // ociclose -- no because it could be used in a LOB?
1152                      return true;
1153              }
1154          }
1155          return false;
1156      }
1157      
1158      // From Oracle Whitepaper: PHP Scalability and High Availability
1159  	function IsConnectionError($err)
1160      {
1161          switch($err) {
1162              case 378: /* buffer pool param incorrect */
1163              case 602: /* core dump */
1164              case 603: /* fatal error */
1165              case 609: /* attach failed */
1166              case 1012: /* not logged in */
1167              case 1033: /* init or shutdown in progress */
1168              case 1043: /* Oracle not available */
1169              case 1089: /* immediate shutdown in progress */
1170              case 1090: /* shutdown in progress */
1171              case 1092: /* instance terminated */
1172              case 3113: /* disconnect */
1173              case 3114: /* not connected */
1174              case 3122: /* closing window */
1175              case 3135: /* lost contact */
1176              case 12153: /* TNS: not connected */
1177              case 27146: /* fatal or instance terminated */
1178              case 28511: /* Lost RPC */
1179              return true;
1180          }
1181          return false;
1182      }
1183      
1184      // returns true or false
1185  	function _close()
1186      {
1187          if (!$this->_connectionID) return;
1188          
1189          if (!$this->autoCommit) OCIRollback($this->_connectionID);
1190          if (count($this->_refLOBs) > 0) {
1191              foreach ($this ->_refLOBs as $key => $value) {
1192                  $this->_refLOBs[$key]['LOB']->free();
1193                  unset($this->_refLOBs[$key]);
1194              }
1195          }
1196          OCILogoff($this->_connectionID);
1197          
1198          $this->_stmt = false;
1199          $this->_connectionID = false;
1200      }
1201      
1202  	function MetaPrimaryKeys($table, $owner=false,$internalKey=false)
1203      {
1204          if ($internalKey) return array('ROWID');
1205          
1206      // tested with oracle 8.1.7
1207          $table = strtoupper($table);
1208          if ($owner) {
1209              $owner_clause = "AND ((a.OWNER = b.OWNER) AND (a.OWNER = UPPER('$owner')))";
1210              $ptab = 'ALL_';
1211          } else {
1212              $owner_clause = '';
1213              $ptab = 'USER_';
1214          }
1215          $sql = "
1216  SELECT /*+ RULE */ distinct b.column_name
1217     FROM {$ptab}CONSTRAINTS a
1218        , {$ptab}CONS_COLUMNS b
1219    WHERE ( UPPER(b.table_name) = ('$table'))
1220      AND (UPPER(a.table_name) = ('$table') and a.constraint_type = 'P')
1221      $owner_clause
1222      AND (a.constraint_name = b.constraint_name)";
1223  
1224           $rs = $this->Execute($sql);
1225          if ($rs && !$rs->EOF) {
1226              $arr = $rs->GetArray();
1227              $a = array();
1228              foreach($arr as $v) {
1229                  $a[] = reset($v);
1230              }
1231              return $a;
1232          }
1233          else return false;
1234      }
1235      
1236      // http://gis.mit.edu/classes/11.521/sqlnotes/referential_integrity.html
1237  	function MetaForeignKeys($table, $owner=false)
1238      {
1239      global $ADODB_FETCH_MODE;
1240      
1241          $save = $ADODB_FETCH_MODE;
1242          $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
1243          $table = $this->qstr(strtoupper($table));
1244          if (!$owner) {
1245              $owner = $this->user;
1246              $tabp = 'user_';
1247          } else
1248              $tabp = 'all_';
1249              
1250          $owner = ' and owner='.$this->qstr(strtoupper($owner));
1251          
1252          $sql = 
1253  "select constraint_name,r_owner,r_constraint_name 
1254      from {$tabp}constraints
1255      where constraint_type = 'R' and table_name = $table $owner";
1256          
1257          $constraints = $this->GetArray($sql);
1258          $arr = false;
1259          foreach($constraints as $constr) {
1260              $cons = $this->qstr($constr[0]);
1261              $rowner = $this->qstr($constr[1]);
1262              $rcons = $this->qstr($constr[2]);
1263              $cols = $this->GetArray("select column_name from {$tabp}cons_columns where constraint_name=$cons $owner order by position");
1264              $tabcol = $this->GetArray("select table_name,column_name from {$tabp}cons_columns where owner=$rowner and constraint_name=$rcons order by position");
1265              
1266              if ($cols && $tabcol) 
1267                  for ($i=0, $max=sizeof($cols); $i < $max; $i++) {
1268                      $arr[$tabcol[$i][0]] = $cols[$i][0].'='.$tabcol[$i][1];
1269                  }
1270          }
1271          $ADODB_FETCH_MODE = $save;
1272          
1273          return $arr;
1274      }
1275  
1276      
1277  	function CharMax()
1278      {
1279          return 4000;
1280      }
1281      
1282  	function TextMax()
1283      {
1284          return 4000;
1285      }
1286      
1287      /**
1288       * Quotes a string.
1289       * An example is  $db->qstr("Don't bother",magic_quotes_runtime());
1290       * 
1291       * @param s            the string to quote
1292       * @param [magic_quotes]    if $s is GET/POST var, set to get_magic_quotes_gpc().
1293       *                This undoes the stupidity of magic quotes for GPC.
1294       *
1295       * @return  quoted string to be sent back to database
1296       */
1297  	function qstr($s,$magic_quotes=false)
1298      {    
1299          //$nofixquotes=false;
1300      
1301          if ($this->noNullStrings && strlen($s)==0)$s = ' ';
1302          if (!$magic_quotes) {    
1303              if ($this->replaceQuote[0] == '\\'){
1304                  $s = str_replace('\\','\\\\',$s);
1305              }
1306              return  "'".str_replace("'",$this->replaceQuote,$s)."'";
1307          }
1308          
1309          // undo magic quotes for " unless sybase is on
1310          if (!ini_get('magic_quotes_sybase')) {
1311              $s = str_replace('\\"','"',$s);
1312              $s = str_replace('\\\\','\\',$s);
1313              return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
1314          } else {
1315              return "'".$s."'";
1316          }
1317      }
1318      
1319  }
1320  
1321  /*--------------------------------------------------------------------------------------
1322           Class Name: Recordset
1323  --------------------------------------------------------------------------------------*/
1324  
1325  class ADORecordset_oci8 extends ADORecordSet {
1326  
1327      var $databaseType = 'oci8';
1328      var $bind=false;
1329      var $_fieldobjs;
1330      
1331      //var $_arr = false;
1332          
1333  	function ADORecordset_oci8($queryID,$mode=false)
1334      {
1335          if ($mode === false) { 
1336              global $ADODB_FETCH_MODE;
1337              $mode = $ADODB_FETCH_MODE;
1338          }
1339          switch ($mode)
1340          {
1341          case ADODB_FETCH_ASSOC:$this->fetchMode = OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1342          case ADODB_FETCH_DEFAULT:
1343          case ADODB_FETCH_BOTH:$this->fetchMode = OCI_NUM+OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1344          case ADODB_FETCH_NUM: 
1345          default:
1346          $this->fetchMode = OCI_NUM+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1347          }
1348          
1349          $this->adodbFetchMode = $mode;
1350          $this->_queryID = $queryID;
1351      }
1352  
1353  
1354  	function Init()
1355      {
1356          if ($this->_inited) return;
1357          
1358          $this->_inited = true;
1359          if ($this->_queryID) {
1360              
1361              $this->_currentRow = 0;
1362              @$this->_initrs();
1363              $this->EOF = !$this->_fetch();
1364              
1365              /*
1366              // based on idea by Gaetano Giunta to detect unusual oracle errors
1367              // see http://phplens.com/lens/lensforum/msgs.php?id=6771
1368              $err = OCIError($this->_queryID);
1369              if ($err && $this->connection->debug) ADOConnection::outp($err);
1370              */
1371              
1372              if (!is_array($this->fields)) {
1373                  $this->_numOfRows = 0;
1374                  $this->fields = array();
1375              }
1376          } else {
1377              $this->fields = array();
1378              $this->_numOfRows = 0;
1379              $this->_numOfFields = 0;
1380              $this->EOF = true;
1381          }
1382      }
1383      
1384  	function _initrs()
1385      {
1386          $this->_numOfRows = -1;
1387          $this->_numOfFields = OCInumcols($this->_queryID);
1388          if ($this->_numOfFields>0) {
1389              $this->_fieldobjs = array();
1390              $max = $this->_numOfFields;
1391              for ($i=0;$i<$max; $i++) $this->_fieldobjs[] = $this->_FetchField($i);
1392          }
1393      }
1394  
1395        /*        Returns: an object containing field information.
1396                Get column information in the Recordset object. fetchField() can be used in order to obtain information about
1397                fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
1398                fetchField() is retrieved.        */
1399  
1400  	function _FetchField($fieldOffset = -1)
1401      {
1402          $fld = new ADOFieldObject;
1403          $fieldOffset += 1;
1404          $fld->name =OCIcolumnname($this->_queryID, $fieldOffset);
1405          $fld->type = OCIcolumntype($this->_queryID, $fieldOffset);
1406          $fld->max_length = OCIcolumnsize($this->_queryID, $fieldOffset);
1407           switch($fld->type) {
1408          case 'NUMBER':
1409               $p = OCIColumnPrecision($this->_queryID, $fieldOffset);
1410              $sc = OCIColumnScale($this->_queryID, $fieldOffset);
1411              if ($p != 0 && $sc == 0) $fld->type = 'INT';
1412              $fld->scale = $p;
1413              break;
1414          
1415           case 'CLOB':
1416          case 'NCLOB':
1417          case 'BLOB': 
1418              $fld->max_length = -1;
1419              break;
1420          }
1421          return $fld;
1422      }
1423      
1424      /* For some reason, OCIcolumnname fails when called after _initrs() so we cache it */
1425  	function FetchField($fieldOffset = -1)
1426      {
1427          return $this->_fieldobjs[$fieldOffset];
1428      }
1429      
1430      
1431      /*
1432      // 10% speedup to move MoveNext to child class
1433      function _MoveNext() 
1434      {
1435      //global $ADODB_EXTENSION;if ($ADODB_EXTENSION) return @adodb_movenext($this);
1436          
1437          if ($this->EOF) return false;
1438          
1439          $this->_currentRow++;
1440          if(@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode))
1441              return true;
1442          $this->EOF = true;
1443          
1444          return false;
1445      }    */
1446      
1447      
1448  	function MoveNext()
1449      {
1450          if (@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) {
1451              $this->_currentRow += 1;
1452              return true;
1453          }
1454          if (!$this->EOF) {
1455              $this->_currentRow += 1;
1456              $this->EOF = true;
1457          }
1458          return false;
1459      }
1460      
1461      /*
1462      # does not work as first record is retrieved in _initrs(), so is not included in GetArray()
1463      function GetArray($nRows = -1) 
1464      {
1465      global $ADODB_OCI8_GETARRAY;
1466      
1467          if (true ||  !empty($ADODB_OCI8_GETARRAY)) {
1468              # does not support $ADODB_ANSI_PADDING_OFF
1469      
1470              //OCI_RETURN_NULLS and OCI_RETURN_LOBS is set by OCIfetchstatement
1471              switch($this->adodbFetchMode) {
1472              case ADODB_FETCH_NUM:
1473              
1474                  $ncols = @OCIfetchstatement($this->_queryID, $results, 0, $nRows, OCI_FETCHSTATEMENT_BY_ROW+OCI_NUM);
1475                  $results = array_merge(array($this->fields),$results);
1476                  return $results;
1477                  
1478              case ADODB_FETCH_ASSOC: 
1479                  if (ADODB_ASSOC_CASE != 2 || $this->databaseType != 'oci8') break;
1480                  
1481                  $ncols = @OCIfetchstatement($this->_queryID, $assoc, 0, $nRows, OCI_FETCHSTATEMENT_BY_ROW);
1482                  $results = array_merge(array($this->fields),$assoc);
1483                  return $results;
1484              
1485              default:
1486                  break;
1487              }
1488          }
1489              
1490          $results = ADORecordSet::GetArray($nRows);
1491          return $results;
1492          
1493      } */
1494      
1495      /* Optimize SelectLimit() by using OCIFetch() instead of OCIFetchInto() */
1496  	function GetArrayLimit($nrows,$offset=-1) 
1497      {
1498          if ($offset <= 0) {
1499              $arr = $this->GetArray($nrows);
1500              return $arr;
1501          }
1502          $arr = array();
1503          for ($i=1; $i < $offset; $i++) 
1504              if (!@OCIFetch($this->_queryID)) return $arr;
1505              
1506          if (!@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) return $arr;;
1507          $results = array();
1508          $cnt = 0;
1509          while (!$this->EOF && $nrows != $cnt) {
1510              $results[$cnt++] = $this->fields;
1511              $this->MoveNext();
1512          }
1513          
1514          return $results;
1515      }
1516  
1517      
1518      /* Use associative array to get fields array */
1519  	function Fields($colname)
1520      {
1521          if (!$this->bind) {
1522              $this->bind = array();
1523              for ($i=0; $i < $this->_numOfFields; $i++) {
1524                  $o = $this->FetchField($i);
1525                  $this->bind[strtoupper($o->name)] = $i;
1526              }
1527          }
1528          
1529           return $this->fields[$this->bind[strtoupper($colname)]];
1530      }
1531      
1532  
1533  
1534  	function _seek($row)
1535      {
1536          return false;
1537      }
1538  
1539  	function _fetch() 
1540      {
1541          return @OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode);
1542      }
1543  
1544      /*        close() only needs to be called if you are worried about using too much memory while your script
1545              is running. All associated result memory for the specified result identifier will automatically be freed.        */
1546  
1547  	function _close() 
1548      {
1549          if ($this->connection->_stmt === $this->_queryID) $this->connection->_stmt = false;
1550          if (!empty($this->_refcursor)) {
1551              OCIFreeCursor($this->_refcursor);
1552              $this->_refcursor = false;
1553          }
1554          @OCIFreeStatement($this->_queryID);
1555           $this->_queryID = false;
1556          
1557      }
1558  
1559  	function MetaType($t,$len=-1)
1560      {
1561          if (is_object($t)) {
1562              $fieldobj = $t;
1563              $t = $fieldobj->type;
1564              $len = $fieldobj->max_length;
1565          }
1566          switch (strtoupper($t)) {
1567           case 'VARCHAR':
1568           case 'VARCHAR2':
1569          case 'CHAR':
1570          case 'VARBINARY':
1571          case 'BINARY':
1572          case 'NCHAR':
1573          case 'NVARCHAR':
1574          case 'NVARCHAR2':
1575                   if ($len <= $this->blobSize) return 'C';
1576          
1577          case 'NCLOB':
1578          case 'LONG':
1579          case 'LONG VARCHAR':
1580          case 'CLOB':
1581          return 'X';
1582          
1583          case 'LONG RAW':
1584          case 'LONG VARBINARY':
1585          case 'BLOB':
1586              return 'B';
1587          
1588          case 'DATE': 
1589              return  ($this->connection->datetime) ? 'T' : 'D';
1590          
1591          
1592          case 'TIMESTAMP': return 'T';
1593          
1594          case 'INT': 
1595          case 'SMALLINT':
1596          case 'INTEGER': 
1597              return 'I';
1598              
1599          default: return 'N';
1600          }
1601      }
1602  }
1603  
1604  class ADORecordSet_ext_oci8 extends ADORecordSet_oci8 {    
1605  	function ADORecordSet_ext_oci8($queryID,$mode=false) 
1606      {
1607          if ($mode === false) { 
1608              global $ADODB_FETCH_MODE;
1609              $mode = $ADODB_FETCH_MODE;
1610          }
1611          switch ($mode)
1612          {
1613          case ADODB_FETCH_ASSOC:$this->fetchMode = OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1614          case ADODB_FETCH_DEFAULT:
1615          case ADODB_FETCH_BOTH:$this->fetchMode = OCI_NUM+OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1616          case ADODB_FETCH_NUM: 
1617          default: $this->fetchMode = OCI_NUM+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1618          }
1619          $this->adodbFetchMode = $mode;
1620          $this->_queryID = $queryID;
1621      }
1622      
1623  	function MoveNext()
1624      {
1625          return adodb_movenext($this);
1626      }
1627  }
1628  ?>


Generated: Thu Jul 28 15:48:31 2011 Cross-referenced by PHPXref 0.7