[ Index ]

PHP Cross Reference of phpBB-3.3.14-deutsch

title

Body

[close]

/phpbb/db/extractor/ -> postgres_extractor.php (source)

   1  <?php
   2  /**
   3  *
   4  * This file is part of the phpBB Forum Software package.
   5  *
   6  * @copyright (c) phpBB Limited <https://www.phpbb.com>
   7  * @license GNU General Public License, version 2 (GPL-2.0)
   8  *
   9  * For full copyright and license information, please see
  10  * the docs/CREDITS.txt file.
  11  *
  12  */
  13  
  14  namespace phpbb\db\extractor;
  15  
  16  use phpbb\db\extractor\exception\extractor_not_initialized_exception;
  17  
  18  class postgres_extractor extends base_extractor
  19  {
  20      /**
  21      * {@inheritdoc}
  22      */
  23  	public function write_start($table_prefix)
  24      {
  25          if (!$this->is_initialized)
  26          {
  27              throw new extractor_not_initialized_exception();
  28          }
  29  
  30          $sql_data = "--\n";
  31          $sql_data .= "-- phpBB Backup Script\n";
  32          $sql_data .= "-- Dump of tables for $table_prefix\n";
  33          $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
  34          $sql_data .= "--\n";
  35          $sql_data .= "BEGIN TRANSACTION;\n";
  36          $this->flush($sql_data);
  37      }
  38  
  39      /**
  40      * {@inheritdoc}
  41      */
  42  	public function write_table($table_name)
  43      {
  44          static $domains_created = array();
  45  
  46          if (!$this->is_initialized)
  47          {
  48              throw new extractor_not_initialized_exception();
  49          }
  50  
  51          $sql = "SELECT a.domain_name, a.data_type, a.character_maximum_length, a.domain_default
  52              FROM INFORMATION_SCHEMA.domains a, INFORMATION_SCHEMA.column_domain_usage b
  53              WHERE a.domain_name = b.domain_name
  54                  AND b.table_name = '{$table_name}'";
  55          $result = $this->db->sql_query($sql);
  56          while ($row = $this->db->sql_fetchrow($result))
  57          {
  58              if (empty($domains_created[$row['domain_name']]))
  59              {
  60                  $domains_created[$row['domain_name']] = true;
  61                  //$sql_data = "DROP DOMAIN {$row['domain_name']};\n";
  62                  $sql_data = "CREATE DOMAIN {$row['domain_name']} as {$row['data_type']}";
  63                  if (!empty($row['character_maximum_length']))
  64                  {
  65                      $sql_data .= '(' . $row['character_maximum_length'] . ')';
  66                  }
  67                  $sql_data .= ' NOT NULL';
  68                  if (!empty($row['domain_default']))
  69                  {
  70                      $sql_data .= ' DEFAULT ' . $row['domain_default'];
  71                  }
  72                  $this->flush($sql_data . ";\n");
  73              }
  74          }
  75          $this->db->sql_freeresult($result);
  76  
  77          $sql_data = '-- Table: ' . $table_name . "\n";
  78          $sql_data .= "DROP TABLE $table_name;\n";
  79          // PGSQL does not "tightly" bind sequences and tables, we must guess...
  80          $sql = "SELECT relname
  81              FROM pg_class
  82              WHERE relkind = 'S'
  83                  AND relname = '{$table_name}_seq'";
  84          $result = $this->db->sql_query($sql);
  85          // We don't even care about storing the results. We already know the answer if we get rows back.
  86          if ($this->db->sql_fetchrow($result))
  87          {
  88              $sql_data .= "DROP SEQUENCE IF EXISTS {$table_name}_seq;\n";
  89              $sql_data .= "CREATE SEQUENCE {$table_name}_seq;\n";
  90          }
  91          $this->db->sql_freeresult($result);
  92  
  93          $field_query = "SELECT a.attnum, a.attname as field, t.typname as type, a.attlen as length, a.atttypmod as lengthvar, a.attnotnull as notnull
  94              FROM pg_class c, pg_attribute a, pg_type t
  95              WHERE c.relname = '" . $this->db->sql_escape($table_name) . "'
  96                  AND a.attnum > 0
  97                  AND a.attrelid = c.oid
  98                  AND a.atttypid = t.oid
  99              ORDER BY a.attnum";
 100          $result = $this->db->sql_query($field_query);
 101  
 102          $sql_data .= "CREATE TABLE $table_name(\n";
 103          $lines = array();
 104          while ($row = $this->db->sql_fetchrow($result))
 105          {
 106              // Get the data from the table
 107              $sql_get_default = "SELECT pg_get_expr(d.adbin, d.adrelid) as rowdefault
 108                  FROM pg_attrdef d, pg_class c
 109                  WHERE (c.relname = '" . $this->db->sql_escape($table_name) . "')
 110                      AND (c.oid = d.adrelid)
 111                      AND d.adnum = " . $row['attnum'];
 112              $def_res = $this->db->sql_query($sql_get_default);
 113              $def_row = $this->db->sql_fetchrow($def_res);
 114              $this->db->sql_freeresult($def_res);
 115  
 116              if (empty($def_row))
 117              {
 118                  unset($row['rowdefault']);
 119              }
 120              else
 121              {
 122                  $row['rowdefault'] = $def_row['rowdefault'];
 123              }
 124  
 125              if ($row['type'] == 'bpchar')
 126              {
 127                  // Internally stored as bpchar, but isn't accepted in a CREATE TABLE statement.
 128                  $row['type'] = 'char';
 129              }
 130  
 131              $line = '  ' . $row['field'] . ' ' . $row['type'];
 132  
 133              if (strpos($row['type'], 'char') !== false)
 134              {
 135                  if ($row['lengthvar'] > 0)
 136                  {
 137                      $line .= '(' . ($row['lengthvar'] - 4) . ')';
 138                  }
 139              }
 140  
 141              if (strpos($row['type'], 'numeric') !== false)
 142              {
 143                  $line .= '(';
 144                  $line .= sprintf("%s,%s", (($row['lengthvar'] >> 16) & 0xffff), (($row['lengthvar'] - 4) & 0xffff));
 145                  $line .= ')';
 146              }
 147  
 148              if (isset($row['rowdefault']))
 149              {
 150                  $line .= ' DEFAULT ' . $row['rowdefault'];
 151              }
 152  
 153              if ($row['notnull'] == 't')
 154              {
 155                  $line .= ' NOT NULL';
 156              }
 157  
 158              $lines[] = $line;
 159          }
 160          $this->db->sql_freeresult($result);
 161  
 162          // Get the listing of primary keys.
 163          $sql_pri_keys = "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
 164              FROM pg_class bc, pg_class ic, pg_index i, pg_attribute ta, pg_attribute ia
 165              WHERE (bc.oid = i.indrelid)
 166                  AND (ic.oid = i.indexrelid)
 167                  AND (ia.attrelid = i.indexrelid)
 168                  AND    (ta.attrelid = bc.oid)
 169                  AND (bc.relname = '" . $this->db->sql_escape($table_name) . "')
 170                  AND (ta.attrelid = i.indrelid)
 171                  AND (ta.attnum = i.indkey[ia.attnum-1])
 172              ORDER BY index_name, tab_name, column_name";
 173  
 174          $result = $this->db->sql_query($sql_pri_keys);
 175  
 176          $index_create = $index_rows = $primary_key = array();
 177  
 178          // We do this in two steps. It makes placing the comma easier
 179          while ($row = $this->db->sql_fetchrow($result))
 180          {
 181              if ($row['primary_key'] == 't')
 182              {
 183                  $primary_key[] = $row['column_name'];
 184                  $primary_key_name = $row['index_name'];
 185              }
 186              else
 187              {
 188                  // We have to store this all this info because it is possible to have a multi-column key...
 189                  // we can loop through it again and build the statement
 190                  $index_rows[$row['index_name']]['table'] = $table_name;
 191                  $index_rows[$row['index_name']]['unique'] = ($row['unique_key'] == 't') ? true : false;
 192                  $index_rows[$row['index_name']]['column_names'][] = $row['column_name'];
 193              }
 194          }
 195          $this->db->sql_freeresult($result);
 196  
 197          if (!empty($index_rows))
 198          {
 199              foreach ($index_rows as $idx_name => $props)
 200              {
 201                  $index_create[] = 'CREATE ' . ($props['unique'] ? 'UNIQUE ' : '') . "INDEX $idx_name ON $table_name (" . implode(', ', $props['column_names']) . ");";
 202              }
 203          }
 204  
 205          if (!empty($primary_key))
 206          {
 207              $lines[] = "  CONSTRAINT $primary_key_name PRIMARY KEY (" . implode(', ', $primary_key) . ")";
 208          }
 209  
 210          // Generate constraint clauses for CHECK constraints
 211          $sql_checks = "SELECT pc.conname AS index_name, pg_get_expr(pc.conbin, pc.conrelid) AS constraint_expr
 212              FROM pg_constraint pc, pg_class bc
 213              WHERE pc.conrelid = bc.oid
 214                  AND bc.relname = '" . $this->db->sql_escape($table_name) . "'
 215                  AND NOT EXISTS (
 216                      SELECT *
 217                      FROM pg_constraint AS c, pg_inherits AS i
 218                          WHERE i.inhrelid = pc.conrelid
 219                              AND c.conname = pc.conname
 220                              AND pg_get_constraintdef(c.oid) = pg_get_constraintdef(pc.oid)
 221                              AND c.conrelid = i.inhparent
 222                  )";
 223          $result = $this->db->sql_query($sql_checks);
 224  
 225          // Add the constraints to the sql file.
 226          while ($row = $this->db->sql_fetchrow($result))
 227          {
 228              if (!empty($row['constraint_expr']))
 229              {
 230                  $lines[] = '  CONSTRAINT ' . $row['index_name'] . ' CHECK ' . $row['constraint_expr'];
 231              }
 232          }
 233          $this->db->sql_freeresult($result);
 234  
 235          $sql_data .= implode(", \n", $lines);
 236          $sql_data .= "\n);\n";
 237  
 238          if (!empty($index_create))
 239          {
 240              $sql_data .= implode("\n", $index_create) . "\n\n";
 241          }
 242          $this->flush($sql_data);
 243      }
 244  
 245      /**
 246      * {@inheritdoc}
 247      */
 248  	public function write_data($table_name)
 249      {
 250          if (!$this->is_initialized)
 251          {
 252              throw new extractor_not_initialized_exception();
 253          }
 254  
 255          // Grab all of the data from current table.
 256          $sql = "SELECT *
 257              FROM $table_name";
 258          $result = $this->db->sql_query($sql);
 259  
 260          $i_num_fields = pg_num_fields($result);
 261          $seq = '';
 262  
 263          for ($i = 0; $i < $i_num_fields; $i++)
 264          {
 265              $ary_type[] = pg_field_type($result, $i);
 266              $ary_name[] = pg_field_name($result, $i);
 267  
 268              $sql = "SELECT pg_get_expr(d.adbin, d.adrelid) as rowdefault
 269                  FROM pg_attrdef d, pg_class c
 270                  WHERE (c.relname = '{$table_name}')
 271                      AND (c.oid = d.adrelid)
 272                      AND d.adnum = " . strval($i + 1);
 273              $result2 = $this->db->sql_query($sql);
 274              if ($row = $this->db->sql_fetchrow($result2))
 275              {
 276                  // Determine if we must reset the sequences
 277                  if (strpos($row['rowdefault'], "nextval('") === 0)
 278                  {
 279                      $seq .= "SELECT SETVAL('{$table_name}_seq',(select case when max({$ary_name[$i]})>0 then max({$ary_name[$i]})+1 else 1 end FROM {$table_name}));\n";
 280                  }
 281              }
 282          }
 283  
 284          $this->flush("COPY $table_name (" . implode(', ', $ary_name) . ') FROM stdin;' . "\n");
 285          while ($row = $this->db->sql_fetchrow($result))
 286          {
 287              $schema_vals = array();
 288  
 289              // Build the SQL statement to recreate the data.
 290              for ($i = 0; $i < $i_num_fields; $i++)
 291              {
 292                  $str_val = $row[$ary_name[$i]];
 293  
 294                  if (preg_match('#char|text|bool|bytea#i', $ary_type[$i]))
 295                  {
 296                      $str_val = str_replace(array("\n", "\t", "\r", "\b", "\f", "\v"), array('\n', '\t', '\r', '\b', '\f', '\v'), addslashes($str_val));
 297                      $str_empty = '';
 298                  }
 299                  else
 300                  {
 301                      $str_empty = '\N';
 302                  }
 303  
 304                  if (empty($str_val) && $str_val !== '0')
 305                  {
 306                      $str_val = $str_empty;
 307                  }
 308  
 309                  $schema_vals[] = $str_val;
 310              }
 311  
 312              // Take the ordered fields and their associated data and build it
 313              // into a valid sql statement to recreate that field in the data.
 314              $this->flush(implode("\t", $schema_vals) . "\n");
 315          }
 316          $this->db->sql_freeresult($result);
 317          $this->flush("\\.\n");
 318  
 319          // Write out the sequence statements
 320          $this->flush($seq);
 321      }
 322  
 323      /**
 324      * Writes closing line(s) to database backup
 325      *
 326      * @return null
 327      * @throws extractor_not_initialized_exception when calling this function before init_extractor()
 328      */
 329  	public function write_end()
 330      {
 331          if (!$this->is_initialized)
 332          {
 333              throw new extractor_not_initialized_exception();
 334          }
 335  
 336          $this->flush("COMMIT;\n");
 337          parent::write_end();
 338      }
 339  }


Generated: Mon Nov 25 19:05:08 2024 Cross-referenced by PHPXref 0.7.1