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

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