Archive for September, 2009

porównywanie baz MySQL w PHP

Często przy pracy nad aplikacjami z bazą SQL zdarza się sytuacja, kiedy baza ‘deweloperska’ uległa nieudokumentowanym dokładnie zmianom, i wreszcie trzeba je wdrożyć w wersji produkcyjnej. Oczywiście lepiej byłoby prowadzić dziennik zmian :) Kiedy jednak już jest za późno, przydaje się poniższy skrypt do porównywania baz. Wychwytuje on różnice na poziomie definicji tabel i pól, proponując stosowne polecenia typu CREATE, ALTER, itp. Propozycje te nie są doskonałe, trzeba zwracać uwagę zwłaszcza na klucze i wartości domyślne, ale na pewno ułatwia synchronizację.

Skrypt napisany na podstawie MySQL Database Diff Script, ale znacznie rozszerzony i zmodyfikowany. Enjoy! :)

<html>
<head>
<style>
.deleted{
	text-decoration:line-through;
	color:red;
}
.added{
	color:green;
}
</style>
</head>
<body>
< ?php
/**
 * original by Adam Young http://adamyoung.net/
 * modified and extended 2009-09-26 by ptrk http://nobigwords.ntxt.net/ 
 * 
 */
$src_host = '';
$src_user = 'root';
$src_pass = '';
$src_db = 'baza32_superskl_emisja';
 
$dst_host = '';
$dst_user = 'root';
$dst_pass = '';
$dst_db = 'baza32_superskl';
 
$src = mysql_connect($src_host, $src_user, $src_pass);
if (!mysql_select_db($src_db, $src)) die("Could not find/USE source database: {$src_db}\n");
 
$src_tables = getTables($src);
 
 
$dst = mysql_connect($dst_host, $dst_user, $dst_pass);
if (!mysql_select_db($dst_db, $dst)) die("Could not find/USE destination database: {$dst_db}\n");
 
$dst_tables = getTables($dst);
 
 
foreach ($src_tables as $t => $table) {
	$i = 0;
	$found = false;
 
	if(isset($dst_tables[$t])){
		$dst_table = $dst_tables[$t];
		if ($dst_table->name == $table->name) {
			$diff = compareDefinitions($table->definition, $dst_table->definition);
			if (count($diff) == 0){
				echo "{$table->name}<br />";
			}else{
				echo "<b>{$table->name} is different</b><br /><ul>";
				$alters = '';
				foreach($diff as $col => $info){
					echo "<li>$col : " . $info['info'] . "</li>";
					$alters .= "alter table `" . $dst_table->name . "` " . $info['alter'] . ";\n";
				}
				echo '</ul>';
				echo "&gt;pre&lt;" . $alters . " &gt;/pre&lt;";
			}
			unset($dst_tables[$i]);
			$found = true;
		}
	}else{
		echo "<span class='deleted'>{$table->name} </span><br />";
		echo "&gt;pre&lt;{$table->create}&gt;/pre&lt;<br />";
	}
}
 
function getTables($link) {
	$rsrc = mysql_query('SHOW TABLES', $link);
	$tables = array();
	while ($row = mysql_fetch_row($rsrc)) {
		$table = new table(
			$row[0],
			getTableDef($link, $row[0]),
			getTableCreate($link, $row[0])
		);
		$tables[$row[0]] = $table;
	}
	return $tables;
}
 
function getTableDef($link, $table) {
	$rsrc = mysql_query("DESCRIBE `{$table}`");
	$result = array();
	while($row = mysql_fetch_row($rsrc)){
		list($name, $type, $null, $key, $default, $extra) = $row;
		$result[$name] = array($type, $null, $key, $default, $extra);
	}
	return $result;
}
 
function getTableCreate($link, $table) {
	$rsrc = mysql_query("SHOW CREATE TABLE `{$table}`");
	$row = mysql_fetch_row($rsrc);
	$result = $row[1];
	return $result;
}
 
