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_extractor.php

Zuletzt modifiziert: 09.10.2024, 12:54 - Dateigröße: 9.54 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\extractor;
015   
016  use phpbb\db\extractor\exception\extractor_not_initialized_exception;
017   
018  class postgres_extractor extends base_extractor
019  {
020      /**
021      * {@inheritdoc}
022      */
023      public function write_start($table_prefix)
024      {
025          if (!$this->is_initialized)
026          {
027              throw new extractor_not_initialized_exception();
028          }
029   
030          $sql_data = "--\n";
031          $sql_data .= "-- phpBB Backup Script\n";
032          $sql_data .= "-- Dump of tables for $table_prefix\n";
033          $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
034          $sql_data .= "--\n";
035          $sql_data .= "BEGIN TRANSACTION;\n";
036          $this->flush($sql_data);
037      }
038   
039      /**
040      * {@inheritdoc}
041      */
042      public function write_table($table_name)
043      {
044          static $domains_created = array();
045   
046          if (!$this->is_initialized)
047          {
048              throw new extractor_not_initialized_exception();
049          }
050   
051          $sql = "SELECT a.domain_name, a.data_type, a.character_maximum_length, a.domain_default
052              FROM INFORMATION_SCHEMA.domains a, INFORMATION_SCHEMA.column_domain_usage b
053              WHERE a.domain_name = b.domain_name
054                  AND b.table_name = '{$table_name}'";
055          $result = $this->db->sql_query($sql);
056          while ($row = $this->db->sql_fetchrow($result))
057          {
058              if (empty($domains_created[$row['domain_name']]))
059              {
060                  $domains_created[$row['domain_name']] = true;
061                  //$sql_data = "DROP DOMAIN {$row['domain_name']};\n";
062                  $sql_data = "CREATE DOMAIN {$row['domain_name']} as {$row['data_type']}";
063                  if (!empty($row['character_maximum_length']))
064                  {
065                      $sql_data .= '(' . $row['character_maximum_length'] . ')';
066                  }
067                  $sql_data .= ' NOT NULL';
068                  if (!empty($row['domain_default']))
069                  {
070                      $sql_data .= ' DEFAULT ' . $row['domain_default'];
071                  }
072                  $this->flush($sql_data . ";\n");
073              }
074          }
075          $this->db->sql_freeresult($result);
076   
077          $sql_data = '-- Table: ' . $table_name . "\n";
078          $sql_data .= "DROP TABLE $table_name;\n";
079          // PGSQL does not "tightly" bind sequences and tables, we must guess...
080          $sql = "SELECT relname
081              FROM pg_class
082              WHERE relkind = 'S'
083                  AND relname = '{$table_name}_seq'";
084          $result = $this->db->sql_query($sql);
085          // We don't even care about storing the results. We already know the answer if we get rows back.
086          if ($this->db->sql_fetchrow($result))
087          {
088              $sql_data .= "DROP SEQUENCE {$table_name}_seq;\n";
089              $sql_data .= "CREATE SEQUENCE {$table_name}_seq;\n";
090          }
091          $this->db->sql_freeresult($result);
092   
093          $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
094              FROM pg_class c, pg_attribute a, pg_type t
095              WHERE c.relname = '" . $this->db->sql_escape($table_name) . "'
096                  AND a.attnum > 0
097                  AND a.attrelid = c.oid
098                  AND a.atttypid = t.oid
099              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 conname as index_name, consrc
212              FROM pg_constraint, pg_class bc
213              WHERE 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 = pg_constraint.conrelid
219                              AND c.conname = pg_constraint.conname
220                              AND c.consrc = pg_constraint.consrc
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 (!is_null($row['consrc']))
229              {
230                  $lines[] = '  CONSTRAINT ' . $row['index_name'] . ' CHECK ' . $row['consrc'];
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 \phpbb\db\extractor\exception\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  }
340