Postgre: Как сдампить базу и запихнуть в контроль версий

Настал тот день, когда Вам приходится писать много, действительно много функций в базе данных, а не в php. И в принципе наверное можно так и писать, потихоньку сохраняя куда-то у себя в схемах, но дублировать код — грустно, нудно и бессмысленно. Не сохранять — а просто ваять базу через консольку sql запросов — как делает большая часть команд разработчиков, не наделенных отдельным архитектором БД, и уж тем более каждый честный одинокий пыхпыхер… — это рискованное земледелие. Мягко выражаясь) Поэтому, для себя я делаю такой вот минимегаскриптик на php (не считая регулярного pg_dumpall -U -f). Потому что мне удобнее видеть в дереве проекта читабельную схему, а в контроле версий — реальные изменения каждого отдельного файла. Схему, сейчас завязанную на экспорте таблиц и функций из Postgre через sql запросы, можно развить и разнообразить под личные вкусы (например, добавить представления — они практически рядом), но ведь забавно что вытянуть в конце концов можно все.

ПС Я знаю про автоматические рисовалки БД вроде DBDesigner, но лично меня удивляют результатами (я люблю больше и все по-другому))))

<?php
include_once 'app/_settings.php';
include_once 'app/_constants.php';
header('Content-Type: text/html; charset="utf-8"');
try {
	$bigtext    = "\n\n\n\n----------------------------------------------------------------------------------\n\n\n\n\n\nCheck DB : " . date('Y-m-d H:i:s');
	$changed	= 0;
	$tables 	= DB::query('SELECT t.*, c.oid, pg_catalog.obj_description(c.oid) AS comment   FROM INFORMATION_SCHEMA.tables AS t 
					LEFT JOIN pg_catalog.pg_class c ON c.relname=t.table_name
					WHERE t.table_schema=\'' . DB_SCHEMA . '\' ORDER BY t.table_name', 'array');
	$functions 	= DB::query('SELECT r.routine_name, r.routine_definition, r.data_type,
					pg_catalog.format_type(p.prorettype, NULL) AS proresult,
					pg_catalog.oidvectortypes(p.proargtypes) AS proarguments,
					proargnames AS proargnames,
					pg_catalog.obj_description(p.oid, \'pg_proc\') AS procomment
					FROM INFORMATION_SCHEMA.routines AS r
					LEFT JOIN pg_catalog.pg_proc AS p ON p.proname=r.routine_name
					WHERE r.specific_schema=\'' . DB_SCHEMA . '\' ORDER BY r.routine_name', 'alist');
	if ($tables) foreach ($tables AS $table) {
		$tid	= $table['oid'];
		$cols	= DB::query('SELECT col.* FROM information_schema.columns AS col
				WHERE col.table_schema=\'' . DB_SCHEMA . '\' 
				AND col.table_name=' .  DB::escape($table['table_name'], true) . ' 
				ORDER BY col.ordinal_position', 'array');
		$keys   = DB::query('SELECT conname, contype, pg_catalog.pg_get_constraintdef(r.oid, true) as condef FROM pg_catalog.pg_constraint r 
				WHERE r.conrelid = ' . $tid, 'array');
		$triggers = DB::query('SELECT trigger_name, action_statement, action_timing, string_agg(event_manipulation, \', \') FROM information_schema.triggers 
				WHERE event_object_table=\'' . $table['table_name'] . '\' GROUP BY trigger_name, action_statement, action_timing ORDER BY trigger_name', 'array');		
		$text = "Table:   " . $table['table_name']
			. "\nComment: " . $table['comment'];
		if ($cols) {
			$text .= "\n\n-----------------------------------------\n\nColumns: ";
			foreach ($cols AS $col) {
				$text .="\n\nName:    " . $col['column_name'] 
						. "\nType:    " . $col['data_type'] 
						. "\nDefault: " . $col['column_default'] 
						. "\nComment: " . DB::query('SELECT pg_catalog.col_description(' . $tid . ',' . $col['dtd_identifier'] . ')');
			}
		}
		if ($keys) {
			$text .= "\n\n-----------------------------------------\n\nIndexes: ";
			foreach ($keys AS $key) {
				$text .="\n\nName:    " . $key['conname'] 
						. "\nType:    " . $key['contype'] 
						. "\nDefined: " . $key['condef'];
			}
		}
		if ($triggers) {
			$text .= "\n\n-----------------------------------------\n\nTriggers: ";
			foreach ($triggers AS $trigger) {
				$text .="\n\nName:    " . $trigger['trigger_name'] 
						. "\nTiming:  " . $trigger['action_timing']
						. "\nActions: " . $trigger['string_agg']
						. "\nDefined: " . $trigger['action_statement'];
				$function_name = trim(str_replace(array('EXECUTE PROCEDURE', '()'), '', $trigger['action_statement']));
				if ($function_name && isset($functions[$function_name])) {
					$text .= "\n\n" . $functions[$function_name]['routine_definition']
							. "\nComment: " . $functions[$function_name]['procomment'];
				}
			}
		}
		$filename = DB_DUMP_PATH . 'table_' . $table['table_name'] . '.settings.php';
		$file = file_get_contents($filename);
		if ($file != $text) {
			file_put_contents($filename, $text);
			$bigtext .= $text;
			$changed++;
		}
	}
	if ($functions) foreach ($functions AS $function) {
		$vars = explode(',', str_replace(array('{', '}'), '', trim($function['proargnames'])));
		$var_types = explode(', ', $function['proarguments']); 
		$var_line  = array();
		if ($vars) {
			foreach ($vars AS $i => $var) {
				if ($var) $var_line[] = '"' . $var . '"::' . $var_types[$i];
			}
		}
		$text = "Function:  " . $function['routine_name']
			. "\nVariables: " . implode(', ', $var_line)
			. "\nReturn:    " . $function['proresult'] 
			. "\nComment:   " . $function['procomment'] 
			. "\n\n" . $function['routine_definition'];
		$filename = DB_DUMP_PATH . 'function_' . $function['routine_name'] . '.settings.php';
		$file = file_get_contents($filename);
		if ($file != $text) {
			file_put_contents($filename, $text);
			$bigtext .= $text;
			$changed++;
		}
	}
	if ($changed) {
		$filename = DB_DUMP_PATH . '_last_check.settings.php';
		$file = file_get_contents($filename);
		file_put_contents($filename, $bigtext, FILE_APPEND | LOCK_EX );
		echo '<pre>' . $bigtext . '

‘;
} else {
echo ‘Nothing Changed, Thank You!’;
}
} catch (Exception $e){
Error::getUserMessage($e);
}

Оставить комментарий

XHTML: Вы можете использовать такие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre lang="" line="" escaped="" cssfile="">