class table {
	var $name;
	var $definition;
	var $create;
	function table($name, $def, $create) {
		$this->name = $name;
		$this->definition = $def;
		$this->create = $create;
	}
}
 
function compareDefinitions($defA, $defB){
	$result = array();
	foreach($defA as $col => $colDefA){
		if(!isset($defB[$col])){
			$result[$col]['info'] = "<span class='deleted'>deleted </span>";
			$result[$col]['alter'] = "drop column `" . $col . "`";
		}else{
			if(implode(',',$colDefA) != implode(',',$defB[$col])){
 
				list($typeA, $nullA, $keyA, $defaultA, $extraA) = $colDefA;
				list($typeB, $nullB, $keyB, $defaultB, $extraB) = $defB[$col];
				$info = '';
				if($typeA != $typeB) $info .= "different type $typeA/$typeB, ";
				if($nullA != $nullB) $info .= "null $nullA/$nullB, ";
				if($keyA != $keyB) $info .= "key: $keyA/$keyB, ";
				if($defaultA != $defaultB) $info .= "default: $defaultA/$defaultB, ";
				if($extraA != $extraB) $info .= "extra: $extraA/$extraB, ";
				$result[$col]['info'] = trim($info,', ');
				$result[$col]['alter'] =	"change `$col` `$col` $typeA ";
				$result[$col]['alter'] .=	($defaultA == '') ? '' : "default '$defaultA' ";
				$result[$col]['alter'] .=	($nullA == 'NO') ? 'NOT NULL ' : '';
				$result[$col]['alter'] .=	"$extraA ";
 
			}
			unset($defB[$col]);
		}
	}
	foreach($defB as $colB => $colDefB){
		list($typeB, $nullB, $keyB, $defaultB, $extraB) = $colDefB;
		$result[$colB]['info'] = "<span class='added'>added</span>";
		$result[$colB]['alter'] = "add `$colB` $typeB ";
 
	}
	return $result;
}
 
 
function errors($link){
	return mysql_errno($link) . ": " . mysql_error($link) . "\n";
}
?>
</body>
</html>

Bankujesz-kupujesz w kompletowaniu

Tatę skusił netbook Samsunga, dostępny na bankujesz-kupujesz.pl banku ING. Zamówiliśmy. Zapłaciliśmy. Było taniej, nawet sporo taniej. (vobis: 1999 zł, ceneo od 1568 zł, na b-k: 1349 zł). Czekamy. Jedenasty dzień, mimo opatrzenia produktu terminem siedmiodniowym, czekamy. Nie ma żadnej wiadomości.

Numer referencyjny zamówienia: #....
Data złożenia 2009-09-03 11:57:06
Razem do zapłaty 1 377,20 zł
Adres dostawy:...
Status zamówienia: kompletowane
Ostatnia zmiana statusu: 2009-09-04 08:03:15
Opis statusu zamówienia:

Jak ja lubię te marketingowe okrągłe zdania: W bankujesz-kupujesz produkty dostępne są łatwo, szybko i bezpiecznie [tutaj].

Już pisałem o tym programie i dalej uważam, że pomysł jest fajny, ale komunikacja szwankuje. Dużo gorsze zdanie mają uczestnicy biznesforum.pl bankujesz-kupujesz.

[2009-09-17] Laptop dotarł. Jest fajny, ale ze strony banku ani słowa przeprosin czy wyjaśnienia. Kilka dni wcześniej dzwoniliśmy z pytaniem, co się dzieje. Uzyskaliśmy trafną, jak się okazało, przepowiednię, ale bez zażenowania związanego ze zwłoką. Na e-mail dotarł list potwierdzający realizację zamówienia. Wydaje mi się, że ważniejsze są e-maile ostrzegające i wyjaśniające PRZED pojawieniem się faktów, niż te stwierdzające status quo. Od banku wymagam więcej niż od sklepu założonego przez pana Wiesia.