$config to phpbb::$config
[phpbb.git] / phpBB / modules / acp / acp_database.php
blob14e38bc6978ac0cca713ba1f193d5c996275cab8
1 <?php
2 /**
4 * @package acp
5 * @version $Id$
6 * @copyright (c) 2005 phpBB Group
7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
9 */
11 /**
12 * @ignore
14 if (!defined('IN_PHPBB'))
16 exit;
19 /**
20 * @package acp
22 class acp_database
24 var $u_action;
26 function main($id, $mode)
28 global $db, $user, $auth, $template, $table_prefix;
30 $user->add_lang('acp/database');
32 $this->tpl_name = 'acp_database';
33 $this->page_title = 'ACP_DATABASE';
35 $action = request_var('action', '');
36 $submit = phpbb_request::is_set_post('submit');
38 $template->assign_vars(array(
39 'MODE' => $mode
40 ));
42 switch ($mode)
44 case 'backup':
46 $this->page_title = 'ACP_BACKUP';
48 switch ($action)
50 case 'download':
51 $type = request_var('type', '');
52 $table = request_var('table', array(''));
53 $format = request_var('method', '');
54 $where = request_var('where', '');
56 if (!sizeof($table))
58 trigger_error($user->lang['TABLE_SELECT_ERROR'] . adm_back_link($this->u_action), E_USER_WARNING);
61 $store = $download = $structure = $schema_data = false;
63 if ($where == 'store_and_download' || $where == 'store')
65 $store = true;
68 if ($where == 'store_and_download' || $where == 'download')
70 $download = true;
73 if ($type == 'full' || $type == 'structure')
75 $structure = true;
78 if ($type == 'full' || $type == 'data')
80 $schema_data = true;
83 @set_time_limit(1200);
85 $time = time();
87 $filename = 'backup_' . $time . '_' . unique_id();
88 switch ($db->dbms_type)
90 case 'mysql':
91 $extractor = new mysql_extractor($download, $store, $format, $filename, $time);
92 break;
94 case 'sqlite':
95 $extractor = new sqlite_extractor($download, $store, $format, $filename, $time);
96 break;
98 case 'postgres':
99 $extractor = new postgres_extractor($download, $store, $format, $filename, $time);
100 break;
102 case 'oracle':
103 $extractor = new oracle_extractor($download, $store, $format, $filename, $time);
104 break;
106 case 'mssql':
107 $extractor = new mssql_extractor($download, $store, $format, $filename, $time);
108 break;
110 case 'firebird':
111 $extractor = new firebird_extractor($download, $store, $format, $filename, $time);
112 break;
114 case 'db2':
115 $extractor = new db2_extractor($download, $store, $format, $filename, $time);
116 break;
119 $extractor->write_start($table_prefix);
121 foreach ($table as $table_name)
123 // Get the table structure
124 if ($structure)
126 $extractor->write_table($table_name);
128 else
130 // We might wanna empty out all that junk :D
131 switch ($db->dbms_type)
133 case 'sqlite':
134 case 'firebird':
135 case 'db2':
136 $extractor->flush('DELETE FROM ' . $table_name . ";\n");
137 break;
139 case 'mssql':
140 $extractor->flush('TRUNCATE TABLE ' . $table_name . "GO\n");
141 break;
143 case 'oracle':
144 $extractor->flush('TRUNCATE TABLE ' . $table_name . "\\\n");
145 break;
147 default:
148 $extractor->flush('TRUNCATE TABLE ' . $table_name . ";\n");
149 break;
153 // Data
154 if ($schema_data)
156 $extractor->write_data($table_name);
160 $extractor->write_end();
162 add_log('admin', 'LOG_DB_BACKUP');
164 if ($download == true)
166 exit;
169 trigger_error($user->lang['BACKUP_SUCCESS'] . adm_back_link($this->u_action));
170 break;
172 default:
173 include(PHPBB_ROOT_PATH . 'includes/functions_install.' . PHP_EXT);
174 $tables = get_tables($db);
175 asort($tables);
176 foreach ($tables as $table_name)
178 if (strlen($table_prefix) === 0 || stripos($table_name, $table_prefix) === 0)
180 $template->assign_block_vars('tables', array(
181 'TABLE' => $table_name
185 unset($tables);
187 $template->assign_vars(array(
188 'U_ACTION' => $this->u_action . '&amp;action=download'
191 $available_methods = array('gzip' => 'zlib', 'bzip2' => 'bz2');
193 foreach ($available_methods as $type => $module)
195 if (!@extension_loaded($module))
197 continue;
200 $template->assign_block_vars('methods', array(
201 'TYPE' => $type
205 $template->assign_block_vars('methods', array(
206 'TYPE' => 'text'
208 break;
210 break;
212 case 'restore':
214 $this->page_title = 'ACP_RESTORE';
216 switch ($action)
218 case 'submit':
219 $delete = request_var('delete', '');
220 $file = request_var('file', '');
222 if (!preg_match('#^backup_\d{10,}_[a-z\d]{16}\.(sql(?:\.(?:gz|bz2))?)$#', $file, $matches))
224 trigger_error($user->lang['BACKUP_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
227 $file_name = PHPBB_ROOT_PATH . 'store/' . $matches[0];
229 if (!file_exists($file_name) || !is_readable($file_name))
231 trigger_error($user->lang['BACKUP_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
234 if ($delete)
236 if (confirm_box(true))
238 unlink($file_name);
239 add_log('admin', 'LOG_DB_DELETE');
240 trigger_error($user->lang['BACKUP_DELETE'] . adm_back_link($this->u_action));
242 else
244 confirm_box(false, $user->lang['DELETE_SELECTED_BACKUP'], build_hidden_fields(array('delete' => $delete, 'file' => $file)));
247 else
249 $download = request_var('download', '');
251 if ($download)
253 $name = $matches[0];
255 switch ($matches[1])
257 case 'sql':
258 $mimetype = 'text/x-sql';
259 break;
260 case 'sql.bz2':
261 $mimetype = 'application/x-bzip2';
262 break;
263 case 'sql.gz':
264 $mimetype = 'application/x-gzip';
265 break;
268 header('Pragma: no-cache');
269 header("Content-Type: $mimetype; name=\"$name\"");
270 header("Content-disposition: attachment; filename=$name");
272 @set_time_limit(0);
274 $fp = @fopen($file_name, 'rb');
276 if ($fp !== false)
278 while (!feof($fp))
280 echo fread($fp, 8192);
282 fclose($fp);
285 flush();
286 exit;
289 switch ($matches[1])
291 case 'sql':
292 $fp = fopen($file_name, 'rb');
293 $read = 'fread';
294 $seek = 'fseek';
295 $eof = 'feof';
296 $close = 'fclose';
297 $fgetd = 'fgetd';
298 break;
300 case 'sql.bz2':
301 $fp = bzopen($file_name, 'r');
302 $read = 'bzread';
303 $seek = '';
304 $eof = 'feof';
305 $close = 'bzclose';
306 $fgetd = 'fgetd_seekless';
307 break;
309 case 'sql.gz':
310 $fp = gzopen($file_name, 'rb');
311 $read = 'gzread';
312 $seek = 'gzseek';
313 $eof = 'gzeof';
314 $close = 'gzclose';
315 $fgetd = 'fgetd';
316 break;
319 switch ($db->dbms_type)
321 case 'mysql':
322 case 'sqlite':
323 case 'db2':
324 while (($sql = $fgetd($fp, ";\n", $read, $seek, $eof)) !== false)
326 $db->sql_query($sql);
328 break;
330 case 'firebird':
331 $delim = ";\n";
332 while (($sql = $fgetd($fp, $delim, $read, $seek, $eof)) !== false)
334 $query = trim($sql);
335 if (substr($query, 0, 8) === 'SET TERM')
337 $delim = $query[9] . "\n";
338 continue;
340 $db->sql_query($query);
342 break;
344 case 'postgres':
345 $delim = ";\n";
346 while (($sql = $fgetd($fp, $delim, $read, $seek, $eof)) !== false)
348 $query = trim($sql);
350 if (substr($query, 0, 13) == 'CREATE DOMAIN')
352 list(, , $domain) = explode(' ', $query);
353 $sql = "SELECT domain_name
354 FROM information_schema.domains
355 WHERE domain_name = '$domain';";
356 $result = $db->sql_query($sql);
357 if (!$db->sql_fetchrow($result))
359 $db->sql_query($query);
361 $db->sql_freeresult($result);
363 else
365 $db->sql_query($query);
368 if (substr($query, 0, 4) == 'COPY')
370 while (($sub = $fgetd($fp, "\n", $read, $seek, $eof)) !== '\.')
372 if ($sub === false)
374 trigger_error($user->lang['RESTORE_FAILURE'] . adm_back_link($this->u_action), E_USER_WARNING);
376 pg_put_line($db->db_connect_id, $sub . "\n");
378 pg_put_line($db->db_connect_id, "\\.\n");
379 pg_end_copy($db->db_connect_id);
382 break;
384 case 'oracle':
385 while (($sql = $fgetd($fp, "/\n", $read, $seek, $eof)) !== false)
387 $db->sql_query($sql);
389 break;
391 case 'mssql':
392 while (($sql = $fgetd($fp, "GO\n", $read, $seek, $eof)) !== false)
394 $db->sql_query($sql);
396 break;
399 $close($fp);
401 // Purge the cache due to updated data
402 phpbb::$acm->purge();
404 add_log('admin', 'LOG_DB_RESTORE');
405 trigger_error($user->lang['RESTORE_SUCCESS'] . adm_back_link($this->u_action));
406 break;
409 default:
410 $methods = array('sql');
411 $available_methods = array('sql.gz' => 'zlib', 'sql.bz2' => 'bz2');
413 foreach ($available_methods as $type => $module)
415 if (!@extension_loaded($module))
417 continue;
419 $methods[] = $type;
422 $dir = PHPBB_ROOT_PATH . 'store/';
423 $dh = @opendir($dir);
425 if ($dh)
427 while (($file = readdir($dh)) !== false)
429 if (preg_match('#^backup_(\d{10,})_[a-z\d]{16}\.(sql(?:\.(?:gz|bz2))?)$#', $file, $matches))
431 $supported = in_array($matches[2], $methods);
433 if ($supported == 'true')
435 $template->assign_block_vars('files', array(
436 'FILE' => $file,
437 'NAME' => gmdate("d-m-Y H:i:s", $matches[1]),
438 'SUPPORTED' => $supported
443 closedir($dh);
446 $template->assign_vars(array(
447 'U_ACTION' => $this->u_action . '&amp;action=submit'
449 break;
451 break;
457 * @package acp
459 class base_extractor
461 var $fh;
462 var $fp;
463 var $write;
464 var $close;
465 var $store;
466 var $download;
467 var $time;
468 var $format;
469 var $run_comp = false;
471 function __construct($download = false, $store = false, $format, $filename, $time)
473 $this->download = $download;
474 $this->store = $store;
475 $this->time = $time;
476 $this->format = $format;
478 switch ($format)
480 case 'text':
481 $ext = '.sql';
482 $open = 'fopen';
483 $this->write = 'fwrite';
484 $this->close = 'fclose';
485 $mimetype = 'text/x-sql';
486 break;
487 case 'bzip2':
488 $ext = '.sql.bz2';
489 $open = 'bzopen';
490 $this->write = 'bzwrite';
491 $this->close = 'bzclose';
492 $mimetype = 'application/x-bzip2';
493 break;
494 case 'gzip':
495 $ext = '.sql.gz';
496 $open = 'gzopen';
497 $this->write = 'gzwrite';
498 $this->close = 'gzclose';
499 $mimetype = 'application/x-gzip';
500 break;
503 if ($download == true)
505 $name = $filename . $ext;
506 header('Pragma: no-cache');
507 header("Content-Type: $mimetype; name=\"$name\"");
508 header("Content-disposition: attachment; filename=$name");
510 switch ($format)
512 case 'bzip2':
513 ob_start();
514 break;
516 case 'gzip':
517 if ((isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false) && strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'msie') === false)
519 ob_start('ob_gzhandler');
521 else
523 $this->run_comp = true;
525 break;
529 if ($store == true)
531 $file = PHPBB_ROOT_PATH . 'store/' . $filename . $ext;
533 $this->fp = $open($file, 'w');
535 if (!$this->fp)
537 trigger_error('Unable to write temporary file to storage folder', E_USER_ERROR);
542 function write_end()
544 static $close;
545 if ($this->store)
547 if ($close === null)
549 $close = $this->close;
551 $close($this->fp);
554 // bzip2 must be written all the way at the end
555 if ($this->download && $this->format === 'bzip2')
557 $c = ob_get_clean();
558 echo bzcompress($c);
562 function flush($data)
564 static $write;
565 if ($this->store === true)
567 if ($write === null)
569 $write = $this->write;
571 $write($this->fp, $data);
574 if ($this->download === true)
576 if ($this->format === 'bzip2' || $this->format === 'text' || ($this->format === 'gzip' && !$this->run_comp))
578 echo $data;
581 // we can write the gzip data as soon as we get it
582 if ($this->format === 'gzip')
584 if ($this->run_comp)
586 echo gzencode($data);
588 else
590 ob_flush();
591 flush();
599 * @package acp
601 class mysql_extractor extends base_extractor
603 function write_start($table_prefix)
605 $sql_data = "#\n";
606 $sql_data .= "# phpBB Backup Script\n";
607 $sql_data .= "# Dump of tables for $table_prefix\n";
608 $sql_data .= "# DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
609 $sql_data .= "#\n";
610 $this->flush($sql_data);
613 function write_table($table_name)
615 global $db;
617 $sql = 'SHOW CREATE TABLE ' . $table_name;
618 $result = $db->sql_query($sql);
619 $row = $db->sql_fetchrow($result);
621 $sql_data = '# Table: ' . $table_name . "\n";
622 $sql_data .= "DROP TABLE IF EXISTS $table_name;\n";
623 $this->flush($sql_data . $row['Create Table'] . ";\n\n");
625 $db->sql_freeresult($result);
628 function write_data($table_name)
630 global $db;
631 if ($db->sql_layer === 'mysqli')
633 $this->write_data_mysqli($table_name);
635 else
637 $this->write_data_mysql($table_name);
641 function write_data_mysqli($table_name)
643 global $db;
644 $sql = "SELECT *
645 FROM $table_name";
646 $result = mysqli_query($db->db_connect_id, $sql, MYSQLI_USE_RESULT);
647 if ($result != false)
649 $fields_cnt = mysqli_num_fields($result);
651 // Get field information
652 $field = mysqli_fetch_fields($result);
653 $field_set = array();
655 for ($j = 0; $j < $fields_cnt; $j++)
657 $field_set[] = $field[$j]->name;
660 $search = array("\\", "'", "\x00", "\x0a", "\x0d", "\x1a", '"');
661 $replace = array("\\\\", "\\'", '\0', '\n', '\r', '\Z', '\\"');
662 $fields = implode(', ', $field_set);
663 $sql_data = 'INSERT INTO ' . $table_name . ' (' . $fields . ') VALUES ';
664 $first_set = true;
665 $query_len = 0;
666 $max_len = get_usable_memory();
668 while ($row = mysqli_fetch_row($result))
670 $values = array();
671 if ($first_set)
673 $query = $sql_data . '(';
675 else
677 $query .= ',(';
680 for ($j = 0; $j < $fields_cnt; $j++)
682 if (!isset($row[$j]) || is_null($row[$j]))
684 $values[$j] = 'NULL';
686 else if (($field[$j]->flags & 32768) && !($field[$j]->flags & 1024))
688 $values[$j] = $row[$j];
690 else
692 $values[$j] = "'" . str_replace($search, $replace, $row[$j]) . "'";
695 $query .= implode(', ', $values) . ')';
697 $query_len += strlen($query);
698 if ($query_len > $max_len)
700 $this->flush($query . ";\n\n");
701 $query = '';
702 $query_len = 0;
703 $first_set = true;
705 else
707 $first_set = false;
710 mysqli_free_result($result);
712 // check to make sure we have nothing left to flush
713 if (!$first_set && $query)
715 $this->flush($query . ";\n\n");
720 function write_data_mysql($table_name)
722 global $db;
723 $sql = "SELECT *
724 FROM $table_name";
725 $result = mysql_unbuffered_query($sql, $db->db_connect_id);
727 if ($result != false)
729 $fields_cnt = mysql_num_fields($result);
731 // Get field information
732 $field = array();
733 for ($i = 0; $i < $fields_cnt; $i++)
735 $field[] = mysql_fetch_field($result, $i);
737 $field_set = array();
739 for ($j = 0; $j < $fields_cnt; $j++)
741 $field_set[] = $field[$j]->name;
744 $search = array("\\", "'", "\x00", "\x0a", "\x0d", "\x1a", '"');
745 $replace = array("\\\\", "\\'", '\0', '\n', '\r', '\Z', '\\"');
746 $fields = implode(', ', $field_set);
747 $sql_data = 'INSERT INTO ' . $table_name . ' (' . $fields . ') VALUES ';
748 $first_set = true;
749 $query_len = 0;
750 $max_len = get_usable_memory();
752 while ($row = mysql_fetch_row($result))
754 $values = array();
755 if ($first_set)
757 $query = $sql_data . '(';
759 else
761 $query .= ',(';
764 for ($j = 0; $j < $fields_cnt; $j++)
766 if (!isset($row[$j]) || is_null($row[$j]))
768 $values[$j] = 'NULL';
770 else if ($field[$j]->numeric && ($field[$j]->type !== 'timestamp'))
772 $values[$j] = $row[$j];
774 else
776 $values[$j] = "'" . str_replace($search, $replace, $row[$j]) . "'";
779 $query .= implode(', ', $values) . ')';
781 $query_len += strlen($query);
782 if ($query_len > $max_len)
784 $this->flush($query . ";\n\n");
785 $query = '';
786 $query_len = 0;
787 $first_set = true;
789 else
791 $first_set = false;
794 mysql_free_result($result);
796 // check to make sure we have nothing left to flush
797 if (!$first_set && $query)
799 $this->flush($query . ";\n\n");
806 * @package acp
808 class sqlite_extractor extends base_extractor
810 function write_start($prefix)
812 $sql_data = "--\n";
813 $sql_data .= "-- phpBB Backup Script\n";
814 $sql_data .= "-- Dump of tables for $prefix\n";
815 $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
816 $sql_data .= "--\n";
817 $sql_data .= "BEGIN TRANSACTION;\n";
818 $this->flush($sql_data);
821 function write_table($table_name)
823 global $db;
824 $sql_data = '-- Table: ' . $table_name . "\n";
825 $sql_data .= "DROP TABLE $table_name;\n";
827 $sql = "SELECT sql
828 FROM sqlite_master
829 WHERE type = 'table'
830 AND name = '" . $db->sql_escape($table_name) . "'
831 ORDER BY type DESC, name;";
832 $result = $db->sql_query($sql);
833 $row = $db->sql_fetchrow($result);
834 $db->sql_freeresult($result);
836 // Create Table
837 $sql_data .= $row['sql'] . ";\n";
839 $result = $db->sql_query("PRAGMA index_list('" . $db->sql_escape($table_name) . "');");
841 $ar = array();
842 while ($row = $db->sql_fetchrow($result))
844 $ar[] = $row;
846 $db->sql_freeresult($result);
848 foreach ($ar as $value)
850 if (strpos($value['name'], 'autoindex') !== false)
852 continue;
855 $result = $db->sql_query("PRAGMA index_info('" . $db->sql_escape($value['name']) . "');");
857 $fields = array();
858 while ($row = $db->sql_fetchrow($result))
860 $fields[] = $row['name'];
862 $db->sql_freeresult($result);
864 $sql_data .= 'CREATE ' . ($value['unique'] ? 'UNIQUE ' : '') . 'INDEX ' . $value['name'] . ' on ' . $table_name . ' (' . implode(', ', $fields) . ");\n";
867 $this->flush($sql_data . "\n");
870 function write_data($table_name)
872 global $db;
873 static $proper;
875 if (is_null($proper))
877 $proper = version_compare(PHP_VERSION, '5.1.3', '>=');
880 if ($proper)
882 $col_types = sqlite_fetch_column_types($db->db_connect_id, $table_name);
884 else
886 $sql = "SELECT sql
887 FROM sqlite_master
888 WHERE type = 'table'
889 AND name = '" . $table_name . "'";
890 $table_data = sqlite_single_query($db->db_connect_id, $sql);
891 $table_data = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', '', $table_data);
892 $table_data = trim($table_data);
894 preg_match('#\((.*)\)#s', $table_data, $matches);
896 $table_cols = explode(',', trim($matches[1]));
897 foreach ($table_cols as $declaration)
899 $entities = preg_split('#\s+#', trim($declaration));
900 $column_name = preg_replace('/"?([^"]+)"?/', '\1', $entities[0]);
902 // Hit a primary key, those are not what we need :D
903 if (empty($entities[1]) || (strtolower($entities[0]) === 'primary' && strtolower($entities[1]) === 'key'))
905 continue;
907 $col_types[$column_name] = $entities[1];
911 $sql = "SELECT *
912 FROM $table_name";
913 $result = sqlite_unbuffered_query($db->db_connect_id, $sql);
914 $rows = sqlite_fetch_all($result, SQLITE_ASSOC);
915 $sql_insert = 'INSERT INTO ' . $table_name . ' (' . implode(', ', array_keys($col_types)) . ') VALUES (';
916 foreach ($rows as $row)
918 foreach ($row as $column_name => $column_data)
920 if (is_null($column_data))
922 $row[$column_name] = 'NULL';
924 else if ($column_data == '')
926 $row[$column_name] = "''";
928 else if (strpos($col_types[$column_name], 'text') !== false || strpos($col_types[$column_name], 'char') !== false || strpos($col_types[$column_name], 'blob') !== false)
930 $row[$column_name] = sanitize_data_generic(str_replace("'", "''", $column_data));
933 $this->flush($sql_insert . implode(', ', $row) . ");\n");
937 function write_end()
939 $this->flush("COMMIT;\n");
940 parent::write_end();
945 * @package acp
947 class postgres_extractor extends base_extractor
949 function write_start($prefix)
951 $sql_data = "--\n";
952 $sql_data .= "-- phpBB Backup Script\n";
953 $sql_data .= "-- Dump of tables for $prefix\n";
954 $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
955 $sql_data .= "--\n";
956 $sql_data .= "BEGIN TRANSACTION;\n";
957 $this->flush($sql_data);
960 function write_table($table_name)
962 global $db;
963 static $domains_created = array();
965 $sql = "SELECT a.domain_name, a.data_type, a.character_maximum_length, a.domain_default
966 FROM INFORMATION_SCHEMA.domains a, INFORMATION_SCHEMA.column_domain_usage b
967 WHERE a.domain_name = b.domain_name
968 AND b.table_name = '{$table_name}'";
969 $result = $db->sql_query($sql);
970 while ($row = $db->sql_fetchrow($result))
972 if (empty($domains_created[$row['domain_name']]))
974 $domains_created[$row['domain_name']] = true;
975 //$sql_data = "DROP DOMAIN {$row['domain_name']};\n";
976 $sql_data = "CREATE DOMAIN {$row['domain_name']} as {$row['data_type']}";
977 if (!empty($row['character_maximum_length']))
979 $sql_data .= '(' . $row['character_maximum_length'] . ')';
981 $sql_data .= ' NOT NULL';
982 if (!empty($row['domain_default']))
984 $sql_data .= ' DEFAULT ' . $row['domain_default'];
986 $this->flush($sql_data . ";\n");
990 $sql_data = '-- Table: ' . $table_name . "\n";
991 $sql_data .= "DROP TABLE $table_name;\n";
992 // PGSQL does not "tightly" bind sequences and tables, we must guess...
993 $sql = "SELECT relname
994 FROM pg_class
995 WHERE relkind = 'S'
996 AND relname = '{$table_name}_seq'";
997 $result = $db->sql_query($sql);
998 // We don't even care about storing the results. We already know the answer if we get rows back.
999 if ($db->sql_fetchrow($result))
1001 $sql_data .= "DROP SEQUENCE {$table_name}_seq;\n";
1002 $sql_data .= "CREATE SEQUENCE {$table_name}_seq;\n";
1004 $db->sql_freeresult($result);
1006 $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
1007 FROM pg_class c, pg_attribute a, pg_type t
1008 WHERE c.relname = '" . $db->sql_escape($table_name) . "'
1009 AND a.attnum > 0
1010 AND a.attrelid = c.oid
1011 AND a.atttypid = t.oid
1012 ORDER BY a.attnum";
1013 $result = $db->sql_query($field_query);
1015 $sql_data .= "CREATE TABLE $table_name(\n";
1016 $lines = array();
1017 while ($row = $db->sql_fetchrow($result))
1019 // Get the data from the table
1020 $sql_get_default = "SELECT pg_get_expr(d.adbin, d.adrelid) as rowdefault
1021 FROM pg_attrdef d, pg_class c
1022 WHERE (c.relname = '" . $db->sql_escape($table_name) . "')
1023 AND (c.oid = d.adrelid)
1024 AND d.adnum = " . $row['attnum'];
1025 $def_res = $db->sql_query($sql_get_default);
1027 if (!$def_res)
1029 unset($row['rowdefault']);
1031 else
1033 $row['rowdefault'] = $db->sql_fetchfield('rowdefault', $def_res);
1035 $db->sql_freeresult($def_res);
1037 if ($row['type'] == 'bpchar')
1039 // Internally stored as bpchar, but isn't accepted in a CREATE TABLE statement.
1040 $row['type'] = 'char';
1043 $line = ' ' . $row['field'] . ' ' . $row['type'];
1045 if (strpos($row['type'], 'char') !== false)
1047 if ($row['lengthvar'] > 0)
1049 $line .= '(' . ($row['lengthvar'] - 4) . ')';
1053 if (strpos($row['type'], 'numeric') !== false)
1055 $line .= '(';
1056 $line .= sprintf("%s,%s", (($row['lengthvar'] >> 16) & 0xffff), (($row['lengthvar'] - 4) & 0xffff));
1057 $line .= ')';
1060 if (isset($row['rowdefault']))
1062 $line .= ' DEFAULT ' . $row['rowdefault'];
1065 if ($row['notnull'] == 't')
1067 $line .= ' NOT NULL';
1070 $lines[] = $line;
1072 $db->sql_freeresult($result);
1075 // Get the listing of primary keys.
1076 $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
1077 FROM pg_class bc, pg_class ic, pg_index i, pg_attribute ta, pg_attribute ia
1078 WHERE (bc.oid = i.indrelid)
1079 AND (ic.oid = i.indexrelid)
1080 AND (ia.attrelid = i.indexrelid)
1081 AND (ta.attrelid = bc.oid)
1082 AND (bc.relname = '" . $db->sql_escape($table_name) . "')
1083 AND (ta.attrelid = i.indrelid)
1084 AND (ta.attnum = i.indkey[ia.attnum-1])
1085 ORDER BY index_name, tab_name, column_name";
1087 $result = $db->sql_query($sql_pri_keys);
1089 $index_create = $index_rows = $primary_key = array();
1091 // We do this in two steps. It makes placing the comma easier
1092 while ($row = $db->sql_fetchrow($result))
1094 if ($row['primary_key'] == 't')
1096 $primary_key[] = $row['column_name'];
1097 $primary_key_name = $row['index_name'];
1099 else
1101 // We have to store this all this info because it is possible to have a multi-column key...
1102 // we can loop through it again and build the statement
1103 $index_rows[$row['index_name']]['table'] = $table_name;
1104 $index_rows[$row['index_name']]['unique'] = ($row['unique_key'] == 't') ? true : false;
1105 $index_rows[$row['index_name']]['column_names'][] = $row['column_name'];
1108 $db->sql_freeresult($result);
1110 if (!empty($index_rows))
1112 foreach ($index_rows as $idx_name => $props)
1114 $index_create[] = 'CREATE ' . ($props['unique'] ? 'UNIQUE ' : '') . "INDEX $idx_name ON $table_name (" . implode(', ', $props['column_names']) . ");";
1118 if (!empty($primary_key))
1120 $lines[] = " CONSTRAINT $primary_key_name PRIMARY KEY (" . implode(', ', $primary_key) . ")";
1123 // Generate constraint clauses for CHECK constraints
1124 $sql_checks = "SELECT conname as index_name, consrc
1125 FROM pg_constraint, pg_class bc
1126 WHERE conrelid = bc.oid
1127 AND bc.relname = '" . $db->sql_escape($table_name) . "'
1128 AND NOT EXISTS (
1129 SELECT *
1130 FROM pg_constraint as c, pg_inherits as i
1131 WHERE i.inhrelid = pg_constraint.conrelid
1132 AND c.conname = pg_constraint.conname
1133 AND c.consrc = pg_constraint.consrc
1134 AND c.conrelid = i.inhparent
1136 $result = $db->sql_query($sql_checks);
1138 // Add the constraints to the sql file.
1139 while ($row = $db->sql_fetchrow($result))
1141 if (!is_null($row['consrc']))
1143 $lines[] = ' CONSTRAINT ' . $row['index_name'] . ' CHECK ' . $row['consrc'];
1146 $db->sql_freeresult($result);
1148 $sql_data .= implode(", \n", $lines);
1149 $sql_data .= "\n);\n";
1151 if (!empty($index_create))
1153 $sql_data .= implode("\n", $index_create) . "\n\n";
1155 $this->flush($sql_data);
1158 function write_data($table_name)
1160 global $db;
1161 // Grab all of the data from current table.
1162 $sql = "SELECT *
1163 FROM $table_name";
1164 $result = $db->sql_query($sql);
1166 $i_num_fields = pg_num_fields($result);
1167 $seq = '';
1169 for ($i = 0; $i < $i_num_fields; $i++)
1171 $ary_type[] = pg_field_type($result, $i);
1172 $ary_name[] = pg_field_name($result, $i);
1175 $sql = "SELECT pg_get_expr(d.adbin, d.adrelid) as rowdefault
1176 FROM pg_attrdef d, pg_class c
1177 WHERE (c.relname = '{$table_name}')
1178 AND (c.oid = d.adrelid)
1179 AND d.adnum = " . strval($i + 1);
1180 $result2 = $db->sql_query($sql);
1181 if ($row = $db->sql_fetchrow($result2))
1183 // Determine if we must reset the sequences
1184 if (strpos($row['rowdefault'], "nextval('") === 0)
1186 $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";
1191 $this->flush("COPY $table_name (" . implode(', ', $ary_name) . ') FROM stdin;' . "\n");
1192 while ($row = $db->sql_fetchrow($result))
1194 $schema_vals = array();
1196 // Build the SQL statement to recreate the data.
1197 for ($i = 0; $i < $i_num_fields; $i++)
1199 $str_val = $row[$ary_name[$i]];
1201 if (preg_match('#char|text|bool|bytea#i', $ary_type[$i]))
1203 $str_val = str_replace(array("\n", "\t", "\r", "\b", "\f", "\v"), array('\n', '\t', '\r', '\b', '\f', '\v'), addslashes($str_val));
1204 $str_empty = '';
1206 else
1208 $str_empty = '\N';
1211 if (empty($str_val) && $str_val !== '0')
1213 $str_val = $str_empty;
1216 $schema_vals[] = $str_val;
1219 // Take the ordered fields and their associated data and build it
1220 // into a valid sql statement to recreate that field in the data.
1221 $this->flush(implode("\t", $schema_vals) . "\n");
1223 $db->sql_freeresult($result);
1224 $this->flush("\\.\n");
1226 // Write out the sequence statements
1227 $this->flush($seq);
1230 function write_end()
1232 $this->flush("COMMIT;\n");
1233 parent::write_end();
1238 * @package acp
1240 class mssql_extractor extends base_extractor
1242 function write_end()
1244 $this->flush("COMMIT\nGO\n");
1245 parent::write_end();
1248 function write_start($prefix)
1250 $sql_data = "--\n";
1251 $sql_data .= "-- phpBB Backup Script\n";
1252 $sql_data .= "-- Dump of tables for $prefix\n";
1253 $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
1254 $sql_data .= "--\n";
1255 $sql_data .= "BEGIN TRANSACTION\n";
1256 $sql_data .= "GO\n";
1257 $this->flush($sql_data);
1260 function write_table($table_name)
1262 global $db;
1263 $sql_data = '-- Table: ' . $table_name . "\n";
1264 $sql_data .= "IF OBJECT_ID(N'$table_name', N'U') IS NOT NULL\n";
1265 $sql_data .= "DROP TABLE $table_name;\n";
1266 $sql_data .= "GO\n";
1267 $sql_data .= "\nCREATE TABLE [$table_name] (\n";
1268 $rows = array();
1270 $text_flag = false;
1272 $sql = "SELECT COLUMN_NAME, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') as IS_IDENTITY
1273 FROM INFORMATION_SCHEMA.COLUMNS
1274 WHERE TABLE_NAME = '$table_name'";
1275 $result = $db->sql_query($sql);
1277 while ($row = $db->sql_fetchrow($result))
1279 $line = "\t[{$row['COLUMN_NAME']}] [{$row['DATA_TYPE']}]";
1281 if ($row['DATA_TYPE'] == 'text')
1283 $text_flag = true;
1286 if ($row['IS_IDENTITY'])
1288 $line .= ' IDENTITY (1 , 1)';
1291 if ($row['CHARACTER_MAXIMUM_LENGTH'] && $row['DATA_TYPE'] !== 'text')
1293 $line .= ' (' . $row['CHARACTER_MAXIMUM_LENGTH'] . ')';
1296 if ($row['IS_NULLABLE'] == 'YES')
1298 $line .= ' NULL';
1300 else
1302 $line .= ' NOT NULL';
1305 if ($row['COLUMN_DEFAULT'])
1307 $line .= ' DEFAULT ' . $row['COLUMN_DEFAULT'];
1310 $rows[] = $line;
1312 $db->sql_freeresult($result);
1314 $sql_data .= implode(",\n", $rows);
1315 $sql_data .= "\n) ON [PRIMARY]";
1317 if ($text_flag)
1319 $sql_data .= " TEXTIMAGE_ON [PRIMARY]";
1322 $sql_data .= "\nGO\n\n";
1323 $rows = array();
1325 $sql = "SELECT CONSTRAINT_NAME, COLUMN_NAME
1326 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
1327 WHERE TABLE_NAME = '$table_name'";
1328 $result = $db->sql_query($sql);
1329 while ($row = $db->sql_fetchrow($result))
1331 if (!sizeof($rows))
1333 $sql_data .= "ALTER TABLE [$table_name] WITH NOCHECK ADD\n";
1334 $sql_data .= "\tCONSTRAINT [{$row['CONSTRAINT_NAME']}] PRIMARY KEY CLUSTERED \n\t(\n";
1336 $rows[] = "\t\t[{$row['COLUMN_NAME']}]";
1338 if (sizeof($rows))
1340 $sql_data .= implode(",\n", $rows);
1341 $sql_data .= "\n\t) ON [PRIMARY] \nGO\n";
1343 $db->sql_freeresult($result);
1345 $index = array();
1346 $sql = "EXEC sp_statistics '$table_name'";
1347 $result = $db->sql_query($sql);
1348 while ($row = $db->sql_fetchrow($result))
1350 if ($row['TYPE'] == 3)
1352 $index[$row['INDEX_NAME']][] = '[' . $row['COLUMN_NAME'] . ']';
1355 $db->sql_freeresult($result);
1357 foreach ($index as $index_name => $column_name)
1359 $index[$index_name] = implode(', ', $column_name);
1362 foreach ($index as $index_name => $columns)
1364 $sql_data .= "\nCREATE INDEX [$index_name] ON [$table_name]($columns) ON [PRIMARY]\nGO\n";
1366 $this->flush($sql_data);
1369 function write_data($table_name)
1371 global $db;
1373 if ($db->sql_layer === 'mssql')
1375 $this->write_data_mssql($table_name);
1377 else if ($db->sql_layer === 'mssql_odbc')
1379 $this->write_data_odbc($table_name);
1381 else
1383 // @todo: write code for MS SQL 2005 DBAL
1384 trigger_error('KungFuDeathGrip');
1388 function write_data_mssql($table_name)
1390 global $db;
1391 $ary_type = $ary_name = array();
1392 $ident_set = false;
1393 $sql_data = '';
1395 // Grab all of the data from current table.
1396 $sql = "SELECT *
1397 FROM $table_name";
1398 $result = $db->sql_query($sql);
1400 $retrieved_data = mssql_num_rows($result);
1402 $i_num_fields = mssql_num_fields($result);
1404 for ($i = 0; $i < $i_num_fields; $i++)
1406 $ary_type[$i] = mssql_field_type($result, $i);
1407 $ary_name[$i] = mssql_field_name($result, $i);
1410 if ($retrieved_data)
1412 $sql = "SELECT 1 as has_identity
1413 FROM INFORMATION_SCHEMA.COLUMNS
1414 WHERE COLUMNPROPERTY(object_id('$table_name'), COLUMN_NAME, 'IsIdentity') = 1";
1415 $result2 = $db->sql_query($sql);
1416 $row2 = $db->sql_fetchrow($result2);
1417 if (!empty($row2['has_identity']))
1419 $sql_data .= "\nSET IDENTITY_INSERT $table_name ON\nGO\n";
1420 $ident_set = true;
1422 $db->sql_freeresult($result2);
1425 while ($row = $db->sql_fetchrow($result))
1427 $schema_vals = $schema_fields = array();
1429 // Build the SQL statement to recreate the data.
1430 for ($i = 0; $i < $i_num_fields; $i++)
1432 $str_val = $row[$ary_name[$i]];
1434 if (preg_match('#char|text|bool|varbinary#i', $ary_type[$i]))
1436 $str_quote = '';
1437 $str_empty = "''";
1438 $str_val = sanitize_data_mssql(str_replace("'", "''", $str_val));
1440 else if (preg_match('#date|timestamp#i', $ary_type[$i]))
1442 if (empty($str_val))
1444 $str_quote = '';
1446 else
1448 $str_quote = "'";
1451 else
1453 $str_quote = '';
1454 $str_empty = 'NULL';
1457 if (empty($str_val) && $str_val !== '0' && !(is_int($str_val) || is_float($str_val)))
1459 $str_val = $str_empty;
1462 $schema_vals[$i] = $str_quote . $str_val . $str_quote;
1463 $schema_fields[$i] = $ary_name[$i];
1466 // Take the ordered fields and their associated data and build it
1467 // into a valid sql statement to recreate that field in the data.
1468 $sql_data .= "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ");\nGO\n";
1470 $this->flush($sql_data);
1471 $sql_data = '';
1473 $db->sql_freeresult($result);
1475 if ($retrieved_data && $ident_set)
1477 $sql_data .= "\nSET IDENTITY_INSERT $table_name OFF\nGO\n";
1479 $this->flush($sql_data);
1482 function write_data_odbc($table_name)
1484 global $db;
1485 $ary_type = $ary_name = array();
1486 $ident_set = false;
1487 $sql_data = '';
1489 // Grab all of the data from current table.
1490 $sql = "SELECT *
1491 FROM $table_name";
1492 $result = $db->sql_query($sql);
1494 $retrieved_data = odbc_num_rows($result);
1496 if ($retrieved_data)
1498 $sql = "SELECT 1 as has_identity
1499 FROM INFORMATION_SCHEMA.COLUMNS
1500 WHERE COLUMNPROPERTY(object_id('$table_name'), COLUMN_NAME, 'IsIdentity') = 1";
1501 $result2 = $db->sql_query($sql);
1502 $row2 = $db->sql_fetchrow($result2);
1503 if (!empty($row2['has_identity']))
1505 $sql_data .= "\nSET IDENTITY_INSERT $table_name ON\nGO\n";
1506 $ident_set = true;
1508 $db->sql_freeresult($result2);
1511 $i_num_fields = odbc_num_fields($result);
1513 for ($i = 0; $i < $i_num_fields; $i++)
1515 $ary_type[$i] = odbc_field_type($result, $i + 1);
1516 $ary_name[$i] = odbc_field_name($result, $i + 1);
1519 while ($row = $db->sql_fetchrow($result))
1521 $schema_vals = $schema_fields = array();
1523 // Build the SQL statement to recreate the data.
1524 for ($i = 0; $i < $i_num_fields; $i++)
1526 $str_val = $row[$ary_name[$i]];
1528 if (preg_match('#char|text|bool|varbinary#i', $ary_type[$i]))
1530 $str_quote = '';
1531 $str_empty = "''";
1532 $str_val = sanitize_data_mssql(str_replace("'", "''", $str_val));
1534 else if (preg_match('#date|timestamp#i', $ary_type[$i]))
1536 if (empty($str_val))
1538 $str_quote = '';
1540 else
1542 $str_quote = "'";
1545 else
1547 $str_quote = '';
1548 $str_empty = 'NULL';
1551 if (empty($str_val) && $str_val !== '0' && !(is_int($str_val) || is_float($str_val)))
1553 $str_val = $str_empty;
1556 $schema_vals[$i] = $str_quote . $str_val . $str_quote;
1557 $schema_fields[$i] = $ary_name[$i];
1560 // Take the ordered fields and their associated data and build it
1561 // into a valid sql statement to recreate that field in the data.
1562 $sql_data .= "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ");\nGO\n";
1564 $this->flush($sql_data);
1566 $sql_data = '';
1569 $db->sql_freeresult($result);
1571 if ($retrieved_data && $ident_set)
1573 $sql_data .= "\nSET IDENTITY_INSERT $table_name OFF\nGO\n";
1575 $this->flush($sql_data);
1581 * @package acp
1583 class db2_extractor extends base_extractor
1585 function write_start($prefix)
1587 $sql_data = "--\n";
1588 $sql_data .= "-- phpBB Backup Script\n";
1589 $sql_data .= "-- Dump of tables for $prefix\n";
1590 $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
1591 $sql_data .= "--\n";
1592 $this->flush($sql_data);
1595 function write_table($table_name)
1597 global $db;
1598 $sql_data = '-- Table: ' . $table_name . "\n";
1599 $sql_data .= "\nCREATE TABLE $table_name (\n";
1600 $rows = array();
1602 // switch to db2_columns()?
1603 $sql = "SELECT colname, typename, length, default, identity, nulls
1604 FROM syscat.columns
1605 WHERE tabname = '$table_name'";
1606 $result = $db->sql_query($sql);
1608 while ($row = $db->sql_fetchrow($result))
1610 $line = "\t{$row['colname']} {$row['typename']}";
1612 if ($row['identity'] == 'Y')
1614 $line .= ' GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1)';
1617 if ($row['typename'] == 'VARCHAR' || $row['typename'] == 'CHARACTER' || $row['typename'] == 'CLOB')
1619 $line .= ' (' . $row['length'] . ')';
1622 if ($row['nulls'] == 'N')
1624 $line .= ' NOT NULL';
1626 else
1628 $line .= ' NULL';
1631 if ($row['default'] !== null)
1633 $line .= ' DEFAULT ' . $row['default'];
1636 $rows[] = $line;
1638 $db->sql_freeresult($result);
1640 // switch to db2_columns()?
1641 $sql = "SELECT colname
1642 FROM SYSCAT.KEYCOLUSE
1643 WHERE tabname = '$table_name'";
1644 $result = $db->sql_query($sql);
1645 $prim_cols = array();
1646 while ($row = $db->sql_fetchrow($result))
1648 $prim_cols[] = $row['colname'];
1650 $db->sql_freeresult($result);
1651 if (sizeof($prim_cols))
1653 $rows[] = "\tPRIMARY KEY (" . implode($prim_cols) . ')';
1656 $sql_data .= implode(",\n", $rows);
1657 $sql_data .= "\n);\n\n";
1658 $rows = array();
1660 $sql = "SELECT colnames, indname
1661 FROM SYSCAT.INDEXES
1662 WHERE TABNAME = '$table_name'
1663 AND UNIQUERULE <> 'P'";
1664 $result = $db->sql_query($sql);
1665 $index = array();
1666 while ($row = $db->sql_fetchrow($result))
1668 $inds = explode('+', $row['colnames']);
1669 unset($inds[0]);
1670 $sql_data .= 'CREATE INDEX ' . $row['indname'] . ' ON ' . $table_name . ' (' . implode(', ', $inds) . ") PCTFREE 10 MINPCTUSED 10 ALLOW REVERSE SCANS PAGE SPLIT SYMMETRIC COLLECT SAMPLED DETAILED STATISTICS;\n";
1672 $db->sql_freeresult($result);
1674 $this->flush($sql_data);
1677 function write_data($table_name)
1679 global $db;
1680 $ary_type = $ary_name = array();
1681 $result = db2_columns($db->db_connect_id, '', '%', $table_name);
1682 $i = 0;
1683 while ($row = $db->sql_fetchrow($result))
1685 $ary_type[$i] = $row['type_name'];
1686 $ary_name[$i++] = strtolower($row['column_name']);
1688 $db->sql_freeresult($result);
1690 // Grab all of the data from current table.
1691 $sql = "SELECT *
1692 FROM $table_name";
1693 $result = $db->sql_query($sql);
1695 $sql_data = '';
1696 $i_num_fields = $i;
1698 while ($row = $db->sql_fetchrow($result))
1700 $schema_vals = $schema_fields = array();
1702 // Build the SQL statement to recreate the data.
1703 for ($i = 0; $i < $i_num_fields; $i++)
1705 $str_val = $row[$ary_name[$i]];
1707 if (preg_match('#char|clob#i', $ary_type[$i]))
1709 $str_quote = "'";
1710 $str_empty = '';
1711 $str_val = sanitize_data_generic(str_replace("'", "''", $str_val));
1713 else if (preg_match('#date|timestamp#i', $ary_type[$i]))
1715 if (empty($str_val))
1717 $str_quote = '';
1719 else
1721 $str_quote = "'";
1724 else
1726 $str_quote = '';
1727 $str_empty = 'NULL';
1730 if (empty($str_val) && $str_val !== '0')
1732 $str_val = $str_empty;
1735 $schema_vals[$i] = $str_quote . $str_val . $str_quote;
1736 $schema_fields[$i] = '"' . $ary_name[$i] . "'";
1739 // Take the ordered fields and their associated data and build it
1740 // into a valid sql statement to recreate that field in the data.
1741 $sql_data = "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ");\n";
1743 $this->flush($sql_data);
1745 $db->sql_freeresult($result);
1750 * @package acp
1752 class oracle_extractor extends base_extractor
1754 function write_table($table_name)
1756 global $db;
1757 $sql_data = '-- Table: ' . $table_name . "\n";
1758 $sql_data .= "DROP TABLE $table_name;\n";
1759 $sql_data .= '\\' . "\n";
1760 $sql_data .= "\nCREATE TABLE $table_name (\n";
1762 $sql = "SELECT COLUMN_NAME, DATA_TYPE, DATA_PRECISION, DATA_LENGTH, NULLABLE, DATA_DEFAULT
1763 FROM ALL_TAB_COLS
1764 WHERE table_name = '{$table_name}'";
1765 $result = $db->sql_query($sql);
1767 $rows = array();
1768 while ($row = $db->sql_fetchrow($result))
1770 $line = ' "' . $row['column_name'] . '" ' . $row['data_type'];
1772 if ($row['data_type'] !== 'CLOB')
1774 if ($row['data_type'] !== 'VARCHAR2')
1776 $line .= '(' . $row['data_precision'] . ')';
1778 else
1780 $line .= '(' . $row['data_length'] . ')';
1784 if (!empty($row['data_default']))
1786 $line .= ' DEFAULT ' . $row['data_default'];
1789 if ($row['nullable'] == 'N')
1791 $line .= ' NOT NULL';
1793 $rows[] = $line;
1795 $db->sql_freeresult($result);
1797 $sql = "SELECT A.CONSTRAINT_NAME, A.COLUMN_NAME
1798 FROM USER_CONS_COLUMNS A, USER_CONSTRAINTS B
1799 WHERE A.CONSTRAINT_NAME = B.CONSTRAINT_NAME
1800 AND B.CONSTRAINT_TYPE = 'P'
1801 AND A.TABLE_NAME = '{$table_name}'";
1802 $result = $db->sql_query($sql);
1804 while ($row = $db->sql_fetchrow($result))
1806 $rows[] = " CONSTRAINT {$row['constraint_name']} PRIMARY KEY ({$row['column_name']})";
1808 $db->sql_freeresult($result);
1810 $sql = "SELECT A.CONSTRAINT_NAME, A.COLUMN_NAME
1811 FROM USER_CONS_COLUMNS A, USER_CONSTRAINTS B
1812 WHERE A.CONSTRAINT_NAME = B.CONSTRAINT_NAME
1813 AND B.CONSTRAINT_TYPE = 'U'
1814 AND A.TABLE_NAME = '{$table_name}'";
1815 $result = $db->sql_query($sql);
1817 while ($row = $db->sql_fetchrow($result))
1819 $rows[] = " CONSTRAINT {$row['constraint_name']} UNIQUE ({$row['column_name']})";
1821 $db->sql_freeresult($result);
1823 $sql_data .= implode(",\n", $rows);
1824 $sql_data .= "\n)\n\\";
1826 $sql = "SELECT A.REFERENCED_NAME
1827 FROM USER_DEPENDENCIES A, USER_TRIGGERS B
1828 WHERE A.REFERENCED_TYPE = 'SEQUENCE'
1829 AND A.NAME = B.TRIGGER_NAME
1830 AND B.TABLE_NAME = '{$table_name}'";
1831 $result = $db->sql_query($sql);
1832 while ($row = $db->sql_fetchrow($result))
1834 $sql_data .= "\nCREATE SEQUENCE {$row['referenced_name']}\\\n";
1836 $db->sql_freeresult($result);
1838 $sql = "SELECT DESCRIPTION, WHEN_CLAUSE, TRIGGER_BODY
1839 FROM USER_TRIGGERS
1840 WHERE TABLE_NAME = '{$table_name}'";
1841 $result = $db->sql_query($sql);
1842 while ($row = $db->sql_fetchrow($result))
1844 $sql_data .= "\nCREATE OR REPLACE TRIGGER {$row['description']}WHEN ({$row['when_clause']})\n{$row['trigger_body']}\\";
1846 $db->sql_freeresult($result);
1848 $sql = "SELECT A.INDEX_NAME, B.COLUMN_NAME
1849 FROM USER_INDEXES A, USER_IND_COLUMNS B
1850 WHERE A.UNIQUENESS = 'NONUNIQUE'
1851 AND A.INDEX_NAME = B.INDEX_NAME
1852 AND B.TABLE_NAME = '{$table_name}'";
1853 $result = $db->sql_query($sql);
1855 $index = array();
1857 while ($row = $db->sql_fetchrow($result))
1859 $index[$row['index_name']][] = $row['column_name'];
1862 foreach ($index as $index_name => $column_names)
1864 $sql_data .= "\nCREATE INDEX $index_name ON $table_name(" . implode(', ', $column_names) . ")\n\\";
1866 $db->sql_freeresult($result);
1867 $this->flush($sql_data);
1870 function write_data($table_name)
1872 global $db;
1873 $ary_type = $ary_name = array();
1875 // Grab all of the data from current table.
1876 $sql = "SELECT *
1877 FROM $table_name";
1878 $result = $db->sql_query($sql);
1880 $i_num_fields = ocinumcols($result);
1882 for ($i = 0; $i < $i_num_fields; $i++)
1884 $ary_type[$i] = ocicolumntype($result, $i + 1);
1885 $ary_name[$i] = ocicolumnname($result, $i + 1);
1888 $sql_data = '';
1890 while ($row = $db->sql_fetchrow($result))
1892 $schema_vals = $schema_fields = array();
1894 // Build the SQL statement to recreate the data.
1895 for ($i = 0; $i < $i_num_fields; $i++)
1897 $str_val = $row[$ary_name[$i]];
1899 if (preg_match('#char|text|bool|raw#i', $ary_type[$i]))
1901 $str_quote = '';
1902 $str_empty = "''";
1903 $str_val = sanitize_data_oracle($str_val);
1905 else if (preg_match('#date|timestamp#i', $ary_type[$i]))
1907 if (empty($str_val))
1909 $str_quote = '';
1911 else
1913 $str_quote = "'";
1916 else
1918 $str_quote = '';
1919 $str_empty = 'NULL';
1922 if (empty($str_val) && $str_val !== '0')
1924 $str_val = $str_empty;
1927 $schema_vals[$i] = $str_quote . $str_val . $str_quote;
1928 $schema_fields[$i] = '"' . $ary_name[$i] . "'";
1931 // Take the ordered fields and their associated data and build it
1932 // into a valid sql statement to recreate that field in the data.
1933 $sql_data = "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ");\n";
1935 $this->flush($sql_data);
1937 $db->sql_freeresult($result);
1940 function write_start($prefix)
1942 $sql_data = "--\n";
1943 $sql_data .= "-- phpBB Backup Script\n";
1944 $sql_data .= "-- Dump of tables for $prefix\n";
1945 $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
1946 $sql_data .= "--\n";
1947 $this->flush($sql_data);
1952 * @package acp
1954 class firebird_extractor extends base_extractor
1956 function write_start($prefix)
1958 $sql_data = "--\n";
1959 $sql_data .= "-- phpBB Backup Script\n";
1960 $sql_data .= "-- Dump of tables for $prefix\n";
1961 $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
1962 $sql_data .= "--\n";
1963 $this->flush($sql_data);
1966 function write_data($table_name)
1968 global $db;
1969 $ary_type = $ary_name = array();
1971 // Grab all of the data from current table.
1972 $sql = "SELECT *
1973 FROM $table_name";
1974 $result = $db->sql_query($sql);
1976 $i_num_fields = ibase_num_fields($result);
1978 for ($i = 0; $i < $i_num_fields; $i++)
1980 $info = ibase_field_info($result, $i);
1981 $ary_type[$i] = $info['type'];
1982 $ary_name[$i] = $info['name'];
1985 while ($row = $db->sql_fetchrow($result))
1987 $schema_vals = $schema_fields = array();
1989 // Build the SQL statement to recreate the data.
1990 for ($i = 0; $i < $i_num_fields; $i++)
1992 $str_val = $row[strtolower($ary_name[$i])];
1994 if (preg_match('#char|text|bool|varbinary|blob#i', $ary_type[$i]))
1996 $str_quote = '';
1997 $str_empty = "''";
1998 $str_val = sanitize_data_generic(str_replace("'", "''", $str_val));
2000 else if (preg_match('#date|timestamp#i', $ary_type[$i]))
2002 if (empty($str_val))
2004 $str_quote = '';
2006 else
2008 $str_quote = "'";
2011 else
2013 $str_quote = '';
2014 $str_empty = 'NULL';
2017 if (empty($str_val) && $str_val !== '0')
2019 $str_val = $str_empty;
2022 $schema_vals[$i] = $str_quote . $str_val . $str_quote;
2023 $schema_fields[$i] = '"' . $ary_name[$i] . '"';
2026 // Take the ordered fields and their associated data and build it
2027 // into a valid sql statement to recreate that field in the data.
2028 $sql_data = "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ");\n";
2030 $this->flush($sql_data);
2032 $db->sql_freeresult($result);
2035 function write_table($table_name)
2037 global $db;
2039 $sql_data = '-- Table: ' . $table_name . "\n";
2040 $sql_data .= "DROP TABLE $table_name;\n";
2042 $data_types = array(7 => 'SMALLINT', 8 => 'INTEGER', 10 => 'FLOAT', 12 => 'DATE', 13 => 'TIME', 14 => 'CHARACTER', 27 => 'DOUBLE PRECISION', 35 => 'TIMESTAMP', 37 => 'VARCHAR', 40 => 'CSTRING', 261 => 'BLOB', 701 => 'DECIMAL', 702 => 'NUMERIC');
2044 $sql_data .= "\nCREATE TABLE $table_name (\n";
2046 $sql = 'SELECT DISTINCT R.RDB$FIELD_NAME as FNAME, R.RDB$NULL_FLAG as NFLAG, R.RDB$DEFAULT_SOURCE as DSOURCE, F.RDB$FIELD_TYPE as FTYPE, F.RDB$FIELD_SUB_TYPE as STYPE, F.RDB$FIELD_LENGTH as FLEN
2047 FROM RDB$RELATION_FIELDS R
2048 JOIN RDB$FIELDS F ON R.RDB$FIELD_SOURCE=F.RDB$FIELD_NAME
2049 LEFT JOIN RDB$FIELD_DIMENSIONS D ON R.RDB$FIELD_SOURCE = D.RDB$FIELD_NAME
2050 WHERE F.RDB$SYSTEM_FLAG = 0
2051 AND R.RDB$RELATION_NAME = \''. $table_name . '\'
2052 ORDER BY R.RDB$FIELD_POSITION';
2053 $result = $db->sql_query($sql);
2055 $rows = array();
2056 while ($row = $db->sql_fetchrow($result))
2058 $line = "\t" . '"' . $row['fname'] . '" ' . $data_types[$row['ftype']];
2060 if ($row['ftype'] == 261 && $row['stype'] == 1)
2062 $line .= ' SUB_TYPE TEXT';
2065 if ($row['ftype'] == 37 || $row['ftype'] == 14)
2067 $line .= ' (' . $row['flen'] . ')';
2070 if (!empty($row['dsource']))
2072 $line .= ' ' . $row['dsource'];
2075 if (!empty($row['nflag']))
2077 $line .= ' NOT NULL';
2079 $rows[] = $line;
2081 $db->sql_freeresult($result);
2083 $sql_data .= implode(",\n", $rows);
2084 $sql_data .= "\n);\n";
2085 $keys = array();
2087 $sql = 'SELECT I.RDB$FIELD_NAME as NAME
2088 FROM RDB$RELATION_CONSTRAINTS RC, RDB$INDEX_SEGMENTS I, RDB$INDICES IDX
2089 WHERE (I.RDB$INDEX_NAME = RC.RDB$INDEX_NAME)
2090 AND (IDX.RDB$INDEX_NAME = RC.RDB$INDEX_NAME)
2091 AND (RC.RDB$RELATION_NAME = \''. $table_name . '\')
2092 ORDER BY I.RDB$FIELD_POSITION';
2093 $result = $db->sql_query($sql);
2095 while ($row = $db->sql_fetchrow($result))
2097 $keys[] = $row['name'];
2100 if (sizeof($keys))
2102 $sql_data .= "\nALTER TABLE $table_name ADD PRIMARY KEY (" . implode(', ', $keys) . ');';
2105 $db->sql_freeresult($result);
2107 $sql = 'SELECT I.RDB$INDEX_NAME as INAME, I.RDB$UNIQUE_FLAG as UFLAG, S.RDB$FIELD_NAME as FNAME
2108 FROM RDB$INDICES I JOIN RDB$INDEX_SEGMENTS S ON S.RDB$INDEX_NAME=I.RDB$INDEX_NAME
2109 WHERE (I.RDB$SYSTEM_FLAG IS NULL OR I.RDB$SYSTEM_FLAG=0)
2110 AND I.RDB$FOREIGN_KEY IS NULL
2111 AND I.RDB$RELATION_NAME = \''. $table_name . '\'
2112 AND I.RDB$INDEX_NAME NOT STARTING WITH \'RDB$\'
2113 ORDER BY S.RDB$FIELD_POSITION';
2114 $result = $db->sql_query($sql);
2116 $index = array();
2117 while ($row = $db->sql_fetchrow($result))
2119 $index[$row['iname']]['unique'] = !empty($row['uflag']);
2120 $index[$row['iname']]['values'][] = $row['fname'];
2123 foreach ($index as $index_name => $data)
2125 $sql_data .= "\nCREATE ";
2126 if ($data['unique'])
2128 $sql_data .= 'UNIQUE ';
2130 $sql_data .= "INDEX $index_name ON $table_name(" . implode(', ', $data['values']) . ");";
2132 $sql_data .= "\n";
2134 $db->sql_freeresult($result);
2136 $sql = 'SELECT D1.RDB$DEPENDENT_NAME as DNAME, D1.RDB$FIELD_NAME as FNAME, D1.RDB$DEPENDENT_TYPE, R1.RDB$RELATION_NAME
2137 FROM RDB$DEPENDENCIES D1
2138 LEFT JOIN RDB$RELATIONS R1 ON ((D1.RDB$DEPENDENT_NAME = R1.RDB$RELATION_NAME) AND (NOT (R1.RDB$VIEW_BLR IS NULL)))
2139 WHERE (D1.RDB$DEPENDED_ON_TYPE = 0)
2140 AND (D1.RDB$DEPENDENT_TYPE <> 3)
2141 AND (D1.RDB$DEPENDED_ON_NAME = \'' . $table_name . '\')
2142 UNION SELECT DISTINCT F2.RDB$RELATION_NAME, D2.RDB$FIELD_NAME, D2.RDB$DEPENDENT_TYPE, R2.RDB$RELATION_NAME FROM RDB$DEPENDENCIES D2, RDB$RELATION_FIELDS F2
2143 LEFT JOIN RDB$RELATIONS R2 ON ((F2.RDB$RELATION_NAME = R2.RDB$RELATION_NAME) AND (NOT (R2.RDB$VIEW_BLR IS NULL)))
2144 WHERE (D2.RDB$DEPENDENT_TYPE = 3)
2145 AND (D2.RDB$DEPENDENT_NAME = F2.RDB$FIELD_SOURCE)
2146 AND (D2.RDB$DEPENDED_ON_NAME = \'' . $table_name . '\')
2147 ORDER BY 1, 2';
2148 $result = $db->sql_query($sql);
2149 while ($row = $db->sql_fetchrow($result))
2151 $sql = 'SELECT T1.RDB$DEPENDED_ON_NAME as GEN, T1.RDB$FIELD_NAME, T1.RDB$DEPENDED_ON_TYPE
2152 FROM RDB$DEPENDENCIES T1
2153 WHERE (T1.RDB$DEPENDENT_NAME = \'' . $row['dname'] . '\')
2154 AND (T1.RDB$DEPENDENT_TYPE = 2 AND T1.RDB$DEPENDED_ON_TYPE = 14)
2155 UNION ALL SELECT DISTINCT D.RDB$DEPENDED_ON_NAME, D.RDB$FIELD_NAME, D.RDB$DEPENDED_ON_TYPE
2156 FROM RDB$DEPENDENCIES D, RDB$RELATION_FIELDS F
2157 WHERE (D.RDB$DEPENDENT_TYPE = 3)
2158 AND (D.RDB$DEPENDENT_NAME = F.RDB$FIELD_SOURCE)
2159 AND (F.RDB$RELATION_NAME = \'' . $row['dname'] . '\')
2160 ORDER BY 1,2';
2161 $result2 = $db->sql_query($sql);
2162 $row2 = $db->sql_fetchrow($result2);
2163 $db->sql_freeresult($result2);
2164 $gen_name = $row2['gen'];
2166 $sql_data .= "\nDROP GENERATOR " . $gen_name . ";";
2167 $sql_data .= "\nSET TERM ^ ;";
2168 $sql_data .= "\nCREATE GENERATOR " . $gen_name . "^";
2169 $sql_data .= "\nSET GENERATOR " . $gen_name . " TO 0^\n";
2170 $sql_data .= "\nCREATE TRIGGER {$row['dname']} FOR $table_name";
2171 $sql_data .= "\nBEFORE INSERT\nAS\nBEGIN";
2172 $sql_data .= "\n NEW.{$row['fname']} = GEN_ID(" . $gen_name . ", 1);";
2173 $sql_data .= "\nEND^\n";
2174 $sql_data .= "\nSET TERM ; ^\n";
2177 $this->flush($sql_data);
2179 $db->sql_freeresult($result);
2183 // get how much space we allow for a chunk of data, very similar to phpMyAdmin's way of doing things ;-) (hey, we only do this for MySQL anyway :P)
2184 function get_usable_memory()
2186 $val = trim(@ini_get('memory_limit'));
2188 if (preg_match('/(\\d+)([mkg]?)/i', $val, $regs))
2190 $memory_limit = (int) $regs[1];
2191 switch ($regs[2])
2194 case 'k':
2195 case 'K':
2196 $memory_limit *= 1024;
2197 break;
2199 case 'm':
2200 case 'M':
2201 $memory_limit *= 1048576;
2202 break;
2204 case 'g':
2205 case 'G':
2206 $memory_limit *= 1073741824;
2207 break;
2210 // how much memory PHP requires at the start of export (it is really a little less)
2211 if ($memory_limit > 6100000)
2213 $memory_limit -= 6100000;
2216 // allow us to consume half of the total memory available
2217 $memory_limit /= 2;
2219 else
2221 // set the buffer to 1M if we have no clue how much memory PHP will give us :P
2222 $memory_limit = 1048576;
2225 return $memory_limit;
2228 function sanitize_data_mssql($text)
2230 $data = preg_split('/[\n\t\r\b\f]/', $text);
2231 preg_match_all('/[\n\t\r\b\f]/', $text, $matches);
2233 $val = array();
2235 foreach ($data as $value)
2237 if (strlen($value))
2239 $val[] = "'" . $value . "'";
2241 if (sizeof($matches[0]))
2243 $val[] = 'char(' . ord(array_shift($matches[0])) . ')';
2247 return implode('+', $val);
2250 function sanitize_data_oracle($text)
2252 $data = preg_split('/[\0\n\t\r\b\f\'"\\\]/', $text);
2253 preg_match_all('/[\0\n\t\r\b\f\'"\\\]/', $text, $matches);
2255 $val = array();
2257 foreach ($data as $value)
2259 if (strlen($value))
2261 $val[] = "'" . $value . "'";
2263 if (sizeof($matches[0]))
2265 $val[] = 'chr(' . ord(array_shift($matches[0])) . ')';
2269 return implode('||', $val);
2272 function sanitize_data_generic($text)
2274 $data = preg_split('/[\n\t\r\b\f]/', $text);
2275 preg_match_all('/[\n\t\r\b\f]/', $text, $matches);
2277 $val = array();
2279 foreach ($data as $value)
2281 if (strlen($value))
2283 $val[] = "'" . $value . "'";
2285 if (sizeof($matches[0]))
2287 $val[] = "'" . array_shift($matches[0]) . "'";
2291 return implode('||', $val);
2294 // modified from PHP.net
2295 function fgetd(&$fp, $delim, $read, $seek, $eof, $buffer = 8192)
2297 $record = '';
2298 $delim_len = strlen($delim);
2300 while (!$eof($fp))
2302 $pos = strpos($record, $delim);
2303 if ($pos === false)
2305 $record .= $read($fp, $buffer);
2306 if ($eof($fp) && ($pos = strpos($record, $delim)) !== false)
2308 $seek($fp, $pos + $delim_len - strlen($record), SEEK_CUR);
2309 return substr($record, 0, $pos);
2312 else
2314 $seek($fp, $pos + $delim_len - strlen($record), SEEK_CUR);
2315 return substr($record, 0, $pos);
2319 return false;
2322 function fgetd_seekless(&$fp, $delim, $read, $seek, $eof, $buffer = 8192)
2324 static $array = array();
2325 static $record = '';
2327 if (!sizeof($array))
2329 while (!$eof($fp))
2331 if (strpos($record, $delim) !== false)
2333 $array = explode($delim, $record);
2334 $record = array_pop($array);
2335 break;
2337 else
2339 $record .= $read($fp, $buffer);
2342 if ($eof($fp) && strpos($record, $delim) !== false)
2344 $array = explode($delim, $record);
2345 $record = array_pop($array);
2349 if (sizeof($array))
2351 return array_shift($array);
2354 return false;