Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

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

   1  <?php
   2  /**
   3   * PDO Firebird driver
   4   *
   5   * This version has only been tested on Firebird 3.0 and PHP 7
   6   *
   7   * This file is part of ADOdb, a Database Abstraction Layer library for PHP.
   8   *
   9   * @package ADOdb
  10   * @link https://adodb.org Project's web site and documentation
  11   * @link https://github.com/ADOdb/ADOdb Source code and issue tracker
  12   *
  13   * The ADOdb Library is dual-licensed, released under both the BSD 3-Clause
  14   * and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option,
  15   * any later version. This means you can use it in proprietary products.
  16   * See the LICENSE.md file distributed with this source code for details.
  17   * @license BSD-3-Clause
  18   * @license LGPL-2.1-or-later
  19   *
  20   * @copyright 2000-2013 John Lim
  21   * @copyright 2019 Damien Regad, Mark Newnham and the ADOdb community
  22   */
  23  
  24  /**
  25   * Class ADODB_pdo_firebird
  26   */
  27  class ADODB_pdo_firebird extends ADODB_pdo
  28  {
  29  	 public $dialect = 3;
  30  	 public $metaTablesSQL = "select lower(rdb\$relation_name) from rdb\$relations where rdb\$relation_name not like 'RDB\$%'";
  31  	 public $metaColumnsSQL = "select lower(a.rdb\$field_name), a.rdb\$null_flag, a.rdb\$default_source, b.rdb\$field_length, b.rdb\$field_scale, b.rdb\$field_sub_type, b.rdb\$field_precision, b.rdb\$field_type from rdb\$relation_fields a, rdb\$fields b where a.rdb\$field_source = b.rdb\$field_name and a.rdb\$relation_name = '%s' order by a.rdb\$field_position asc";
  32  
  33  	 var $arrayClass = 'ADORecordSet_array_pdo_firebird';
  34  
  35  	function _init($parentDriver)
  36  	 {
  37  	 	 $this->pdoDriver = $parentDriver;
  38  	 	 //$parentDriver->_bindInputArray = true;
  39  	 	 //$parentDriver->hasTransactions = false; // // should be set to false because of PDO SQLite driver not supporting changing autocommit mode
  40  	 	 //$parentDriver->hasInsertID = true;
  41  	 }
  42  
  43  	 /**
  44  	  * Gets the version iformation from the server
  45  	  *
  46  	  * @return string[]
  47  	  */
  48  	public function serverInfo()
  49  	 {
  50  	 	 $arr['dialect'] = $this->dialect;
  51  	 	 switch ($arr['dialect']) {
  52  	 	 	 case '':
  53  	 	 	 case '1':
  54  	 	 	 	 $s = 'Firebird Dialect 1';
  55  	 	 	 	 break;
  56  	 	 	 case '2':
  57  	 	 	 	 $s = 'Firebird Dialect 2';
  58  	 	 	 	 break;
  59  	 	 	 default:
  60  	 	 	 case '3':
  61  	 	 	 	 $s = 'Firebird Dialect 3';
  62  	 	 	 	 break;
  63  	 	 }
  64  	 	 $arr['version'] = ADOConnection::_findvers($s);
  65  	 	 $arr['description'] = $s;
  66  	 	 return $arr;
  67  	 }
  68  
  69  	 /**
  70  	  * Returns the tables in the database.
  71  	  *
  72  	  * @param mixed $ttype
  73  	  * @param bool  $showSchema
  74  	  * @param mixed $mask
  75  	  *
  76  	  * @return    string[]
  77  	  */
  78  	public function metaTables($ttype = false, $showSchema = false, $mask = false)
  79  	 {
  80  	 	 $ret = ADOConnection::MetaTables($ttype, $showSchema);
  81  
  82  	 	 return $ret;
  83  	 }
  84  
  85  	public function metaColumns($table, $normalize = true)
  86  	 {
  87  	 	 global $ADODB_FETCH_MODE;
  88  
  89  	 	 $save = $ADODB_FETCH_MODE;
  90  	 	 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
  91  
  92  	 	 $rs = $this->Execute(sprintf($this->metaColumnsSQL, strtoupper($table)));
  93  
  94  	 	 $ADODB_FETCH_MODE = $save;
  95  
  96  	 	 if ($rs === false) {
  97  	 	 	 return false;
  98  	 	 }
  99  
 100  	 	 $retarr = array();
 101  	 	 $dialect3 = $this->dialect == 3;
 102  	 	 while (!$rs->EOF) { //print_r($rs->fields);
 103  	 	 	 $fld = new ADOFieldObject();
 104  	 	 	 $fld->name = trim($rs->fields[0]);
 105  	 	 	 $this->_ConvertFieldType($fld, $rs->fields[7], $rs->fields[3], $rs->fields[4], $rs->fields[5],
 106  	 	 	 	 $rs->fields[6], $dialect3);
 107  	 	 	 if (isset($rs->fields[1]) && $rs->fields[1]) {
 108  	 	 	 	 $fld->not_null = true;
 109  	 	 	 }
 110  	 	 	 if (isset($rs->fields[2])) {
 111  
 112  	 	 	 	 $fld->has_default = true;
 113  	 	 	 	 $d = substr($rs->fields[2], strlen('default '));
 114  	 	 	 	 switch ($fld->type) {
 115  	 	 	 	 	 case 'smallint':
 116  	 	 	 	 	 case 'integer':
 117  	 	 	 	 	 	 $fld->default_value = (int)$d;
 118  	 	 	 	 	 	 break;
 119  	 	 	 	 	 case 'char':
 120  	 	 	 	 	 case 'blob':
 121  	 	 	 	 	 case 'text':
 122  	 	 	 	 	 case 'varchar':
 123  	 	 	 	 	 	 $fld->default_value = (string)substr($d, 1, strlen($d) - 2);
 124  	 	 	 	 	 	 break;
 125  	 	 	 	 	 case 'double':
 126  	 	 	 	 	 case 'float':
 127  	 	 	 	 	 	 $fld->default_value = (float)$d;
 128  	 	 	 	 	 	 break;
 129  	 	 	 	 	 default:
 130  	 	 	 	 	 	 $fld->default_value = $d;
 131  	 	 	 	 	 	 break;
 132  	 	 	 	 }
 133  	 	 	 }
 134  	 	 	 if ((isset($rs->fields[5])) && ($fld->type == 'blob')) {
 135  	 	 	 	 $fld->sub_type = $rs->fields[5];
 136  	 	 	 } else {
 137  	 	 	 	 $fld->sub_type = null;
 138  	 	 	 }
 139  	 	 	 if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) {
 140  	 	 	 	 $retarr[] = $fld;
 141  	 	 	 } else {
 142  	 	 	 	 $retarr[strtoupper($fld->name)] = $fld;
 143  	 	 	 }
 144  
 145  	 	 	 $rs->MoveNext();
 146  	 	 }
 147  	 	 $rs->Close();
 148  	 	 if (empty($retarr)) {
 149  	 	 	 return false;
 150  	 	 } else {
 151  	 	 	 return $retarr;
 152  	 	 }
 153  	 }
 154  
 155  	public function metaIndexes($table, $primary = false, $owner = false)
 156  	 {
 157  	 	 // save old fetch mode
 158  	 	 global $ADODB_FETCH_MODE;
 159  	 	 $save = $ADODB_FETCH_MODE;
 160  	 	 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
 161  	 	 if ($this->fetchMode !== false) {
 162  	 	 	 $savem = $this->SetFetchMode(false);
 163  	 	 }
 164  	 	 $table = strtoupper($table);
 165  	 	 $sql = "SELECT * FROM RDB\$INDICES WHERE RDB\$RELATION_NAME = '" . $table . "'";
 166  	 	 if (!$primary) {
 167  	 	 	 $sql .= " AND RDB\$INDEX_NAME NOT LIKE 'RDB\$%'";
 168  	 	 } else {
 169  	 	 	 $sql .= " AND RDB\$INDEX_NAME NOT LIKE 'RDB\$FOREIGN%'";
 170  	 	 }
 171  
 172  	 	 // get index details
 173  	 	 $rs = $this->Execute($sql);
 174  	 	 if (!is_object($rs)) {
 175  	 	 	 // restore fetchmode
 176  	 	 	 if (isset($savem)) {
 177  	 	 	 	 $this->SetFetchMode($savem);
 178  	 	 	 }
 179  	 	 	 $ADODB_FETCH_MODE = $save;
 180  	 	 	 return false;
 181  	 	 }
 182  
 183  	 	 $indexes = array();
 184  	 	 while ($row = $rs->FetchRow()) {
 185  	 	 	 $index = $row[0];
 186  	 	 	 if (!isset($indexes[$index])) {
 187  	 	 	 	 if (is_null($row[3])) {
 188  	 	 	 	 	 $row[3] = 0;
 189  	 	 	 	 }
 190  	 	 	 	 $indexes[$index] = array(
 191  	 	 	 	 	 'unique' => ($row[3] == 1),
 192  	 	 	 	 	 'columns' => array()
 193  	 	 	 	 );
 194  	 	 	 }
 195  	 	 	 $sql = "SELECT * FROM RDB\$INDEX_SEGMENTS WHERE RDB\$INDEX_NAME = '" . $index . "' ORDER BY RDB\$FIELD_POSITION ASC";
 196  	 	 	 $rs1 = $this->Execute($sql);
 197  	 	 	 while ($row1 = $rs1->FetchRow()) {
 198  	 	 	 	 $indexes[$index]['columns'][$row1[2]] = $row1[1];
 199  	 	 	 }
 200  	 	 }
 201  	 	 // restore fetchmode
 202  	 	 if (isset($savem)) {
 203  	 	 	 $this->SetFetchMode($savem);
 204  	 	 }
 205  	 	 $ADODB_FETCH_MODE = $save;
 206  
 207  	 	 return $indexes;
 208  	 }
 209  
 210  	public function metaPrimaryKeys($table, $owner_notused = false, $internalKey = false)
 211  	 {
 212  	 	 if ($internalKey) {
 213  	 	 	 return array('RDB$DB_KEY');
 214  	 	 }
 215  
 216  	 	 $table = strtoupper($table);
 217  
 218  	 	 $sql = 'SELECT S.RDB$FIELD_NAME AFIELDNAME
 219  	 FROM RDB$INDICES I JOIN RDB$INDEX_SEGMENTS S ON I.RDB$INDEX_NAME=S.RDB$INDEX_NAME
 220  	 WHERE I.RDB$RELATION_NAME=\'' . $table . '\' and I.RDB$INDEX_NAME like \'RDB$PRIMARY%\'
 221  	 ORDER BY I.RDB$INDEX_NAME,S.RDB$FIELD_POSITION';
 222  
 223  	 	 $a = $this->GetCol($sql, false, true);
 224  	 	 if ($a && sizeof($a) > 0) {
 225  	 	 	 return $a;
 226  	 	 }
 227  	 	 return false;
 228  	 }
 229  
 230  	public function createSequence($seqname = 'adodbseq', $startID = 1)
 231  	 {
 232  	 	 $ok = $this->execute("CREATE SEQUENCE $seqname");
 233  	 	 if (!$ok) {
 234  	 	 	 return false;
 235  	 	 }
 236  
 237  	 	 return $this->execute("ALTER SEQUENCE $seqname RESTART WITH " . ($startID - 1));
 238  	 }
 239  
 240  	public function dropSequence($seqname = 'adodbseq')
 241  	 {
 242  	 	 $seqname = strtoupper($seqname);
 243  	 	 return $this->Execute("DROP SEQUENCE $seqname");
 244  	 }
 245  
 246  
 247  	public function _affectedrows()
 248  	 {
 249  	 	 return fbird_affected_rows($this->_transactionID ? $this->_transactionID : $this->_connectionID);
 250  	 }
 251  
 252  	public function genId($seqname = 'adodbseq', $startID = 1)
 253  	 {
 254  	 	 $getnext = ("SELECT Gen_ID($seqname,1) FROM RDB\$DATABASE");
 255  	 	 $rs = @$this->execute($getnext);
 256  	 	 if (!$rs) {
 257  	 	 	 $this->execute(("CREATE SEQUENCE $seqname"));
 258  	 	 	 $this->execute("ALTER SEQUENCE $seqname RESTART WITH " . ($startID - 1) . ';');
 259  	 	 	 $rs = $this->execute($getnext);
 260  	 	 }
 261  	 	 if ($rs && !$rs->EOF) {
 262  	 	 	 $this->genID = (integer)reset($rs->fields);
 263  	 	 } else {
 264  	 	 	 $this->genID = 0; // false
 265  	 	 }
 266  
 267  	 	 if ($rs) {
 268  	 	 	 $rs->Close();
 269  	 	 }
 270  
 271  	 	 return $this->genID;
 272  	 }
 273  
 274  	public function selectLimit($sql, $nrows = -1, $offset = -1, $inputarr = false, $secs = 0)
 275  	 {
 276  	 	 $nrows = (integer)$nrows;
 277  	 	 $offset = (integer)$offset;
 278  	 	 $str = 'SELECT ';
 279  	 	 if ($nrows >= 0) {
 280  	 	 	 $str .= "FIRST $nrows ";
 281  	 	 }
 282  	 	 $str .= ($offset >= 0) ? "SKIP $offset " : '';
 283  
 284  	 	 $sql = preg_replace('/^[ \t]*select/i', $str, $sql);
 285  	 	 if ($secs) {
 286  	 	 	 $rs = $this->cacheExecute($secs, $sql, $inputarr);
 287  	 	 } else {
 288  	 	 	 $rs = $this->execute($sql, $inputarr);
 289  	 	 }
 290  
 291  	 	 return $rs;
 292  	 }
 293  
 294  	 /**
 295  	  * Sets the appropriate type into the $fld variable
 296  	  *
 297  	  * @param ADOFieldObject $fld By reference
 298  	  * @param int            $ftype
 299  	  * @param int            $flen
 300  	  * @param int            $fscale
 301  	  * @param int            $fsubtype
 302  	  * @param int            $fprecision
 303  	  * @param bool           $dialect3
 304  	  */
 305  	private function _convertFieldType(&$fld, $ftype, $flen, $fscale, $fsubtype, $fprecision, $dialect3)
 306  	 {
 307  	 	 $fscale = abs($fscale);
 308  	 	 $fld->max_length = $flen;
 309  	 	 $fld->scale = null;
 310  	 	 switch ($ftype) {
 311  	 	 	 case 7:
 312  	 	 	 case 8:
 313  	 	 	 	 if ($dialect3) {
 314  	 	 	 	 	 switch ($fsubtype) {
 315  	 	 	 	 	 	 case 0:
 316  	 	 	 	 	 	 	 $fld->type = ($ftype == 7 ? 'smallint' : 'integer');
 317  	 	 	 	 	 	 	 break;
 318  	 	 	 	 	 	 case 1:
 319  	 	 	 	 	 	 	 $fld->type = 'numeric';
 320  	 	 	 	 	 	 	 $fld->max_length = $fprecision;
 321  	 	 	 	 	 	 	 $fld->scale = $fscale;
 322  	 	 	 	 	 	 	 break;
 323  	 	 	 	 	 	 case 2:
 324  	 	 	 	 	 	 	 $fld->type = 'decimal';
 325  	 	 	 	 	 	 	 $fld->max_length = $fprecision;
 326  	 	 	 	 	 	 	 $fld->scale = $fscale;
 327  	 	 	 	 	 	 	 break;
 328  	 	 	 	 	 } // switch
 329  	 	 	 	 } else {
 330  	 	 	 	 	 if ($fscale != 0) {
 331  	 	 	 	 	 	 $fld->type = 'decimal';
 332  	 	 	 	 	 	 $fld->scale = $fscale;
 333  	 	 	 	 	 	 $fld->max_length = ($ftype == 7 ? 4 : 9);
 334  	 	 	 	 	 } else {
 335  	 	 	 	 	 	 $fld->type = ($ftype == 7 ? 'smallint' : 'integer');
 336  	 	 	 	 	 }
 337  	 	 	 	 }
 338  	 	 	 	 break;
 339  	 	 	 case 16:
 340  	 	 	 	 if ($dialect3) {
 341  	 	 	 	 	 switch ($fsubtype) {
 342  	 	 	 	 	 	 case 0:
 343  	 	 	 	 	 	 	 $fld->type = 'decimal';
 344  	 	 	 	 	 	 	 $fld->max_length = 18;
 345  	 	 	 	 	 	 	 $fld->scale = 0;
 346  	 	 	 	 	 	 	 break;
 347  	 	 	 	 	 	 case 1:
 348  	 	 	 	 	 	 	 $fld->type = 'numeric';
 349  	 	 	 	 	 	 	 $fld->max_length = $fprecision;
 350  	 	 	 	 	 	 	 $fld->scale = $fscale;
 351  	 	 	 	 	 	 	 break;
 352  	 	 	 	 	 	 case 2:
 353  	 	 	 	 	 	 	 $fld->type = 'decimal';
 354  	 	 	 	 	 	 	 $fld->max_length = $fprecision;
 355  	 	 	 	 	 	 	 $fld->scale = $fscale;
 356  	 	 	 	 	 	 	 break;
 357  	 	 	 	 	 } // switch
 358  	 	 	 	 }
 359  	 	 	 	 break;
 360  	 	 	 case 10:
 361  	 	 	 	 $fld->type = 'float';
 362  	 	 	 	 break;
 363  	 	 	 case 14:
 364  	 	 	 	 $fld->type = 'char';
 365  	 	 	 	 break;
 366  	 	 	 case 27:
 367  	 	 	 	 if ($fscale != 0) {
 368  	 	 	 	 	 $fld->type = 'decimal';
 369  	 	 	 	 	 $fld->max_length = 15;
 370  	 	 	 	 	 $fld->scale = 5;
 371  	 	 	 	 } else {
 372  	 	 	 	 	 $fld->type = 'double';
 373  	 	 	 	 }
 374  	 	 	 	 break;
 375  	 	 	 case 35:
 376  	 	 	 	 if ($dialect3) {
 377  	 	 	 	 	 $fld->type = 'timestamp';
 378  	 	 	 	 } else {
 379  	 	 	 	 	 $fld->type = 'date';
 380  	 	 	 	 }
 381  	 	 	 	 break;
 382  	 	 	 case 12:
 383  	 	 	 	 $fld->type = 'date';
 384  	 	 	 	 break;
 385  	 	 	 case 13:
 386  	 	 	 	 $fld->type = 'time';
 387  	 	 	 	 break;
 388  	 	 	 case 37:
 389  	 	 	 	 $fld->type = 'varchar';
 390  	 	 	 	 break;
 391  	 	 	 case 40:
 392  	 	 	 	 $fld->type = 'cstring';
 393  	 	 	 	 break;
 394  	 	 	 case 261:
 395  	 	 	 	 $fld->type = 'blob';
 396  	 	 	 	 $fld->max_length = -1;
 397  	 	 	 	 break;
 398  	 	 } // switch
 399  	 }
 400  }
 401  
 402  /**
 403   * Class ADORecordSet_pdo_firebird
 404   */
 405  class ADORecordSet_pdo_firebird extends ADORecordSet_pdo
 406  {
 407  
 408  	 public $databaseType = "pdo_firebird";
 409  
 410  	 /**
 411  	  * returns the field object
 412  	  *
 413  	  * @param int $fieldOffset Optional field offset
 414  	  *
 415  	  * @return object The ADOFieldObject describing the field
 416  	  */
 417  	public function fetchField($fieldOffset = 0)
 418  	 {
 419  	 }
 420  }
 421  
 422  /**
 423   * Class ADORecordSet_array_pdo_firebird
 424   */
 425  class ADORecordSet_array_pdo_firebird extends ADORecordSet_array_pdo
 426  {
 427  	 public $databaseType = "pdo_firebird";
 428  	 public $canSeek = true;
 429  
 430  	 /**
 431  	  * returns the field object
 432  	  *
 433  	  * @param int $fieldOffset Optional field offset
 434  	  *
 435  	  * @return object The ADOFieldObject describing the field
 436  	  */
 437  	public function fetchField($fieldOffset = 0)
 438  	 {
 439  
 440  	 	 $fld = new ADOFieldObject;
 441  	 	 $fld->name = $fieldOffset;
 442  	 	 $fld->type = 'C';
 443  	 	 $fld->max_length = 0;
 444  
 445  	 	 // This needs to be populated from the metadata
 446  	 	 $fld->not_null = false;
 447  	 	 $fld->has_default = false;
 448  	 	 $fld->default_value = 'null';
 449  
 450  	 	 return $fld;
 451  	 }
 452  }