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 311 and 402] [Versions 400 and 402] [Versions 401 and 402]

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