[ Index ] |
PHP Cross Reference of MyBB 1.8.38 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * MyBB 1.8 4 * Copyright 2020 MyBB Group, All Rights Reserved 5 * 6 * Website: http://www.mybb.com 7 * License: http://www.mybb.com/about/license 8 */ 9 10 class PostgresPdoDbDriver extends AbstractPdoDbDriver 11 { 12 /** 13 * The title of this layer. 14 * 15 * @var string 16 */ 17 public $title = "PostgreSQL (PDO)"; 18 19 /** 20 * The short title of this layer. 21 * 22 * @var string 23 */ 24 public $short_title = "PostgreSQL (PDO)"; 25 26 /** 27 * Explanation of a query. 28 * 29 * @var string 30 */ 31 public $explain = ''; 32 33 protected function getDsn($hostname, $db, $port, $encoding) 34 { 35 $dsn = "pgsql:host={$hostname};dbname={$db}"; 36 37 if ($port !== null) { 38 $dsn .= ";port={$port}"; 39 } 40 41 if (!empty($encoding)) { 42 $dsn .= ";options='--client_encoding={$encoding}'"; 43 } 44 45 return $dsn; 46 } 47 48 public function query($string, $hideErrors = false, $writeQuery = false) 49 { 50 $string = preg_replace("#LIMIT (\s*)([0-9]+),(\s*)([0-9]+);?$#im", "LIMIT $4 OFFSET $2", trim($string)); 51 52 return parent::query($string, $hideErrors, $writeQuery); 53 } 54 55 public function explain_query($string, $qtime) 56 { 57 $duration = format_time_duration($qtime); 58 $queryText = htmlspecialchars_uni($string); 59 60 if (preg_match('/^\\s*SELECT\\b/i', $string) === 1) { 61 $query = $this->current_link->query("EXPLAIN {$string}"); 62 63 $this->explain .= <<<HTML 64 <table style="background-color: #666;" width="95%" cellpadding="4" cellspacing="1" align="center"> 65 <tr> 66 <td colspan="8" style="background-color: #ccc;"> 67 <strong>#{$this->query_count} - Select Query</strong> 68 </td> 69 </tr> 70 <tr> 71 <td colspan="8" style="background-color: #fefefe;"> 72 <span style=\"font-family: Courier; font-size: 14px;">{$queryText}</span> 73 </td> 74 <tr style="background-color: #efefef"> 75 <td> 76 <strong>Info</strong> 77 </td> 78 </tr> 79 HTML; 80 81 while ($table = $query->fetch(PDO::FETCH_ASSOC)) { 82 $this->explain .= <<<HTML 83 <tr style="background-color: #fff"> 84 <td>{$table['QUERY PLAN']}</td> 85 </tr> 86 HTML; 87 } 88 89 $this->explain .= <<<HTML 90 <tr> 91 <td colspan="8" style="background-color: #fff;"> 92 Query Time: {$duration} 93 </td> 94 </tr> 95 </table> 96 <br /> 97 HTML; 98 } else { 99 $this->explain .= <<<HTML 100 <table style="background-color: #666;" width="95%" cellpadding="4" cellspacing="1" align="center"> 101 <tr> 102 <td style="background-color: #ccc;"> 103 <strong>#{$this->query_count} - Write Query</strong> 104 </td> 105 </tr> 106 <tr style="background-color: #fefefe;"> 107 <td> 108 <span style="font-family: Courier; font-size: 14px;">{$queryText}</span> 109 </td> 110 </tr> 111 <tr> 112 <td style="background-color: #fff"> 113 Query Time: {$duration} 114 </td> 115 </tr> 116 </table> 117 <br /> 118 HTML; 119 } 120 121 $this->querylist[$this->query_count]['query'] = $string; 122 $this->querylist[$this->query_count]['time'] = $qtime; 123 } 124 125 public function list_tables($database, $prefix = '') 126 { 127 if ($prefix) { 128 $query = $this->write_query("SELECT table_name FROM information_schema.tables WHERE table_schema='public' AND table_name LIKE '{$this->escape_string($prefix)}%'"); 129 } else { 130 $query = $this->write_query("SELECT table_name FROM information_schema.tables WHERE table_schema='public'"); 131 } 132 133 return $query->fetchAll(PDO::FETCH_COLUMN); 134 } 135 136 public function table_exists($table) 137 { 138 $query = $this->write_query("SELECT COUNT(table_name) as table_names FROM information_schema.tables WHERE table_schema = 'public' AND table_name='{$this->table_prefix}{$table}'"); 139 140 $exists = $this->fetch_field($query, 'table_names'); 141 142 return $exists > 0; 143 } 144 145 public function field_exists($field, $table) 146 { 147 $query = $this->write_query("SELECT COUNT(column_name) as column_names FROM information_schema.columns WHERE table_name='{$this->table_prefix}{$table}' AND column_name='{$field}'"); 148 149 $exists = $this->fetch_field($query, 'column_names'); 150 151 return $exists > 0; 152 } 153 154 public function simple_select($table, $fields = "*", $conditions = "", $options = array()) 155 { 156 $query = "SELECT {$fields} FROM {$this->table_prefix}{$table}"; 157 if ($conditions != "") { 158 $query .= " WHERE {$conditions}"; 159 } 160 161 if (isset($options['group_by'])) { 162 $query .= " GROUP BY {$options['group_by']}"; 163 } 164 165 if (isset($options['order_by'])) { 166 $query .= " ORDER BY {$options['order_by']}"; 167 if (isset($options['order_dir'])) { 168 $query .= " {$options['order_dir']}"; 169 } 170 } 171 172 if (isset($options['limit_start']) && isset($options['limit'])) { 173 $query .= " LIMIT {$options['limit']} OFFSET {$options['limit_start']}"; 174 } else if (isset($options['limit'])) { 175 $query .= " LIMIT {$options['limit']}"; 176 } 177 178 return $this->query($query); 179 } 180 181 public function insert_query($table, $array) 182 { 183 if (!is_array($array)) { 184 return false; 185 } 186 187 $values = $this->build_value_string($table, $array); 188 189 $fields = implode(",", array_keys($array)); 190 $this->write_query(" 191 INSERT 192 INTO {$this->table_prefix}{$table} ({$fields}) 193 VALUES ({$values}) 194 "); 195 196 return $this->insert_id(); 197 } 198 199 private function quote_val($value, $quote = "'") 200 { 201 if (is_int($value)) { 202 return $value; 203 } 204 205 return "{$quote}{$value}{$quote}"; 206 } 207 208 public function insert_query_multiple($table, $array) 209 { 210 if (!is_array($array)){ 211 return; 212 } 213 214 // Field names 215 $fields = array_keys($array[0]); 216 $fields = implode(",", $fields); 217 218 $insert_rows = array(); 219 foreach ($array as $values) { 220 $insert_rows[] = "(".$this->build_value_string($table, $values).")"; 221 } 222 223 $insert_rows = implode(", ", $insert_rows); 224 225 $this->write_query(" 226 INSERT 227 INTO {$this->table_prefix}{$table} ({$fields}) 228 VALUES {$insert_rows} 229 "); 230 } 231 232 public function update_query($table, $array, $where = "", $limit = "", $no_quote = false) 233 { 234 global $mybb; 235 236 if (!is_array($array)) { 237 return false; 238 } 239 240 $query = $this->build_field_value_string($table, $array, $no_quote); 241 242 if(!empty($where)) { 243 $query .= " WHERE {$where}"; 244 } 245 246 return $this->write_query(" 247 UPDATE {$this->table_prefix}$table 248 SET $query 249 "); 250 } 251 252 public function delete_query($table, $where = "", $limit = "") 253 { 254 $query = ""; 255 if (!empty($where)) { 256 $query .= " WHERE {$where}"; 257 } 258 259 return $this->write_query(" 260 DELETE 261 FROM {$this->table_prefix}$table 262 $query 263 "); 264 } 265 266 public function optimize_table($table) 267 { 268 $this->write_query("VACUUM {$this->table_prefix}{$table};"); 269 } 270 271 public function analyze_table($table) 272 { 273 $this->write_query("ANALYZE {$this->table_prefix}{$table};"); 274 } 275 276 public function show_create_table($table) 277 { 278 $query = $this->write_query(" 279 SELECT a.attnum, a.attname as field, t.typname as type, a.attlen as length, a.atttypmod as lengthvar, a.attnotnull as notnull 280 FROM pg_class c 281 LEFT JOIN pg_attribute a ON (a.attrelid = c.oid) 282 LEFT JOIN pg_type t ON (a.atttypid = t.oid) 283 WHERE c.relname = '{$this->table_prefix}{$table}' AND a.attnum > 0 284 ORDER BY a.attnum 285 "); 286 287 $lines = array(); 288 $table_lines = "CREATE TABLE {$this->table_prefix}{$table} (\n"; 289 290 while ($row = $this->fetch_array($query)) { 291 // Get the data from the table 292 $query2 = $this->write_query(" 293 SELECT pg_get_expr(d.adbin, d.adrelid) as rowdefault 294 FROM pg_attrdef d 295 LEFT JOIN pg_class c ON (c.oid = d.adrelid) 296 WHERE c.relname = '{$this->table_prefix}{$table}' AND d.adnum = '{$row['attnum']}' 297 "); 298 299 if (!$query2) { 300 unset($row['rowdefault']); 301 } else { 302 $row['rowdefault'] = $this->fetch_field($query2, 'rowdefault'); 303 } 304 305 if ($row['type'] == 'bpchar') { 306 // Stored in the engine as bpchar, but in the CREATE TABLE statement it's char 307 $row['type'] = 'char'; 308 } 309 310 $line = " {$row['field']} {$row['type']}"; 311 312 if (strpos($row['type'], 'char') !== false) { 313 if ($row['lengthvar'] > 0) { 314 $line .= '('.($row['lengthvar'] - 4).')'; 315 } 316 } 317 318 if (strpos($row['type'], 'numeric') !== false) { 319 $line .= '('.sprintf("%s,%s", (($row['lengthvar'] >> 16) & 0xffff), (($row['lengthvar'] - 4) & 0xffff)).')'; 320 } 321 322 if (!empty($row['rowdefault'])) { 323 $line .= " DEFAULT {$row['rowdefault']}"; 324 } 325 326 if ($row['notnull'] == 't') { 327 $line .= ' NOT NULL'; 328 } 329 330 $lines[] = $line; 331 } 332 333 // Get the listing of primary keys. 334 $query = $this->write_query(" 335 SELECT ic.relname as index_name, bc.relname as tab_name, ta.attname as column_name, i.indisunique as unique_key, i.indisprimary as primary_key 336 FROM pg_class bc 337 LEFT JOIN pg_index i ON (bc.oid = i.indrelid) 338 LEFT JOIN pg_class ic ON (ic.oid = i.indexrelid) 339 LEFT JOIN pg_attribute ia ON (ia.attrelid = i.indexrelid) 340 LEFT JOIN pg_attribute ta ON (ta.attrelid = bc.oid AND ta.attrelid = i.indrelid AND ta.attnum = i.indkey[ia.attnum-1]) 341 WHERE bc.relname = '{$this->table_prefix}{$table}' 342 ORDER BY index_name, tab_name, column_name 343 "); 344 345 $primary_key = array(); 346 $primary_key_name = ''; 347 348 $unique_keys = array(); 349 350 // We do this in two steps. It makes placing the comma easier 351 while ($row = $this->fetch_array($query)) { 352 if ($row['primary_key'] == 't') { 353 $primary_key[] = $row['column_name']; 354 $primary_key_name = $row['index_name']; 355 } 356 357 if ($row['unique_key'] == 't') { 358 $unique_keys[$row['index_name']][] = $row['column_name']; 359 } 360 } 361 362 if (!empty($primary_key)) { 363 $lines[] = " CONSTRAINT $primary_key_name PRIMARY KEY (".implode(', ', $primary_key).")"; 364 } 365 366 foreach ($unique_keys as $key_name => $key_columns) { 367 $lines[] = " CONSTRAINT $key_name UNIQUE (".implode(', ', $key_columns).")"; 368 } 369 370 $table_lines .= implode(", \n", $lines); 371 $table_lines .= "\n)\n"; 372 373 return $table_lines; 374 } 375 376 public function show_fields_from($table) 377 { 378 $query = $this->write_query("SELECT column_name FROM information_schema.constraint_column_usage WHERE table_name = '{$this->table_prefix}{$table}' and constraint_name = '{$this->table_prefix}{$table}_pkey' LIMIT 1"); 379 $primary_key = $this->fetch_field($query, 'column_name'); 380 381 $query = $this->write_query(" 382 SELECT column_name, data_type, is_nullable, column_default, character_maximum_length, numeric_precision, numeric_precision_radix, numeric_scale 383 FROM information_schema.columns 384 WHERE table_name = '{$this->table_prefix}{$table}' 385 "); 386 387 $field_info = array(); 388 while ($field = $this->fetch_array($query)) { 389 if ($field['column_name'] == $primary_key) { 390 $field['_key'] = 'PRI'; 391 } else { 392 $field['_key'] = ''; 393 } 394 395 if (!is_null($field['column_default']) && stripos($field['column_default'], 'nextval') !== false) { 396 $field['_extra'] = 'auto_increment'; 397 } else { 398 $field['_extra'] = ''; 399 } 400 401 // bit, character, text fields. 402 if (!is_null($field['character_maximum_length'])) { 403 $field['data_type'] .= '('.(int)$field['character_maximum_length'].')'; 404 } 405 // numeric/decimal fields. 406 else if ($field['numeric_precision_radix'] == 10 && !is_null($field['numeric_precision']) && !is_null($field['numeric_scale'])) { 407 $field['data_type'] .= '('.(int)$field['numeric_precision'].','.(int)$field['numeric_scale'].')'; 408 } 409 410 $field_info[] = array( 411 'Field' => $field['column_name'], 412 'Type' => $field['data_type'], 413 'Null' => $field['is_nullable'], 414 'Key' => $field['_key'], 415 'Default' => $field['column_default'], 416 'Extra' => $field['_extra'], 417 ); 418 } 419 420 return $field_info; 421 } 422 423 function is_fulltext($table, $index = "") 424 { 425 return false; 426 } 427 428 public function supports_fulltext($table) 429 { 430 return false; 431 } 432 433 public function index_exists($table, $index) 434 { 435 $err = $this->error_reporting; 436 $this->error_reporting = 0; 437 438 $tableName = $this->escape_string("{$this->table_prefix}{$table}"); 439 440 $query = $this->write_query("SELECT * FROM pg_indexes WHERE tablename = '{$tableName}'"); 441 442 $exists = $this->fetch_field($query, $index); 443 $this->error_reporting = $err; 444 445 return (bool)$exists; 446 } 447 448 public function supports_fulltext_boolean($table) 449 { 450 return false; 451 } 452 453 public function create_fulltext_index($table, $column, $name = "") 454 { 455 return false; 456 } 457 458 public function drop_index($table, $name) 459 { 460 $this->write_query(" 461 ALTER TABLE {$this->table_prefix}{$table} 462 DROP INDEX {$name} 463 "); 464 } 465 466 public function drop_table($table, $hard = false, $table_prefix = true) 467 { 468 if ($table_prefix == false) { 469 $table_prefix = ""; 470 } else { 471 $table_prefix = $this->table_prefix; 472 } 473 474 $table_prefix_bak = $this->table_prefix; 475 $this->table_prefix = ''; 476 $fields = array_column($this->show_fields_from($table_prefix.$table), 'Field'); 477 478 if ($hard == false) { 479 if($this->table_exists($table_prefix.$table)) 480 { 481 $this->write_query("DROP TABLE {$table_prefix}{$table}"); 482 } 483 } else { 484 $this->write_query("DROP TABLE {$table_prefix}{$table}"); 485 } 486 487 $this->table_prefix = $table_prefix_bak; 488 489 if(!empty($fields)) { 490 foreach ($fields as &$field) { 491 $field = "{$table_prefix}{$table}_{$field}_seq"; 492 } 493 unset($field); 494 495 if (version_compare($this->get_version(), '8.2.0', '>=')) { 496 $fields = implode(', ', $fields); 497 $this->write_query("DROP SEQUENCE IF EXISTS {$fields}"); 498 } else { 499 $fields = "'" . implode("', '", $fields) . "'"; 500 $query = $this->query("SELECT sequence_name as field FROM information_schema.sequences WHERE sequence_name in ({$fields}) AND sequence_schema = 'public'"); 501 while ($row = $this->fetch_array($query)) { 502 $this->write_query("DROP SEQUENCE {$row['field']}"); 503 } 504 } 505 } 506 } 507 508 public function rename_table($old_table, $new_table, $table_prefix = true) 509 { 510 if ($table_prefix == false) { 511 $table_prefix = ""; 512 } else { 513 $table_prefix = $this->table_prefix; 514 } 515 516 return $this->write_query("ALTER TABLE {$table_prefix}{$old_table} RENAME TO {$table_prefix}{$new_table}"); 517 } 518 519 public function replace_query($table, $replacements = array(), $default_field = "", $insert_id = true) 520 { 521 global $mybb; 522 523 if ($default_field == "") { 524 $query = $this->write_query("SELECT column_name FROM information_schema.constraint_column_usage WHERE table_name = '{$this->table_prefix}{$table}' and constraint_name = '{$this->table_prefix}{$table}_pkey' LIMIT 1"); 525 $main_field = $this->fetch_field($query, 'column_name'); 526 } else { 527 $main_field = $default_field; 528 } 529 530 if (!is_array($main_field)) { 531 $main_field = array($main_field); 532 } 533 534 if(version_compare($this->get_version(), '9.5.0', '>=')) 535 { 536 // ON CONFLICT clause supported 537 538 $main_field_csv = implode(',', $main_field); 539 540 // INSERT-like list of fields and values 541 $fields = implode(",", array_keys($replacements)); 542 $values = $this->build_value_string($table, $replacements); 543 544 // UPDATE-like SET list, using special EXCLUDED table to avoid passing values twice 545 $reassignment_values = array(); 546 $true_replacement_keys = array_diff( 547 array_keys($replacements), 548 array_flip($main_field) 549 ); 550 foreach($true_replacement_keys as $key) 551 { 552 $reassignment_values[$key] = 'EXCLUDED.' . $key; 553 } 554 555 $reassignments = $this->build_field_value_string($table, $reassignment_values, true); 556 557 $this->write_query(" 558 INSERT 559 INTO {$this->table_prefix}{$table} ({$fields}) 560 VALUES ({$values}) 561 ON CONFLICT ($main_field_csv) DO UPDATE SET {$reassignments} 562 "); 563 } 564 else 565 { 566 // manual SELECT and UPDATE/INSERT (prone to TOCTOU issues) 567 568 $update = false; 569 $search_bit = array(); 570 571 if (!is_array($main_field)) { 572 $main_field = array($main_field); 573 } 574 575 foreach ($main_field as $field) { 576 if (isset($mybb->binary_fields[$table][$field]) && $mybb->binary_fields[$table][$field]) { 577 $search_bit[] = "{$field} = ".$replacements[$field]; 578 } else { 579 $search_bit[] = "{$field} = ".$this->quote_val($replacements[$field]); 580 } 581 } 582 583 $search_bit = implode(" AND ", $search_bit); 584 585 $query = $this->write_query("SELECT COUNT(".$main_field[0].") as count FROM {$this->table_prefix}{$table} WHERE {$search_bit} LIMIT 1"); 586 587 if ($this->fetch_field($query, "count") == 1) { 588 $update = true; 589 } 590 591 if ($update === true) { 592 return $this->update_query($table, $replacements, $search_bit); 593 } else { 594 return $this->insert_query($table, $replacements); 595 } 596 } 597 } 598 599 public function drop_column($table, $column) 600 { 601 return $this->write_query("ALTER TABLE {$this->table_prefix}{$table} DROP {$column}"); 602 } 603 604 public function add_column($table, $column, $definition) 605 { 606 return $this->write_query("ALTER TABLE {$this->table_prefix}{$table} ADD {$column} {$definition}"); 607 } 608 609 public function modify_column($table, $column, $new_definition, $new_not_null = false, $new_default_value = false) 610 { 611 $result1 = $result2 = $result3 = true; 612 613 if ($new_definition !== false) { 614 $result1 = $this->write_query("ALTER TABLE {$this->table_prefix}{$table} ALTER COLUMN {$column} TYPE {$new_definition}"); 615 } 616 617 if ($new_not_null !== false) { 618 $set_drop = "DROP"; 619 620 if (strtolower($new_not_null) == "set") { 621 $set_drop = "SET"; 622 } 623 624 $result2 = $this->write_query("ALTER TABLE {$this->table_prefix}{$table} ALTER COLUMN {$column} {$set_drop} NOT NULL"); 625 } 626 627 if ($new_default_value !== null) { 628 if($new_default_value !== false) { 629 $result3 = $this->write_query("ALTER TABLE {$this->table_prefix}{$table} ALTER COLUMN {$column} SET DEFAULT {$new_default_value}"); 630 } else { 631 $result3 = $this->write_query("ALTER TABLE {$this->table_prefix}{$table} ALTER COLUMN {$column} DROP DEFAULT"); 632 } 633 } 634 635 return $result1 && $result2 && $result3; 636 } 637 638 public function rename_column($table, $old_column, $new_column, $new_definition, $new_not_null = false, $new_default_value = false) 639 { 640 $result1 = $this->write_query("ALTER TABLE {$this->table_prefix}{$table} RENAME COLUMN {$old_column} TO {$new_column}"); 641 $result2 = $this->modify_column($table, $new_column, $new_definition, $new_not_null, $new_default_value); 642 643 return $result1 && $result2; 644 } 645 646 public function fetch_size($table = '') 647 { 648 if (!empty($table)) { 649 $query = $this->query("SELECT SUM(reltuples), SUM(relpages) FROM pg_class WHERE relname = '{$this->table_prefix}{$table}'"); 650 } else { 651 $query = $this->query("SELECT SUM(reltuples), SUM(relpages) FROM pg_class"); 652 } 653 654 if (null === $query) { 655 return 0; 656 } 657 658 $result = $this->fetch_array($query, PDO::FETCH_NUM); 659 660 if (false === $result) { 661 return 0; 662 } 663 664 return $result[0] + $result[1]; 665 } 666 667 public function fetch_db_charsets() 668 { 669 return false; 670 } 671 672 public function fetch_charset_collation($charset) 673 { 674 return false; 675 } 676 677 public function build_create_table_collation() 678 { 679 return ''; 680 } 681 682 public function insert_id() 683 { 684 try { 685 return $this->write_link->lastInsertId(); 686 } catch (PDOException $e) { 687 // in order to behave the same way as the MySQL driver, we return false if there is no last insert ID 688 return false; 689 } 690 } 691 692 public function escape_binary($string) 693 { 694 $hex = bin2hex($string); 695 return "decode('{$hex}', 'hex')"; 696 } 697 698 public function unescape_binary($string) 699 { 700 // binary fields are treated as streams 701 /** @var resource $string */ 702 return fgets($string); 703 } 704 705 /** 706 * @param string $table 707 * @param string $append 708 * 709 * @return string 710 */ 711 public function build_fields_string($table, $append="") 712 { 713 $fields = $this->show_fields_from($table); 714 $comma = $fieldstring = ''; 715 716 foreach($fields as $key => $field) 717 { 718 $fieldstring .= "{$comma}{$append}{$field['Field']}"; 719 $comma = ','; 720 } 721 722 return $fieldstring; 723 } 724 725 /** 726 * @param string $table 727 * @param array $array 728 * @param bool $no_quote 729 * 730 * @return string 731 */ 732 protected function build_field_value_string($table, $array, $no_quote = false) 733 { 734 global $mybb; 735 736 $strings = array(); 737 738 if ($no_quote == true) 739 { 740 $quote = ""; 741 } 742 else 743 { 744 $quote = "'"; 745 } 746 747 foreach($array as $field => $value) 748 { 749 if(!isset($mybb->binary_fields[$table][$field]) || !$mybb->binary_fields[$table][$field]) 750 { 751 $value = $this->quote_val($value, $quote); 752 } 753 754 $strings[] = "{$field}={$value}"; 755 } 756 757 $string = implode(', ', $strings); 758 759 return $string; 760 } 761 762 /** 763 * @param string $table 764 * @param array $array 765 * 766 * @return string 767 */ 768 protected function build_value_string($table, $array) 769 { 770 global $mybb; 771 772 $values = array(); 773 774 foreach($array as $field => $value) 775 { 776 if(!isset($mybb->binary_fields[$table][$field]) || !$mybb->binary_fields[$table][$field]) 777 { 778 $value = $this->quote_val($value); 779 } 780 781 $values[$field] = $value; 782 } 783 784 $string = implode(",", $values); 785 786 return $string; 787 } 788 789 public function __set($name, $value) 790 { 791 if ($name === 'type') { 792 // NOTE: This is to prevent the type being set - this type should appear as `pgsql` to ensure compatibility 793 return; 794 } 795 } 796 797 public function __get($name) 798 { 799 if ($name === 'type') { 800 // NOTE: this is to ensure compatibility checks on the DB type will work 801 return 'pgsql'; 802 } 803 804 return null; 805 } 806 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
2005 - 2021 © MyBB.de | Alle Rechte vorbehalten! | Sponsor: netcup | Cross-referenced by PHPXref |