Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

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

   1  <?php
   2  /**
   3   * Portable version of Oracle oci8 driver
   4   *
   5   * This file is part of ADOdb, a Database Abstraction Layer library for PHP.
   6   *
   7   * Portable version of oci8 driver, to make it more similar to other database
   8   * drivers. The main differences are
   9   * 1. that the OCI_ASSOC names are in lowercase instead of uppercase.
  10   * 2. bind variables are mapped using ? instead of :<bindvar>
  11   *
  12   * @package ADOdb
  13   * @link https://adodb.org Project's web site and documentation
  14   * @link https://github.com/ADOdb/ADOdb Source code and issue tracker
  15   *
  16   * The ADOdb Library is dual-licensed, released under both the BSD 3-Clause
  17   * and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option,
  18   * any later version. This means you can use it in proprietary products.
  19   * See the LICENSE.md file distributed with this source code for details.
  20   * @license BSD-3-Clause
  21   * @license LGPL-2.1-or-later
  22   *
  23   * @copyright 2000-2013 John Lim
  24   * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
  25   */
  26  
  27  // security - hide paths
  28  if (!defined('ADODB_DIR')) die();
  29  
  30  include_once(ADODB_DIR.'/drivers/adodb-oci8.inc.php');
  31  
  32  class ADODB_oci8po extends ADODB_oci8 {
  33  	 var $databaseType = 'oci8po';
  34  	 var $dataProvider = 'oci8';
  35  	 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
  36  	 var $metaTablesSQL = "select lower(table_name),table_type from cat where table_type in ('TABLE','VIEW')";
  37  
  38  	function Param($name,$type='C')
  39  	 {
  40  	 	 return '?';
  41  	 }
  42  
  43  	function Prepare($sql,$cursor=false)
  44  	 {
  45  	 	 $sqlarr = explode('?',$sql);
  46  	 	 $sql = $sqlarr[0];
  47  	 	 for ($i = 1, $max = sizeof($sqlarr); $i < $max; $i++) {
  48  	 	 	 $sql .=  ':'.($i-1) . $sqlarr[$i];
  49  	 	 }
  50  	 	 return ADODB_oci8::Prepare($sql,$cursor);
  51  	 }
  52  
  53  	function Execute($sql,$inputarr=false)
  54  	 {
  55  	 	 return ADOConnection::Execute($sql,$inputarr);
  56  	 }
  57  
  58  	 /**
  59  	  * The optimizations performed by ADODB_oci8::SelectLimit() are not
  60  	  * compatible with the oci8po driver, so we rely on the slower method
  61  	  * from the base class.
  62  	  * We can't properly handle prepared statements either due to preprocessing
  63  	  * of query parameters, so we treat them as regular SQL statements.
  64  	  */
  65  	function SelectLimit($sql, $nrows=-1, $offset=-1, $inputarr=false, $secs2cache=0)
  66  	 {
  67  	 	 if(is_array($sql)) {
  68  //	 	 	 $sql = $sql[0];
  69  	 	 }
  70  	 	 return ADOConnection::SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
  71  	 }
  72  
  73  	 // emulate handling of parameters ? ?, replacing with :bind0 :bind1
  74  	function _query($sql,$inputarr=false)
  75  	 {
  76  	 	 if (is_array($inputarr)) {
  77  	 	 	 $i = 0;
  78  	 	 	 if (is_array($sql)) {
  79  	 	 	 	 foreach($inputarr as $v) {
  80  	 	 	 	 	 $arr['bind'.$i++] = $v;
  81  	 	 	 	 }
  82  	 	 	 } else {
  83  	 	 	 	 $sql = $this->extractBinds($sql,$inputarr);
  84  	 	 	 }
  85  	 	 }
  86  	 	 return ADODB_oci8::_query($sql,$inputarr);
  87  	 }
  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  	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  	 	 for ($i=0;$i<=$sqlLength;$i++)
 118  	 	 {
 119  	 	 	 /*
 120  	 	 	 * find the next character of the string
 121  	 	 	 */
 122  	 	 	 $c = $sql[$i];
 123  
 124  	 	 	 if ($c == "'" && !$inString && $escaped==0)
 125  	 	 	 	 /*
 126  	 	 	 	 * Found the start of a string inside the statement
 127  	 	 	 	 */
 128  	 	 	 	 $inString = true;
 129  	 	 	 elseif ($c == "\\" && $escaped==0)
 130  	 	 	 	 /*
 131  	 	 	 	 * The next character will be escaped
 132  	 	 	 	 */
 133  	 	 	 	 $escaped = 1;
 134  	 	 	 elseif ($c == "'" && $inString && $escaped==0)
 135  	 	 	 	 /*
 136  	 	 	 	 * We found the end of the string
 137  	 	 	 	 */
 138  	 	 	 	 $inString = false;
 139  
 140  	 	 	 if ($escaped == 2)
 141  	 	 	 	 $escaped = 0;
 142  
 143  	 	 	 if ($escaped==0 && !$inString && $c == '?')
 144  	 	 	 	 /*
 145  	 	 	 	 * We found a bind symbol, replace it with the oracle equivalent
 146  	 	 	 	 */
 147  	 	 	 	 $newSql .= ':' . $inputKeys[$bindCount++];
 148  	 	 	 else
 149  	 	 	 	 /*
 150  	 	 	 	 * Add the current character the pile
 151  	 	 	 	 */
 152  	 	 	 	 $newSql .= $c;
 153  
 154  	 	 	 if ($escaped == 1)
 155  	 	 	 	 /*
 156  	 	 	 	 * We have just found an escape character, make sure we ignore the
 157  	 	 	 	 * next one that comes along, it might be a ' character
 158  	 	 	 	 */
 159  	 	 	 	 $escaped = 2;
 160  	 	 }
 161  
 162  	 	 return $newSql;
 163  
 164  	 }
 165  }
 166  
 167  /*--------------------------------------------------------------------------------------
 168  	 	  Class Name: Recordset
 169  --------------------------------------------------------------------------------------*/
 170  
 171  class ADORecordset_oci8po extends ADORecordset_oci8 {
 172  
 173  	 var $databaseType = 'oci8po';
 174  
 175  	function Fields($colname)
 176  	 {
 177  	 	 if ($this->fetchMode & OCI_ASSOC) return $this->fields[$colname];
 178  
 179  	 	 if (!$this->bind) {
 180  	 	 	 $this->bind = array();
 181  	 	 	 for ($i=0; $i < $this->_numOfFields; $i++) {
 182  	 	 	 	 $o = $this->FetchField($i);
 183  	 	 	 	 $this->bind[strtoupper($o->name)] = $i;
 184  	 	 	 }
 185  	 	 }
 186  	 	  return $this->fields[$this->bind[strtoupper($colname)]];
 187  	 }
 188  
 189  	 // lowercase field names...
 190  	function _FetchField($fieldOffset = -1)
 191  	 {
 192  	 	 $fld = new ADOFieldObject;
 193  	 	 $fieldOffset += 1;
 194  	 	 $fld->name = oci_field_name($this->_queryID, $fieldOffset);
 195  	 	 if (ADODB_ASSOC_CASE == ADODB_ASSOC_CASE_LOWER) {
 196  	 	 	 $fld->name = strtolower($fld->name);
 197  	 	 }
 198  	 	 $fld->type = oci_field_type($this->_queryID, $fieldOffset);
 199  	 	 $fld->max_length = oci_field_size($this->_queryID, $fieldOffset);
 200  	 	 if ($fld->type == 'NUMBER') {
 201  	 	 	 $sc = oci_field_scale($this->_queryID, $fieldOffset);
 202  	 	 	 if ($sc == 0) {
 203  	 	 	 	 $fld->type = 'INT';
 204  	 	 	 }
 205  	 	 }
 206  	 	 return $fld;
 207  	 }
 208  
 209  	 // 10% speedup to move MoveNext to child class
 210  	function MoveNext()
 211  	 {
 212  	 	 $ret = @oci_fetch_array($this->_queryID,$this->fetchMode);
 213  	 	 if($ret !== false) {
 214  	 	 global $ADODB_ANSI_PADDING_OFF;
 215  	 	 	 $this->fields = $ret;
 216  	 	 	 $this->_currentRow++;
 217  	 	 	 $this->_updatefields();
 218  
 219  	 	 	 if (!empty($ADODB_ANSI_PADDING_OFF)) {
 220  	 	 	 	 foreach($this->fields as $k => $v) {
 221  	 	 	 	 	 if (is_string($v)) $this->fields[$k] = rtrim($v);
 222  	 	 	 	 }
 223  	 	 	 }
 224  	 	 	 return true;
 225  	 	 }
 226  	 	 if (!$this->EOF) {
 227  	 	 	 $this->EOF = true;
 228  	 	 	 $this->_currentRow++;
 229  	 	 }
 230  	 	 return false;
 231  	 }
 232  
 233  	function GetArrayLimit($nrows,$offset=-1)
 234  	 {
 235  	 	 if ($offset <= 0) {
 236  	 	 	 $arr = $this->GetArray($nrows);
 237  	 	 	 return $arr;
 238  	 	 }
 239  	 	 for ($i=1; $i < $offset; $i++)
 240  	 	 	 if (!@oci_fetch($this->_queryID)) {
 241  	 	 	 	 $arr = array();
 242  	 	 	 	 return $arr;
 243  	 	 	 }
 244  	 	 $ret = @oci_fetch_array($this->_queryID,$this->fetchMode);
 245  	 	 if ($ret === false) {
 246  	 	 	 $arr = array();
 247  	 	 	 return $arr;
 248  	 	 }
 249  	 	 $this->fields = $ret;
 250  	 	 $this->_updatefields();
 251  	 	 $results = array();
 252  	 	 $cnt = 0;
 253  	 	 while (!$this->EOF && $nrows != $cnt) {
 254  	 	 	 $results[$cnt++] = $this->fields;
 255  	 	 	 $this->MoveNext();
 256  	 	 }
 257  
 258  	 	 return $results;
 259  	 }
 260  
 261  	function _fetch()
 262  	 {
 263  	 	 global $ADODB_ANSI_PADDING_OFF;
 264  
 265  	 	 $ret = @oci_fetch_array($this->_queryID,$this->fetchMode);
 266  	 	 if ($ret) {
 267  	 	 	 $this->fields = $ret;
 268  	 	 	 $this->_updatefields();
 269  
 270  	 	 	 if (!empty($ADODB_ANSI_PADDING_OFF)) {
 271  	 	 	 	 foreach($this->fields as $k => $v) {
 272  	 	 	 	 	 if (is_string($v)) $this->fields[$k] = rtrim($v);
 273  	 	 	 	 }
 274  	 	 	 }
 275  	 	 }
 276  	 	 return $ret !== false;
 277  	 }
 278  
 279  }