Mysql Diff / Mysql tools

5 02 2007

Trabalhando com desenvolvimento e banco de dados, é comum
estar trabalhando em uma versão X e ter que migrar uma versão
Y para essa versão X. Muito comum por sinal.

Diversas vezes tive problemas em encontrar as diferenças entre duas versões
diferentes de um mesmo banco de dados, pelo fato simples de não anotar as
mudanças efetuadas manualmente na estrutura do banco. Acredito que esse problema
venha a ser menos recorrentes quando há alguem ou uma equipe trabalhando exclusivamente
com o banco.

De qualquer maneira, quando precisava fazer um diff de bancos, mysql, costumava
perder bastante tempo fazendo isso manualmente e não eram raras as vezes que
não encontrava todas as diferenças. Para solucionar este pequeno problema, em parte,
acabei por desenvolver um mysqldiff, que tem se mostrado bastante funcional e tem
resolvido o problema.

Junto com o mysqldiff há, no momento, mais duas opções, uma para mostrar a quantidade
de espaço que um db esta utilizando e uma outra para exibir relações entre tabelas
utilizando engine InnoDB.

Segue o alguns exemplos de uso (para as 3 opções) e o código da versão 0.01:

mysqltools.php

$ mysqltools.php
Uso: mysqltools.php options
relations: dbname
size: db1 db2 … dbn
tablesdiff: olddb newdb

$ mysqltools.php tablesdiff zayp_old zayp
# New tables: 1
A logs
# Deleted filds in table “projeto” : 1
DF projeto.observacao
# New filds in table “requisito_funcional”: 1
AF requisito_funcional.observacao
# Changed filds in table “tarefa” : 1
CF tarefa.tempo_estimado

$ mysqltools.php tablesdiff sfff sfff_remoto
# New filds in table “cv”: 1
AF cv.endereco
# Deleted filds in table “cv” : 7
DF cv.endereco_rua
DF cv.endereco_numero
DF cv.endereco_cep
DF cv.endereco_bairro
DF cv.endereco_uf
DF cv.endereco_cidade
DF cv.endereco_complemento
# Deleted filds in table “jornalista” : 1
DF jornalista.mensagem

$ mysqltools.php size r2s zayp cep
Database “r2s” size: 281.171875M
Database “zayp” size: 1.34375M
Database “cep” size: 34.741413116455M

$ mysqltools.php relations r2s
# table “bot_account_tag” : 2
bot_account_tag.id_account -> account.id_account
bot_account_tag.id_tag -> tag.id_tag
# table “category_to_rss” : 2
category_to_rss.id_category -> category.id_category,
category_to_rss.id_rss -> rss.id_rss
# table “point_user_rss_item” : 1
point_user_rss_item.id_rss_item -> rss_item.id_rss_item
# table “related_categories” : 2
related_categories.id_category -> category.id_category,
related_categories.id_related_category -> category.id_category
# table “related_tag” : 2
related_tag.id_tag -> tag.id_tag
related_tag.id_related_tag -> tag.id_tag
# table “rss_category” : 1
rss_category.id_rss -> rss.id_rss
# table “rss_cloud” : 1
rss_cloud.id_rss -> rss.id_rss
# table “rss_image” : 1
rss_image.id_rss -> rss.id_rss
# table “rss_item” : 1
rss_item.id_rss -> rss.id_rss
# table “rss_item_category” : 1
rss_item_category.id_rss_item -> rss_item.id_rss_item
# table “rss_item_link_referer” : 2
rss_item_link_referer.id_rss_item_refering -> rss_item.id_rss_item
rss_item_link_referer.id_rss_item_refered -> rss_item.id_rss_item
# table “rss_item_title_referer” : 2
rss_item_title_referer.id_rss_item_refered -> rss_item.id_rss_item
rss_item_title_referer.id_rss_item_refering -> rss_item.id_rss_item
# table “tags_to_rss” : 2
tags_to_rss.id_tag -> tag.id_tag
tags_to_rss.id_rss -> rss.id_rss
# table “tags_to_rss_item” : 2
tags_to_rss_item.id_tag -> tag.id_tag
tags_to_rss_item.id_rss_item -> rss_item.id_rss_item
# table “text_input” : 1
text_input.id_rss -> rss.id_rss
# table “visualization_rss_item” : 1
visualization_rss_item.id_rss_item -> rss_item.id_rss_item

