Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

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

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