Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]

   1  <?php
   2  /*
   3  @version   v5.20.16  12-Jan-2020
   4  @copyright (c) 2000-2013 John Lim. All rights reserved.
   5  @copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
   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.org/
  11  
  12    Portable version of oci8 driver, to make it more similar to other database drivers.
  13    The main differences are
  14  
  15     1. that the OCI_ASSOC names are in lowercase instead of uppercase.
  16     2. bind variables are mapped using ? instead of :<bindvar>
  17  
  18     Should some emulation of RecordCount() be implemented?
  19  
  20  */
  21  
  22  // security - hide paths
  23  if (!defined('ADODB_DIR')) die();
  24  
  25  include_once(ADODB_DIR.'/drivers/adodb-oci8.inc.php');
  26  
  27  class ADODB_oci8po extends ADODB_oci8 {
  28  	 var $databaseType = 'oci8po';
  29  	 var $dataProvider = 'oci8';
  30  	 var $metaColumnsSQL = "select lower(cname),coltype,width, SCALE, PRECISION, NULLS, DEFAULTVAL from col where tname='%s' order by colno"; //changed by smondino@users.sourceforge. net
  31  	 var $metaTablesSQL = "select lower(table_name),table_type from cat where table_type in ('TABLE','VIEW')";
  32  
  33  	function __construct()
  34  	 {
  35  	 	 $this->_hasOCIFetchStatement = ADODB_PHPVER >= 0x4200;
  36  	 	 # oci8po does not support adodb extension: adodb_movenext()
  37  	 }
  38  
  39  	function Param($name,$type='C')
  40  	 {
  41  	 	 return '?';
  42  	 }
  43  
  44  	function Prepare($sql,$cursor=false)
  45  	 {
  46  	 	 $sqlarr = explode('?',$sql);
  47  	 	 $sql = $sqlarr[0];
  48  	 	 for ($i = 1, $max = sizeof($sqlarr); $i < $max; $i++) {
  49  	 	 	 $sql .=  ':'.($i-1) . $sqlarr[$i];
  50  	 	 }
  51  	 	 return ADODB_oci8::Prepare($sql,$cursor);
  52  	 }
  53  
  54  	function Execute($sql,$inputarr=false)
  55  	 {
  56  	 	 return ADOConnection::Execute($sql,$inputarr);
  57  	 }
  58  
  59  	 /**
  60  	  * The optimizations performed by ADODB_oci8::SelectLimit() are not
  61  	  * compatible with the oci8po driver, so we rely on the slower method
  62  	  * from the base class.
  63  	  * We can't properly handle prepared statements either due to preprocessing
  64  	  * of query parameters, so we treat them as regular SQL statements.
  65  	  */
  66  	function SelectLimit($sql, $nrows=-1, $offset=-1, $inputarr=false, $secs2cache=0)
  67  	 {
  68  	 	 if(is_array($sql)) {
  69  //	 	 	 $sql = $sql[0];
  70  	 	 }
  71  	 	 return ADOConnection::SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
  72  	 }
  73  
  74  	 // emulate handling of parameters ? ?, replacing with :bind0 :bind1
  75  	function _query($sql,$inputarr=false)
  76  	 {
  77  	 	 if (is_array($inputarr)) {
  78  	 	 	 $i = 0;
  79  	 	 	 if (is_array($sql)) {
  80  	 	 	 	 foreach($inputarr as $v) {
  81  	 	 	 	 	 $arr['bind'.$i++] = $v;
  82  	 	 	 	 }
  83  	 	 	 } else {
  84  	 	 	 	 $sql = $this->extractBinds($sql,$inputarr);
  85  	 	 	 }
  86  	 	 }
  87  	 	 return ADODB_oci8::_query($sql,$inputarr);
  88  	 }
  89  	 /**
  90  	 * Replaces compatibility bind markers with oracle ones and returns a
  91  	 * valid sql statement
  92  	 *
  93  	 * This replaces a regexp based section of code that has been subject
  94  	 * to numerous tweaks, as more extreme test cases have appeared. This
  95  	 * is now done this like this to help maintainability and avoid the 
  96  	 * need to rely on regexp experienced maintainers
  97          *
  98  	 * @param	 string	 	 $sql	 	 The sql statement
  99  	 * @param	 string[]	 $inputarr	 The bind array
 100  	 *
 101  	 * @return	 string	 The modified statement
 102  	 */	 
 103  	final private function extractBinds($sql,$inputarr)
 104  	 {
 105  	 	 $inString  = false;
 106  	 	 $escaped   = 0;
 107  	 	 $sqlLength = strlen($sql) - 1;
 108  	 	 $newSql    = '';
 109  	 	 $bindCount = 0;
 110  	 	 
 111  	 	 /*
 112  	 	 * inputarr is the passed in bind list, which is associative, but
 113  	 	 * we only want the keys here
 114  	 	 */
 115  	 	 $inputKeys = array_keys($inputarr);
 116  	 	 
 117  	 	 
 118  	 	 for ($i=0;$i<=$sqlLength;$i++)
 119  	 	 {
 120  	 	 	 /*
 121  	 	 	 * find the next character of the string
 122  	 	 	 */
 123              $c = $sql[$i];
 124  
 125  	 	 	 if ($c == "'" && !$inString && $escaped==0)
 126  	 	 	 	 /*
 127  	 	 	 	 * Found the start of a string inside the statement
 128  	 	 	 	 */
 129  	 	 	 	 $inString = true;
 130  	 	 	 elseif ($c == "\\" && $escaped==0)
 131  	 	 	 	 /*
 132  	 	 	 	 * The next character will be escaped
 133  	 	 	 	 */
 134  	 	 	 	 $escaped = 1;
 135  	 	 	 elseif ($c == "'" && $inString && $escaped==0)
 136  	 	 	 	 /*
 137  	 	 	 	 * We found the end of the string
 138  	 	 	 	 */
 139  	 	 	 	 $inString = false;
 140  	 	 	 
 141  	 	 	 if ($escaped == 2)
 142  	 	 	 	 $escaped = 0;
 143  
 144  	 	 	 if ($escaped==0 && !$inString && $c == '?')
 145  	 	 	 	 /*
 146  	 	 	 	 * We found a bind symbol, replace it with the oracle equivalent
 147  	 	 	 	 */
 148  	 	 	 	 $newSql .= ':' . $inputKeys[$bindCount++];
 149  	 	 	 else
 150  	 	 	 	 /*
 151  	 	 	 	 * Add the current character the pile
 152  	 	 	 	 */
 153  	 	 	 	 $newSql .= $c;
 154  	 	 	 
 155  	 	 	 if ($escaped == 1)
 156  	 	 	 	 /*
 157  	 	 	 	 * We have just found an escape character, make sure we ignore the
 158  	 	 	 	 * next one that comes along, it might be a ' character
 159  	 	 	 	 */
 160  	 	 	 	 $escaped = 2;
 161  	 	 }
 162  	 	 
 163  	 	 return $newSql;
 164  	 	 	 
 165  	 }
 166  }
 167  
 168  /*--------------------------------------------------------------------------------------
 169  	 	  Class Name: Recordset
 170  --------------------------------------------------------------------------------------*/
 171  
 172  class ADORecordset_oci8po extends ADORecordset_oci8 {
 173  
 174  	 var $databaseType = 'oci8po';
 175  
 176  	function __construct($queryID,$mode=false)
 177  	 {
 178  	 	 parent::__construct($queryID,$mode);
 179  	 }
 180  
 181  	function Fields($colname)
 182  	 {
 183  	 	 if ($this->fetchMode & OCI_ASSOC) return $this->fields[$colname];
 184  
 185  	 	 if (!$this->bind) {
 186  	 	 	 $this->bind = array();
 187  	 	 	 for ($i=0; $i < $this->_numOfFields; $i++) {
 188  	 	 	 	 $o = $this->FetchField($i);
 189  	 	 	 	 $this->bind[strtoupper($o->name)] = $i;
 190  	 	 	 }
 191  	 	 }
 192  	 	  return $this->fields[$this->bind[strtoupper($colname)]];
 193  	 }
 194  
 195  	 // lowercase field names...
 196  	function _FetchField($fieldOffset = -1)
 197  	 {
 198  	 	 $fld = new ADOFieldObject;
 199  	 	 $fieldOffset += 1;
 200  	 	 $fld->name = OCIcolumnname($this->_queryID, $fieldOffset);
 201  	 	 if (ADODB_ASSOC_CASE == ADODB_ASSOC_CASE_LOWER) {
 202  	 	 	 $fld->name = strtolower($fld->name);
 203  	 	 }
 204  	 	 $fld->type = OCIcolumntype($this->_queryID, $fieldOffset);
 205  	 	 $fld->max_length = OCIcolumnsize($this->_queryID, $fieldOffset);
 206  	 	 if ($fld->type == 'NUMBER') {
 207  	 	 	 $sc = OCIColumnScale($this->_queryID, $fieldOffset);
 208  	 	 	 if ($sc == 0) {
 209  	 	 	 	 $fld->type = 'INT';
 210  	 	 	 }
 211  	 	 }
 212  	 	 return $fld;
 213  	 }
 214  
 215  	 // 10% speedup to move MoveNext to child class
 216  	function MoveNext()
 217  	 {
 218  	 	 $ret = @oci_fetch_array($this->_queryID,$this->fetchMode);
 219  	 	 if($ret !== false) {
 220  	 	 global $ADODB_ANSI_PADDING_OFF;
 221  	 	 	 $this->fields = $ret;
 222  	 	 	 $this->_currentRow++;
 223  	 	 	 $this->_updatefields();
 224  
 225  	 	 	 if (!empty($ADODB_ANSI_PADDING_OFF)) {
 226  	 	 	 	 foreach($this->fields as $k => $v) {
 227  	 	 	 	 	 if (is_string($v)) $this->fields[$k] = rtrim($v);
 228  	 	 	 	 }
 229  	 	 	 }
 230  	 	 	 return true;
 231  	 	 }
 232  	 	 if (!$this->EOF) {
 233  	 	 	 $this->EOF = true;
 234  	 	 	 $this->_currentRow++;
 235  	 	 }
 236  	 	 return false;
 237  	 }
 238  
 239  	 /* Optimize SelectLimit() by using OCIFetch() instead of OCIFetchInto() */
 240  	function GetArrayLimit($nrows,$offset=-1)
 241  	 {
 242  	 	 if ($offset <= 0) {
 243  	 	 	 $arr = $this->GetArray($nrows);
 244  	 	 	 return $arr;
 245  	 	 }
 246  	 	 for ($i=1; $i < $offset; $i++)
 247  	 	 	 if (!@OCIFetch($this->_queryID)) {
 248  	 	 	 	 $arr = array();
 249  	 	 	 	 return $arr;
 250  	 	 	 }
 251  	 	 $ret = @oci_fetch_array($this->_queryID,$this->fetchMode);
 252  	 	 if ($ret === false) {
 253  	 	 	 $arr = array();
 254  	 	 	 return $arr;
 255  	 	 }
 256  	 	 $this->fields = $ret;
 257  	 	 $this->_updatefields();
 258  	 	 $results = array();
 259  	 	 $cnt = 0;
 260  	 	 while (!$this->EOF && $nrows != $cnt) {
 261  	 	 	 $results[$cnt++] = $this->fields;
 262  	 	 	 $this->MoveNext();
 263  	 	 }
 264  
 265  	 	 return $results;
 266  	 }
 267  
 268  	function _fetch()
 269  	 {
 270  	 	 global $ADODB_ANSI_PADDING_OFF;
 271  
 272  	 	 $ret = @oci_fetch_array($this->_queryID,$this->fetchMode);
 273  	 	 if ($ret) {
 274  	 	 	 $this->fields = $ret;
 275  	 	 	 $this->_updatefields();
 276  
 277  	 	 	 if (!empty($ADODB_ANSI_PADDING_OFF)) {
 278  	 	 	 	 foreach($this->fields as $k => $v) {
 279  	 	 	 	 	 if (is_string($v)) $this->fields[$k] = rtrim($v);
 280  	 	 	 	 }
 281  	 	 	 }
 282  	 	 }
 283  	 	 return $ret !== false;
 284  	 }
 285  
 286  }