#!/usr/local/bin/php -q
<?php
  class MysqlTools {
      private $host = 'localhost';
      private $user = 'root';
      private $pass = '';
      private $db   = array();
      private $link;
      private $_argv;      
       private function connect()
      {
          $this->link = @mysql_connect (
                          $this->host,
                          $this->user,
                          $this->pass );
          if ( !$this->link )
              die ( mysql_error()."n" );
      }

      private function dbSize()
      {
          if ( sizeof($this->_argv) < 3 )
              die (sprintf('Uso: %s dbsize db1 db2 ... dbn%s', $this->_argv[0], "n"));

          foreach ( $this->_argv as $k => $a ) {
              if ( $k < 2 ) continue;
              $this->db[] = $a;
          }

          foreach ( $this->db as $db ) {
              mysql_select_db($db) || die ( mysql_error()."n" );
              $rs = mysql_query ('show table status', $this->link );
              $size = 0;
              while ( $r = mysql_fetch_array($rs, MYSQL_ASSOC) ) {
                  $size += $r['Data_length'];
                  $size += $r['Index_length'];
              }

              $size = $size / 1024 / 1024;
              echo sprintf('Database "%s" size: %sM%s', $db, $size, "n");
          }
      }

      private function dbTablesDiff ()
      {
          if ( sizeof($this->_argv) != 4 )
              die (sprintf('Uso: %s dbtablesdiff olddb newdb%s', $this->_argv[0], "n"));

          foreach ( $this->_argv as $k => $a ) {
              if ( $k < 2 ) continue;
              $this->db[] = $a;
          }

          $tables = array();
          $fields = array();
          $cfields = array();
          foreach ( $this->db as $db ) {
              mysql_select_db($db) || die ( mysql_error()."n" );
              $rs = mysql_query ('show tables', $this->link );
              while ( $r = mysql_fetch_array($rs, MYSQL_NUM) ) {
                  foreach ( $r as $v )
                      $tables[$db][] = $v;
              }
              foreach ( $tables[$db] as $v ) {
                  $rs = mysql_query ( sprintf('show columns from %s ', $v), $this->link );
                  while ( $r = mysql_fetch_array($rs, MYSQL_ASSOC) ) {
                      $fields[$db][$v][] = $r['Field'];
                      $cfields[$db][$v][$r['Field']] = md5(print_r($r, true));
                  }
              }
          }

          $nTables1 = sizeof($this->db[0]);
          $nTables2 = sizeof($this->db[1]);
          $tablesAdded = array_diff(
                            $tables[ $this->db[1] ],
                            $tables[ $this->db[0] ]
                          );

          $tablesRemoved = array_diff (
                            $tables[ $this->db[0] ],
                            $tables[ $this->db[1] ]
                            );

          if ( sizeof($tablesAdded) )
              echo sprintf('# New tables: %s%s', sizeof($tablesAdded), "n");

          foreach ( $tablesAdded as $newTable )
              echo sprintf('A %s%s', $newTable, "n");

          if ( sizeof($tablesRemoved) )
              echo sprintf('# Deleted tables: %s%s', sizeof($tablesRemoved), "n");

          foreach ( $tablesRemoved as $delTable )
              echo sprintf('D %s%s', $delTable, "n");

          $odb = $this->db[1];
          foreach ( $fields as $ndb => $ntables ) {
              foreach ( $ntables as $ntable => $tfil ) {
                  if ( array_search($ntable, $tables[$odb]) !== false ) {
                      $addedFields = array_diff (
                                        $fields[$odb][$ntable],
                                        $tfil
                                      );

                      $removedFields = array_diff (
                                        $tfil,
                                        $fields[$odb][$ntable]
                                      );

                      if (sizeof($addedFields) )
                          echo sprintf('# New filds in table "%s": %s%s',  $ntable, sizeof($addedFields), "n");

                      foreach ( $addedFields as $af )
                          echo sprintf('AF %s.%s%s', $ntable, $af, "n");

                      if (sizeof($removedFields) )
                          echo sprintf('# Deleted filds in table "%s" : %s%s',  $ntable, sizeof($removedFields), "n");

                      foreach ( $removedFields as $rf )
                          echo sprintf('DF %s.%s%s', $ntable, $rf, "n");

                      $sameFields = array_intersect (
                                        $tfil,
                                        $fields[$odb][$ntable]
                                      );

                      $cf = array();
                      foreach ( $cfields[$ndb][$ntable] as $f => $v ) {
                          if ( !array_key_exists ( $f, $cfields[$odb][$ntable] ) ) continue;
                          if ( $v != $cfields[$odb][$ntable][$f] )
                              $cf[] = $f;
                      }

                      if ( sizeof($cf) )
                          echo sprintf('# Changed filds in table "%s" : %s%s',  $ntable, sizeof($cf), "n");

                      foreach ( $cf as $c )
                              echo sprintf('CF %s.%s%s', $ntable, $c, "n" );
                  }
              }

              $odb = $this->db[0];
              break; // : )
          }
      }

       private function dbRelations (  )
       {
          if ( sizeof($this->_argv) != 3 )
              die (sprintf('Uso: %s dbrelactions db%s', $this->_argv[0], "n"));

          $db = $this->_argv[2];
          $tables = array();

          mysql_select_db($db) || die ( mysql_error()."n" );
          $rs = mysql_query ('show tables', $this->link );
          while ( $r = mysql_fetch_array($rs, MYSQL_NUM) ) {
                foreach ( $r as $v )
                    $tables[] = $v;
          }

          foreach ( $tables as $table ) {
              $rs = mysql_query ( sprintf('SHOW CREATE TABLE %s', $table) );
              $result = mysql_fetch_array($rs, MYSQL_ASSOC);
              if ( !@$result['Create Table'] ) continue;
              $script = str_replace ( array('(',')', '`'), array('','',''), $result['Create Table']);
              $source = explode ( "n", $script );
              $cont = 0;
              $fk = array();
              foreach ( $source as $line ) {
                  $line = trim($line);
                  if ( substr($line,0, 10) == 'CONSTRAINT' ) {
                      $tokens = explode ( ' ', $line );
                      $fk[$cont]['field']   = $tokens[4];
                      $fk[$cont]['fktable'] = $tokens[6];
                      $fk[$cont]['fkfield'] = $tokens[7];
                      $cont++;
                  }
              }

              if (sizeof($fk))
                  echo sprintf('# table "%s" : %s%s', $table, sizeof($fk), "n" );

              foreach ( $fk as $f ) {
                  echo sprintf ('%s.%s -> %s.%s%s', $table, $f['field'], $f['fktable'], $f['fkfield'], "n");
              }
          }
      }

      private function uso()
      {
        echo sprintf('Uso: %s <relations|tablesdiff|size> options %s', $this->_argv[0], "n");
        echo "relations:  dbnamen";
        echo "size:       db1 db2 ... dbnn";
        echo "tablesdiff: olddb newdbn";
      }

      public function run()
      {
          global $argv;
          $this->_argv = $argv;
          $this->connect();
          $opt = trim(@$argv[1]);
          switch ( $opt ) {
              case 'size':
                  $this->dbSize();
              break;

              case 'relations':
                  $this->dbRelations();
              break;

              case 'tablesdiff':
                  $this->dbTablesDiff();
              break;

              default:
                  $this->uso();
                  echo sprintf('Opcao desconhecida (%s)%s', $opt, "n");
              break;
          }
      }
  }
  $mt = new MysqlTools();
  $mt->run();
Anúncios

Ações

Information

One response

18 09 2010
ganso

minha conta confirmada

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s




%d blogueiros gostam disto: