[ Index ]
 

Code source de eGroupWare 1.2.106-2

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

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

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


Généré le : Sun Feb 25 17:20:01 2007 par Balluche grâce à PHPXref 0.7