Comparando esquemas

Hibernate tiene una mala costumbre: si uno lo deja, hace la base de datos como se le ocurre. Qué quiero decir con esto? que si 2 veces le decimos que lo haga, e intentamos comparar los esquemas resultantes, serán distintos, porque no mantiene el órden de las columnas dentro de las tablas.

Si el programa va a buscar los datos haciendo selects por nombre de columna, no habrá problemas (e hibernate los hace así) pero al querer comparar 2 esquemas de desarrollo, para detectar las diferencias y poder aplicar los cambios, nos encontraremos que tablas que no tienen diferencias aparecen como diferentes.

Con este panorama (y muchas, muchas tablas que comparar a mano) es que me armé un script en php que compara tablas y columnas entre 2 esquemas, para listar los cambios necesarios para llevar la base original a la base de ejemplo.

Atención: NO CHEQUEA FK ni CONSTRAINTS ni INDICES es sólo para tablas.

<?

function db_open($database){
  $serverName = "YourServerHere";
  $connectionInfo = array( "Database"=>$database);
  $conn = sqlsrv_connect( $serverName, $connectionInfo);
  if( !$conn ) {
    echo "Connection could not be established.\n";
    die( print_r( sqlsrv_errors(), true));
  }
  return $conn;
}

function GetArrayTablas($conn){
  $sql="SELECT so.name AS Tabla, sc.name AS Columna, st.name AS Tipo, sc.max_length AS Tamanio,
        CASE sc.is_nullable
          when 0 then 'NOT NULL'
          else 'NULL'
        END AS Nullificable
        FROM sys.objects so INNER JOIN sys.columns sc ON so.object_id = sc.object_id
             INNER JOIN sys.types st ON st.system_type_id = sc.system_type_id AND st.name != 'sysname'
        WHERE so.type = 'U' ORDER BY so.name, sc.name";

  $res=sqlsrv_query($conn,$sql);
  while($row=sqlsrv_fetch_array($res,SQLSRV_FETCH_ASSOC)){
    $miarray['Tipo']=strtolower($row['Tipo']) ;
    $miarray['Tamanio']=strtolower($row['Tamanio']) ;
    $miarray['Null']=strtolower($row['Nullificable']) ;

    if(trim($miarray['Tipo'])=='nvarchar'){
      if($miarray['Tamanio']==510){
        $miarray['Tamanio']=255;
      } else {
        $miarray['Tamanio']=($miarray['Tamanio']/2);
      }
    }
    $origen[strtolower($row['Tabla'])][strtolower($row['Columna'])]=$miarray;
  }
  return $origen;
}

$conn=db_open("DbEjemplo");
$origen=GetArrayTablas($conn);

$conn=db_open("DbDestino");
$destino=GetArrayTablas($conn);

//recorro origen, a ver si a destino le falta algo (o hay que modificar algo)
$tablas=(array_keys($origen));

for ($i=0;$i<count($tablas);$i++){
  //me fijo que exista en destino:
  if(!array_key_exists($tablas[$i],$destino)){
    echo "tabla ".$tablas[$i]." no existe en destino==> debo crear!\n";
  } else {
    //si existe, asique habra que verificar las columnas!
    $columnas=(array_keys($origen[$tablas[$i]]));
    for($j=0;$j<count($columnas);$j++){
      //me fijo que exista!
      if(array_key_exists($columnas[$j],$destino[$tablas[$i]])){
        //la columna existe!
        //chequeo valores (tipo, tamanio, null)
        $cambio=0;
        //chequeo tipo!
        if($origen[$tablas[$i]][$columnas[$j]]['Tipo']!=$destino[$tablas[$i]][$columnas[$j]]['Tipo']){
          //echo "CAMBIO EL TIPO!\n";
          $cambio=1;
        }
        if($origen[$tablas[$i]][$columnas[$j]]['Tamanio']!=$destino[$tablas[$i]][$columnas[$j]]['Tamanio']){
          //echo "CAMBIO EL Tamanio!\n";
          if($origen[$tablas[$i]][$columnas[$j]]['Tamanio']=='-1'){
            $origen[$tablas[$i]][$columnas[$j]]['Tamanio']='max';
          }
          $cambio=1;
        }
        if($origen[$tablas[$i]][$columnas[$j]]['Null']!=$destino[$tablas[$i]][$columnas[$j]]['Null']){
          //echo "CAMBIO EL Null!\n";
          $cambio=1;
        }
        if($cambio==1){
          if(trim($origen[$tablas[$i]][$columnas[$j]]['Tipo'])=='int' ||
             trim($origen[$tablas[$i]][$columnas[$j]]['Tipo'])=='ntext' ||
             trim($origen[$tablas[$i]][$columnas[$j]]['Tipo'])=='bit' ){
            $ALTERCOLUMN.= "ALTER TABLE [".$tablas[$i]."] ALTER COLUMN [".$columnas[$j]."] ".$origen[$tablas[$i]][$columnas[$j]]['Tipo']." ".$origen[$tablas[$i]][$columnas[$j]]['Null'].";\n";
          } else {
            $ALTERCOLUMN.= "ALTER TABLE [".$tablas[$i]."] ALTER COLUMN [".$columnas[$j]."] ".$origen[$tablas[$i]][$columnas[$j]]['Tipo']." (".$origen[$tablas[$i]][$columnas[$j]]['Tamanio'].") ".$origen[$tablas[$i]][$columnas[$j]]['Null'].";\n";
          }
        }
      } else {
        if($origen[$tablas[$i]][$columnas[$j]]['Tamanio']=='-1'){
          $origen[$tablas[$i]][$columnas[$j]]['Tamanio']='max';
        }
        if(trim($origen[$tablas[$i]][$columnas[$j]]['Tipo'])=='int' ||
           trim($origen[$tablas[$i]][$columnas[$j]]['Tipo'])=='ntext' ||
           trim($origen[$tablas[$i]][$columnas[$j]]['Tipo'])=='bit' ){
          //echo "debo crear columna ".$columnas[$j]." en ".$tablas[$i]." \n";
          $ADDCOLUMN.= "ALTER TABLE [".$tablas[$i]."] ADD [".$columnas[$j]."] ".$origen[$tablas[$i]][$columnas[$j]]['Tipo']." ".$origen[$tablas[$i]][$columnas[$j]]['Null'].";\n";
        } else {
          $ADDCOLUMN.= "ALTER TABLE [".$tablas[$i]."] ADD [".$columnas[$j]."] ".$origen[$tablas[$i]][$columnas[$j]]['Tipo']." (".$origen[$tablas[$i]][$columnas[$j]]['Tamanio'].") ".$origen[$tablas[$i]][$columnas[$j]]['Null'].";\n";
        }
      }
    }
  }
}

//ahora chequeo al reves!

$tablas=(array_keys($destino));
for ($i=0;$i<count($tablas);$i++){
  //me fijo que exista en destino:
  if(!array_key_exists($tablas[$i],$origen)){
    echo "tabla ".$tablas[$i]." no existe en origen==> debo dropear\n";
  } else {
    //si existe, asique habra que verificar las columnas!
    $columnas=(array_keys($destino[$tablas[$i]]));
    for($j=0;$j<count($columnas);$j++){
      //me fijo que exista!
      if(!array_key_exists($columnas[$j],$origen[$tablas[$i]])){
        $DROPCOLUMN.= "ALTER TABLE [".$tablas[$i]."] DROP COLUMN [".$columnas[$j]."];\n";
      }
    }
  }
}

echo $ADDCOLUMN."\n";
echo $DROPCOLUMN."\n";
echo $ALTERCOLUMN."\n";
?>

Leave a Reply