Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

postgres.php

Zuletzt modifiziert: 09.10.2024, 12:54 - Dateigröße: 15.83 KiB


001  <?php
002  /**
003   *
004   * This file is part of the phpBB Forum Software package.
005   *
006   * @copyright (c) phpBB Limited <https://www.phpbb.com>
007   * @license GNU General Public License, version 2 (GPL-2.0)
008   *
009   * For full copyright and license information, please see
010   * the docs/CREDITS.txt file.
011   *
012   */
013   
014  namespace phpbb\db\tools;
015   
016  /**
017   * Database Tools for handling cross-db actions such as altering columns, etc.
018   * Currently not supported is returning SQL for creating tables.
019   */
020  class postgres extends tools
021  {
022      /**
023       * Get the column types for postgres only
024       *
025       * @return array
026       */
027      public static function get_dbms_type_map()
028      {
029          return array(
030              'postgres'    => array(
031                  'INT:'        => 'INT4',
032                  'BINT'        => 'INT8',
033                  'ULINT'        => 'INT4', // unsigned
034                  'UINT'        => 'INT4', // unsigned
035                  'UINT:'        => 'INT4', // unsigned
036                  'USINT'        => 'INT2', // unsigned
037                  'BOOL'        => 'INT2', // unsigned
038                  'TINT:'        => 'INT2',
039                  'VCHAR'        => 'varchar(255)',
040                  'VCHAR:'    => 'varchar(%d)',
041                  'CHAR:'        => 'char(%d)',
042                  'XSTEXT'    => 'varchar(1000)',
043                  'STEXT'        => 'varchar(3000)',
044                  'TEXT'        => 'varchar(8000)',
045                  'MTEXT'        => 'TEXT',
046                  'XSTEXT_UNI'=> 'varchar(100)',
047                  'STEXT_UNI'    => 'varchar(255)',
048                  'TEXT_UNI'    => 'varchar(4000)',
049                  'MTEXT_UNI'    => 'TEXT',
050                  'TIMESTAMP'    => 'INT4', // unsigned
051                  'DECIMAL'    => 'decimal(5,2)',
052                  'DECIMAL:'    => 'decimal(%d,2)',
053                  'PDECIMAL'    => 'decimal(6,3)',
054                  'PDECIMAL:'    => 'decimal(%d,3)',
055                  'VCHAR_UNI'    => 'varchar(255)',
056                  'VCHAR_UNI:'=> 'varchar(%d)',
057                  'VCHAR_CI'    => 'varchar_ci',
058                  'VARBINARY'    => 'bytea',
059              ),
060          );
061      }
062   
063      /**
064      * Constructor. Set DB Object and set {@link $return_statements return_statements}.
065      *
066      * @param \phpbb\db\driver\driver_interface    $db                    Database connection
067      * @param bool        $return_statements    True if only statements should be returned and no SQL being executed
068      */
069      public function __construct(\phpbb\db\driver\driver_interface $db, $return_statements = false)
070      {
071          parent::__construct($db, $return_statements);
072   
073          // Determine mapping database type
074          $this->sql_layer = 'postgres';
075   
076          $this->dbms_type_map = self::get_dbms_type_map();
077      }
078   
079      /**
080       * {@inheritDoc}
081       */
082      function sql_list_tables()
083      {
084          $sql = 'SELECT relname
085              FROM pg_stat_user_tables';
086          $result = $this->db->sql_query($sql);
087   
088          $tables = array();
089          while ($row = $this->db->sql_fetchrow($result))
090          {
091              $name = current($row);
092              $tables[$name] = $name;
093          }
094          $this->db->sql_freeresult($result);
095   
096          return $tables;
097      }
098   
099      /**
100       * {@inheritDoc}
101       */
102      function sql_create_table($table_name, $table_data)
103      {
104          // holds the DDL for a column
105          $columns = $statements = array();
106   
107          if ($this->sql_table_exists($table_name))
108          {
109              return $this->_sql_run_sql($statements);
110          }
111   
112          // Begin transaction
113          $statements[] = 'begin';
114   
115          // Determine if we have created a PRIMARY KEY in the earliest
116          $primary_key_gen = false;
117   
118          // Determine if the table requires a sequence
119          $create_sequence = false;
120   
121          // Begin table sql statement
122          $table_sql = 'CREATE TABLE ' . $table_name . ' (' . "\n";
123   
124          // Iterate through the columns to create a table
125          foreach ($table_data['COLUMNS'] as $column_name => $column_data)
126          {
127              // here lies an array, filled with information compiled on the column's data
128              $prepared_column = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
129   
130              if (isset($prepared_column['auto_increment']) && $prepared_column['auto_increment'] && strlen($column_name) > 26) // "${column_name}_gen"
131              {
132                  trigger_error("Index name '${column_name}_gen' on table '$table_name' is too long. The maximum auto increment column length is 26 characters.", E_USER_ERROR);
133              }
134   
135              // here we add the definition of the new column to the list of columns
136              $columns[] = "\t {$column_name} " . $prepared_column['column_type_sql'];
137   
138              // see if we have found a primary key set due to a column definition if we have found it, we can stop looking
139              if (!$primary_key_gen)
140              {
141                  $primary_key_gen = isset($prepared_column['primary_key_set']) && $prepared_column['primary_key_set'];
142              }
143   
144              // create sequence DDL based off of the existance of auto incrementing columns
145              if (!$create_sequence && isset($prepared_column['auto_increment']) && $prepared_column['auto_increment'])
146              {
147                  $create_sequence = $column_name;
148              }
149          }
150   
151          // this makes up all the columns in the create table statement
152          $table_sql .= implode(",\n", $columns);
153   
154          // we have yet to create a primary key for this table,
155          // this means that we can add the one we really wanted instead
156          if (!$primary_key_gen)
157          {
158              // Write primary key
159              if (isset($table_data['PRIMARY_KEY']))
160              {
161                  if (!is_array($table_data['PRIMARY_KEY']))
162                  {
163                      $table_data['PRIMARY_KEY'] = array($table_data['PRIMARY_KEY']);
164                  }
165   
166                  $table_sql .= ",\n\t PRIMARY KEY (" . implode(', ', $table_data['PRIMARY_KEY']) . ')';
167              }
168          }
169   
170          // do we need to add a sequence for auto incrementing columns?
171          if ($create_sequence)
172          {
173              $statements[] = "CREATE SEQUENCE {$table_name}_seq;";
174          }
175   
176          // close the table
177          $table_sql .= "\n);";
178          $statements[] = $table_sql;
179   
180          // Write Keys
181          if (isset($table_data['KEYS']))
182          {
183              foreach ($table_data['KEYS'] as $key_name => $key_data)
184              {
185                  if (!is_array($key_data[1]))
186                  {
187                      $key_data[1] = array($key_data[1]);
188                  }
189   
190                  $old_return_statements = $this->return_statements;
191                  $this->return_statements = true;
192   
193                  $key_stmts = ($key_data[0] == 'UNIQUE') ? $this->sql_create_unique_index($table_name, $key_name, $key_data[1]) : $this->sql_create_index($table_name, $key_name, $key_data[1]);
194   
195                  foreach ($key_stmts as $key_stmt)
196                  {
197                      $statements[] = $key_stmt;
198                  }
199   
200                  $this->return_statements = $old_return_statements;
201              }
202          }
203   
204          // Commit Transaction
205          $statements[] = 'commit';
206   
207          return $this->_sql_run_sql($statements);
208      }
209   
210      /**
211       * {@inheritDoc}
212       */
213      function sql_list_columns($table_name)
214      {
215          $columns = array();
216   
217          $sql = "SELECT a.attname
218              FROM pg_class c, pg_attribute a
219              WHERE c.relname = '{$table_name}'
220                  AND a.attnum > 0
221                  AND a.attrelid = c.oid";
222          $result = $this->db->sql_query($sql);
223   
224          while ($row = $this->db->sql_fetchrow($result))
225          {
226              $column = strtolower(current($row));
227              $columns[$column] = $column;
228          }
229          $this->db->sql_freeresult($result);
230   
231          return $columns;
232      }
233   
234      /**
235       * {@inheritDoc}
236       */
237      function sql_index_exists($table_name, $index_name)
238      {
239          $sql = "SELECT ic.relname as index_name
240              FROM pg_class bc, pg_class ic, pg_index i
241              WHERE (bc.oid = i.indrelid)
242                  AND (ic.oid = i.indexrelid)
243                  AND (bc.relname = '" . $table_name . "')
244                  AND (i.indisunique != 't')
245                  AND (i.indisprimary != 't')";
246          $result = $this->db->sql_query($sql);
247   
248          while ($row = $this->db->sql_fetchrow($result))
249          {
250              // This DBMS prefixes index names with the table name
251              $row['index_name'] = $this->strip_table_name_from_index_name($table_name, $row['index_name']);
252   
253              if (strtolower($row['index_name']) == strtolower($index_name))
254              {
255                  $this->db->sql_freeresult($result);
256                  return true;
257              }
258          }
259          $this->db->sql_freeresult($result);
260   
261          return false;
262      }
263   
264      /**
265       * {@inheritDoc}
266       */
267      function sql_unique_index_exists($table_name, $index_name)
268      {
269          $sql = "SELECT ic.relname as index_name, i.indisunique
270              FROM pg_class bc, pg_class ic, pg_index i
271              WHERE (bc.oid = i.indrelid)
272                  AND (ic.oid = i.indexrelid)
273                  AND (bc.relname = '" . $table_name . "')
274                  AND (i.indisprimary != 't')";
275          $result = $this->db->sql_query($sql);
276   
277          while ($row = $this->db->sql_fetchrow($result))
278          {
279              if ($row['indisunique'] != 't')
280              {
281                  continue;
282              }
283   
284              // This DBMS prefixes index names with the table name
285              $row['index_name'] = $this->strip_table_name_from_index_name($table_name, $row['index_name']);
286   
287              if (strtolower($row['index_name']) == strtolower($index_name))
288              {
289                  $this->db->sql_freeresult($result);
290                  return true;
291              }
292          }
293          $this->db->sql_freeresult($result);
294   
295          return false;
296      }
297   
298      /**
299      * Function to prepare some column information for better usage
300      * @access private
301      */
302      function sql_prepare_column_data($table_name, $column_name, $column_data)
303      {
304          if (strlen($column_name) > 30)
305          {
306              trigger_error("Column name '$column_name' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR);
307          }
308   
309          // Get type
310          list($column_type, $orig_column_type) = $this->get_column_type($column_data[0]);
311   
312          // Adjust default value if db-dependent specified
313          if (is_array($column_data[1]))
314          {
315              $column_data[1] = (isset($column_data[1][$this->sql_layer])) ? $column_data[1][$this->sql_layer] : $column_data[1]['default'];
316          }
317   
318          $sql = " {$column_type} ";
319   
320          $return_array = array(
321              'column_type'        => $column_type,
322              'auto_increment'    => false,
323          );
324   
325          if (isset($column_data[2]) && $column_data[2] == 'auto_increment')
326          {
327              $default_val = "nextval('{$table_name}_seq')";
328              $return_array['auto_increment'] = true;
329          }
330          else if (!is_null($column_data[1]))
331          {
332              $default_val = "'" . $column_data[1] . "'";
333              $return_array['null'] = 'NOT NULL';
334              $sql .= 'NOT NULL ';
335          }
336          else
337          {
338              // Integers need to have 0 instead of empty string as default
339              if (strpos($column_type, 'INT') === 0)
340              {
341                  $default_val = '0';
342              }
343              else
344              {
345                  $default_val = "'" . $column_data[1] . "'";
346              }
347              $return_array['null'] = 'NULL';
348              $sql .= 'NULL ';
349          }
350   
351          $return_array['default'] = $default_val;
352   
353          $sql .= "DEFAULT {$default_val}";
354   
355          // Unsigned? Then add a CHECK contraint
356          if (in_array($orig_column_type, $this->unsigned_types))
357          {
358              $return_array['constraint'] = "CHECK ({$column_name} >= 0)";
359              $sql .= " CHECK ({$column_name} >= 0)";
360          }
361   
362          $return_array['column_type_sql'] = $sql;
363   
364          return $return_array;
365      }
366   
367      /**
368       * {@inheritDoc}
369       */
370      function sql_column_add($table_name, $column_name, $column_data, $inline = false)
371      {
372          $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
373          $statements = array();
374   
375          // Does not support AFTER, only through temporary table
376          if (version_compare($this->db->sql_server_info(true), '8.0', '>='))
377          {
378              $statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type_sql'];
379          }
380          else
381          {
382              // old versions cannot add columns with default and null information
383              $statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type'] . ' ' . $column_data['constraint'];
384   
385              if (isset($column_data['null']))
386              {
387                  if ($column_data['null'] == 'NOT NULL')
388                  {
389                      $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN ' . $column_name . ' SET NOT NULL';
390                  }
391              }
392   
393              if (isset($column_data['default']))
394              {
395                  $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN ' . $column_name . ' SET DEFAULT ' . $column_data['default'];
396              }
397          }
398   
399          return $this->_sql_run_sql($statements);
400      }
401   
402      /**
403       * {@inheritDoc}
404       */
405      function sql_column_remove($table_name, $column_name, $inline = false)
406      {
407          $statements = array();
408   
409          $statements[] = 'ALTER TABLE ' . $table_name . ' DROP COLUMN "' . $column_name . '"';
410   
411          return $this->_sql_run_sql($statements);
412      }
413   
414      /**
415       * {@inheritDoc}
416       */
417      function sql_index_drop($table_name, $index_name)
418      {
419          $statements = array();
420   
421          $statements[] = 'DROP INDEX ' . $table_name . '_' . $index_name;
422   
423          return $this->_sql_run_sql($statements);
424      }
425   
426      /**
427       * {@inheritDoc}
428       */
429      function sql_table_drop($table_name)
430      {
431          $statements = array();
432   
433          if (!$this->sql_table_exists($table_name))
434          {
435              return $this->_sql_run_sql($statements);
436          }
437   
438          // the most basic operation, get rid of the table
439          $statements[] = 'DROP TABLE ' . $table_name;
440   
441          // PGSQL does not "tightly" bind sequences and tables, we must guess...
442          $sql = "SELECT relname
443              FROM pg_class
444              WHERE relkind = 'S'
445                  AND relname = '{$table_name}_seq'";
446          $result = $this->db->sql_query($sql);
447   
448          // We don't even care about storing the results. We already know the answer if we get rows back.
449          if ($this->db->sql_fetchrow($result))
450          {
451              $statements[] =  "DROP SEQUENCE {$table_name}_seq;\n";
452          }
453          $this->db->sql_freeresult($result);
454   
455          return $this->_sql_run_sql($statements);
456      }
457   
458      /**
459       * {@inheritDoc}
460       */
461      function sql_create_primary_key($table_name, $column, $inline = false)
462      {
463          $statements = array();
464   
465          $statements[] = 'ALTER TABLE ' . $table_name . ' ADD PRIMARY KEY (' . implode(', ', $column) . ')';
466   
467          return $this->_sql_run_sql($statements);
468      }
469   
470      /**
471       * {@inheritDoc}
472       */
473      function sql_create_unique_index($table_name, $index_name, $column)
474      {
475          $statements = array();
476   
477          $this->check_index_name_length($table_name, $index_name);
478   
479          $statements[] = 'CREATE UNIQUE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')';
480   
481          return $this->_sql_run_sql($statements);
482      }
483   
484      /**
485       * {@inheritDoc}
486       */
487      function sql_create_index($table_name, $index_name, $column)
488      {
489          $statements = array();
490   
491          $this->check_index_name_length($table_name, $index_name);
492   
493          // remove index length
494          $column = preg_replace('#:.*$#', '', $column);
495   
496          $statements[] = 'CREATE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')';
497   
498          return $this->_sql_run_sql($statements);
499      }
500   
501   
502      /**
503       * {@inheritDoc}
504       */
505      function sql_list_index($table_name)
506      {
507          $index_array = array();
508   
509          $sql = "SELECT ic.relname as index_name
510              FROM pg_class bc, pg_class ic, pg_index i
511              WHERE (bc.oid = i.indrelid)
512                  AND (ic.oid = i.indexrelid)
513                  AND (bc.relname = '" . $table_name . "')
514                  AND (i.indisunique != 't')
515                  AND (i.indisprimary != 't')";
516          $result = $this->db->sql_query($sql);
517   
518          while ($row = $this->db->sql_fetchrow($result))
519          {
520              $row['index_name'] = $this->strip_table_name_from_index_name($table_name, $row['index_name']);
521   
522              $index_array[] = $row['index_name'];
523          }
524          $this->db->sql_freeresult($result);
525   
526          return array_map('strtolower', $index_array);
527      }
528   
529      /**
530       * {@inheritDoc}
531       */
532      function sql_column_change($table_name, $column_name, $column_data, $inline = false)
533      {
534          $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
535          $statements = array();
536   
537          $sql = 'ALTER TABLE ' . $table_name . ' ';
538   
539          $sql_array = array();
540          $sql_array[] = 'ALTER COLUMN ' . $column_name . ' TYPE ' . $column_data['column_type'];
541   
542          if (isset($column_data['null']))
543          {
544              if ($column_data['null'] == 'NOT NULL')
545              {
546                  $sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET NOT NULL';
547              }
548              else if ($column_data['null'] == 'NULL')
549              {
550                  $sql_array[] = 'ALTER COLUMN ' . $column_name . ' DROP NOT NULL';
551              }
552          }
553   
554          if (isset($column_data['default']))
555          {
556              $sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET DEFAULT ' . $column_data['default'];
557          }
558   
559          // we don't want to double up on constraints if we change different number data types
560          if (isset($column_data['constraint']))
561          {
562              $constraint_sql = "SELECT consrc as constraint_data
563                  FROM pg_constraint, pg_class bc
564                  WHERE conrelid = bc.oid
565                      AND bc.relname = '{$table_name}'
566                      AND NOT EXISTS (
567                          SELECT *
568                          FROM pg_constraint as c, pg_inherits as i
569                          WHERE i.inhrelid = pg_constraint.conrelid
570                              AND c.conname = pg_constraint.conname
571                              AND c.consrc = pg_constraint.consrc
572                              AND c.conrelid = i.inhparent
573                      )";
574   
575              $constraint_exists = false;
576   
577              $result = $this->db->sql_query($constraint_sql);
578              while ($row = $this->db->sql_fetchrow($result))
579              {
580                  if (trim($row['constraint_data']) == trim($column_data['constraint']))
581                  {
582                      $constraint_exists = true;
583                      break;
584                  }
585              }
586              $this->db->sql_freeresult($result);
587   
588              if (!$constraint_exists)
589              {
590                  $sql_array[] = 'ADD ' . $column_data['constraint'];
591              }
592          }
593   
594          $sql .= implode(', ', $sql_array);
595   
596          $statements[] = $sql;
597   
598          return $this->_sql_run_sql($statements);
599      }
600   
601      /**
602      * Get a list with existing indexes for the column
603      *
604      * @param string $table_name
605      * @param string $column_name
606      * @param bool $unique Should we get unique indexes or normal ones
607      * @return array        Array with Index name => columns
608      */
609      public function get_existing_indexes($table_name, $column_name, $unique = false)
610      {
611          // Not supported
612          throw new \Exception('DBMS is not supported');
613      }
614  }
615