Migration d’une base DB2 8.2 sur AIX vers 9.5 sur Linux

 

Note Technique

Date

Classement

 

Page

1/6

Rédacteur :

Fabrice SCEMAMA

 

Historique

Version

Date

Modifications

1.0

25/03/2009

Version Initiale

1.1

31/03/2009

Modification du script d'import / load des IXF, rapport listant les rejets

1.2

02/04/2009

Prise en charge des tables en rejet

1.3

17/04/2009

Ajout de scripts perl destinés à contrôler l'intégrité des tables réimportées.

Précision du codeset sur create database, et intérêt.

1.4

21/04/2009

Amélioration des scripts de contrôle et de correction des imports , paramètres de tuning nécessaires à un import massif.

 

 

I. Objectifs et périmètre du document

Ce document couvre la migration d'une base de données située sur une instance DB2 8.2 fonctionnant sur AIX, vers une instance DB2 9.5 fonctionnant sur Linux. On se base sur la configuration obtenue à l'issue de l'application des étapes mentionnées dans les documents « Installation et Administration de Linux Fedora 10 (sur vm) » et « Installation de DB2 9.5 Workgroup Edition sur Linux Fedora 10 ».

La base de données de test utilisée est DBSIEB, située sur le serveur SRVDB1. C'est une base Siebel.

Ne sont pas couverts les aspects liés au tuning et au backup.

II. Export des données sur AIX (DB2 8.2)

 

telnet SRVDB1

login => sadmin ; password => db2

 

Le répertoire /backup/formation a été chmoddé 0777 par le root pour les besoins de cette migration pilote. Prévoir de l'espace !

  • cd /backup/formation
  • mkdir dbsieb.`date +%Y%m%d`
  • cd dbsieb.`date +%Y%m%d`

Création d'un répertoire à la date du jour.

nohup db2move DBSIEB EXPORT -u siebel -p xxx >db2move.log 2>&1 &

Export des tables.

nohup db2look -d DBSIEB -e -a -l -x -xd –i siebel –w xxx -o dbsieb.ddl >db2look.log 2>&1 &

Export du schéma de la base (param. i pour le user, et w pour le mot de passe).

Note : sur le serveur DEV, où DB2 est installé sur Windows 2000, la commande db2look existait, mais pas la commande db2move. Le script suivant, qui nécessite un compilateur Perl, a remédié à la situation :

#!/usr/bin/perl -w
use strict;

my $DB = "HYPODEV";
my $USER = "siebel";
my $PASS = "xxx";
my $SCHEMA = "SIEBEL";
my $REP_EXPORT = "W:\\FScemama\\HYPODEV.20090504";

system("db2 connect to $DB user $USER using $PASS");
my $cmd = "db2 select tabname from syscat.tables where tabschema='$SCHEMA'";
my $out = `$cmd`;

my(@Tables) = ();
my(@lines) = split(/\n/, $out);
foreach(@lines)
{
    if(m/^[a-zA-Z]/)
    {
        my $T = $_;
        $T =~s/^\s*//;
        $T =~s/\s*$//;
        push(@Tables, $T);
    }
}

open(DB, ">$REP_EXPORT/db2move.lst");
for(my $i = 0; $i <= $#Tables; $i++)
{
    print "Export table $Tables[$i] ($i / $#Tables)\n";
    system("db2 export to $REP_EXPORT\\$Tables[$i].ixf of ixf messages

    $REP_EXPORT\\$Tables[$i].msg select * from $Tables[$i]");
    print DB "!\"$SCHEMA\".\"$Tables[$i]\"!$Tables[$i].ixf!$Tables[$i].msg!\n";
}
close(DB);

system("db2 connect reset");
system("db2 terminate");

Enregistrer ce fichier dans C:\temp\export.pl, puis exécuter C:\perl\bin\perl c:\temp\export.pl .

 

On obtient les mêmes fichiers IXF qu'avec db2move ; un fichier db2move.lst est créé, tel qu'attendu par les scripts d'import indiqués dans la suite de ce document.

 

III. Import des données vers Linux (DB2 9.5 Workgroup Edition)

  1. Préparation de l'environnement et création de la base

 

LIRE notes de droite avant exécution.

useradd siebel –p xxx

Il s'agit du user DB2 qui possèdera la base DBSIEB. Ce mot de passe devra être renforcé.

Si le serveur a été connecté à l'AD à l'aide de Samba, il ne faut pas créer ce user local, mais utiliser celui de l'AD (OU MonDomaine\ADM). Créé le 17/4/9, siebel@mondomaine.fr a pour mot de passe 'xxx990'.

mkdir /home/database

En attendant de pouvoir monter des répertoires du NAS.

ln -s /home /app

L'habitude ayant été prise de trouver le répertoire database dans /app … cette habitude pourrait être changée.

for i in 1 2 3 4 5 6; do mkdir /home/database/pgform0$i; done

Ces répertoires contiendront les tablespaces créés par l'application du fichier dbsieb.ddl créé précédemment.

chown -R db2inst1:db2grp1 /home/database

Donner au user dba le contrôle des répertoires contenant les tablespaces.

  • Si on utilise un compte siebel local :

cat <<eot >>/home/siebel/.bashrc
# The following three lines have been added by UDB DB2.
if [ -f /home/db2home/db2inst1/sqllib/db2profile ]; then
  . /home/db2home/db2inst1/sqllib/db2profile
fi
eot

mkdir /home/MONDOMAINE/siebel
cp /etc/skel/.* /home/MONDOMAINE/siebel
chown –R siebel /home/MONDOMAINE/siebel

cat <<eot >>/home/siebel/.bashrc
# The following three lines have been added by UDB DB2.
if [ -f /home/db2home/db2inst1/sqllib/db2profile ]; then
  . /home/db2home/db2inst1/sqllib/db2profile
fi
eot

Variables d'environnement pour notre nouvel user.

su – db2inst1
cat <<eot |db2
create database DBSIEB using codeset 1252 territory fr COLLATE USING IDENTITY
connect to DBSIEB
grant dbadm on database to user siebel
revoke connect on database from public
connect reset
quit
eot

Création de la DB DBSIEB, et grant de tous les droits au user siebel sur cette base.

 

/!\ Bien noter la syntaxe du CREATE DATABASE. En n'indiquant pas la spécificité française, on perd la gestion correcte des accents (qui occupent alors 3 chars au lieu d'un seul, compromettant par la suite l'insertion de nombreuses lignes). L'option COLLATE USING IDENTITY est une spécificité nécessaire à Siebel.

 

2. Adaptation du schéma aux spécificités de DB2 9.5

Le fichier dbsieb.ddl obtenu précédemment ne peut être appliqué tel quel.

Modifications indispensables :

 

3. Création du schéma

 

su – db2inst1

 
  • mount.cifs //rue-wsas01/f\$ /mnt/smbfs -o username=mondomaine\\adm-scemama

On a choisi de monter un partage réseau, par manque d'espace local.

cd /mnt/smbfs/FScemama
mkdir dbsieb.`date +%Y%m%d`
cd dbsieb.`date +%Y%m%d`

Création d'un répertoire à la date du jour.

  • lftp SRVDB1 -u sadmin,db2 -e "cd /backup/formation/dbsieb.`date +%Y%m%d`;mget *;bye"

Récupération des fichiers d'export de SRVDB1, par FTP.

db2 -vtf dbsieb.ddl >/tmp/importDDL.log 2>&1

Création du schéma. Vérifier le fichier de log.

cat <<eot |db2
connect to dbsieb
get db cfg
connect reset
quit
eot

Permet de connaître les valeurs de tuning par défaut de la base.

cat <<eot |db2
update db cfg for DBSIEB using LOGPRIMARY 30
update db cfg for DBSIEB using LOGSECOND 100
update db cfg for DBSIEB using LOGFILSIZ 8192
update db cfg for DBSIEB using LOGBUFSZ 1024
quit
eot

Ajustements destinés à faciliter les insertions massives.

 

Requiert 1,7 Go dans /home/db2home/.

Par défaut, DB2 alloue un nombre spécifique de pages de 4 Ko pour la mise en mémoire tampon et la mise en mémoire cache des données et des index. Cette valeur peut varier en fonction du système d'exploitation concerné, mais elle est en général égale à 1 000 pages (ou à 4 Mo d'espace de pool de mémoire tampon). Le paramètre bufferpool peut être utilisé pour le stockage de grandes quantités de données et d'index au sein de mémoires physiques, ce qui permet de réduire la quantité nécessaire de pagination de et vers l'espace de stockage. En règle générale, vous pouvez affecter un maximum de 80 pour cent de mémoire disponible à une utilisation au sein de pools de mémoire tampon.

 

Un bufferpool IBMDEFAULTBP de 128000 permet d'augmenter la taille du pool de mémoire tampon PAR DEFAUT à 512 Mo de mémoire. Nous mettons 32768.

cat <<eot |db2
connect to dbsieb
SELECT * FROM SYSCAT.BUFFERPOOLS
ALTER BUFFERPOOL IBMDEFAULTBP DEFERRED SIZE 32768
connect reset
eot
su – root
/etc/rc.d/init.d/db2 restart

Applique les changements opérés précédemment sur la configuration de la DB.

 

4. Importation des tables

Démarche : normalement, on aurait dû être en mesure d'importer toutes les tables, telles qu'indiquées dans le fichier « db2move.lst », par la seule commande « db2move DBSIEB IMPORT -io REPLACE_CREATE ».

Toutefois, cette commande échouerait pour toutes les tables contenant des colonnes avec identity (i.e. des séquences). Référence IBM : voir le Data Movement Utilities Guide and Reference.

Une première approche consiste à lancer, pour chaque table, une commande de type « db2 import from tab10.ixf of ixf modified by identityignore insert into eim_account ». Toutefois, cette méthode a pour effet d'ignorer le champ devant s'incrémenter automatiquement ; la DB le fait donc commencer à 1, et l'incrémente elle-même au fil de l'import. Cette méthode n'est pas utilisable : elle rendrait la base de données incohérente.

La seconde approche, telle que préconisée par IBM, consiste finalement, pour chaque table, à :

/!\ Ce n'est toutefois pas suffisant. Tel qu'énoncé, nous créerions par exemple une séquence commençant à 1, et chargerions des valeurs situées par exemple entre 10000 et 20000. Mais, toute future insertion verrait la valeur 1 affectée à la colonne identity, puis 2, etc. jusqu'à 10000 ! et nous aboutirions à des doublons. La solution coniste donc, en plus de ce qui précède, à modifier le schéma (dbsieb.ddl), de sorte qu'une query comportant par exemple.. :

CREATE TABLE "SIEBEL "."EIM_ACC_SRC_DTL" (
         "MS_IDENT" DECIMAL(15,0) NOT NULL GENERATED ALWAYS AS IDENTITY (
         START WITH +1
         INCREMENT BY +1
         MINVALUE +1
         MAXVALUE +999999999999999
         NO CYCLE
         CACHE 20
         NO ORDER ) ,
         "ROW_ID" VARCHAR(15) NOT NULL ,

 

Soit rectifiée avec un START WITH commençant soit à MAX(MS_IDENT) + 1 (qui serait à récupérer au moment de l'import), soit plus simplement à une valeur suffisamment haute => par exemple « +199999999999999 ». On choisit cette dernière option.

Ccncrètement, il faut donc coder un script destiné à parser le fichier « db2move.lst », afin d'y récupérer chaque nom de table exportée, et le nom du fichier IXF correspondant. Puis, pour chaque table, exécuter les commandes précédemment exposées.

A noter que le script suivant peut être amélioré ; cela pourrait être une bonne idée de ne créer les indices qu'après l'import et la mise en production, au moins pour accélérer le temps d'import.

cat <<"eot" >/tmp/load.pl
#!/usr/bin/perl -w
use strict;

system("db2 connect to dbsieb user siebel using xxx990");
open(DB, "db2move.lst") || die "Cant find db2move.lst";
while(<DB>)
{
  # Ex.:
  # !"SIEBEL "."EIM_ACC_SRC_DTL"!tab1.ixf!tab1.msg!
  #
  my(@F) = split(/\!/, $_);

  # For these commands, ["siebel "."table"] should be transformed
  # into [table]. Still a mystery to me.
  #
  if($F[1] =~/\"[^\"]+\"\.*\"[^\"]+\"/)
  {
    $F[1] =~s/^(.*)\"[^\"]+\"\.*\"([^\"]+)\"(.*)$/$1$2$3/;
  }

  print "————————————\n";
  print "Table [$F[1]] / [$F[2]]\n";

  # Delete from the table
  #
  Cleanup($F[1]);

  my $cmd = "db2 delete from $F[1]";
  print "Query: [$cmd]\n";
  my $out = `$cmd 2>&1`;
  $out =~s/^\s*//; $out =~s/\s*$//;
  print "[$out]\n";

  Commit();

  # CREATE TABLE "SIEBEL "."EIM_ACC_SRC_DTL" (
  #         "MS_IDENT" DECIMAL(15,0) NOT NULL GENERATED ALWAYS AS IDENTITY (
  # …
  # ) ;
  #
  my $Ident = 0;
  if(-e "./dbsieb.ddl")
  {
    my $flag = 0;
    open(DDL, "dbsieb.ddl");
    while(<DDL>)
    {
     if(m/create\s*table/i && m/\"$F[1]\"/i)
     {
        ++ $flag;
        next;
     }
     if($flag)
     {
        if(m/\;\s*$/)
        {
         last;
        }
        if(m/GENERATED\s*ALWAYS\s*AS\s*IDENTITY/i)
        {
         ++ $Ident;
        }
      }
    }
    close(DDL);
  }
  print "Identities: [$Ident] (table $F[1])\n";

  # Now, try to load data (schema not included; will fail if identity columns)
  #
  my(@ff) = ('read', 'inserted', 'rejected');
  my(%res) = ();

  unless($Ident)
  {
    # $cmd = "db2 import from $F[2] of ixf insert into $F[1]";
    $cmd = "db2 load from $F[2] of ixf insert into $F[1] nonrecoverable";
    print "Query: [$cmd]\n";
    $out = `$cmd 2>&1`;
    $out =~s/^\s*//; $out =~s/\s*$//;
    print "Out: [$out]\n";

    # This is a failure:
    # Number of rows read = 100
    # Number of rows skipped = 0
    # Number of rows inserted = 0
    # Number of rows updated = 0
    # Number of rows rejected = 100
    # Number of rows committed = 100
    #
    my(@lines) = split(/\n/, $out);
    foreach my $L (@lines)
    {
     $L =~s/^\s*//;
     if($L =~/Number of rows/i)
     {
        $L =~s/^Number of rows //i;
        my $tmp = $L;
        $tmp =~s/\s.*$//;
        foreach my $f (@ff)
        {
         if($f eq $tmp)
         {
            $res{$f} = $L;
            $res{$f} =~s/\D//g;
         }
        }
      }
    }

    Cleanup($F[1]);
  }

  foreach(@ff)
  {
    $res{$_} = 0 unless(defined($res{$_}) && $res{$_} =~/^\d+$/);
    print " [$_]: [$res{$_}]\n";
  }

  if($Ident || ($res{read} == $res{rejected} && $res{rejected} > 0 && $res{inserted} == 0))
  {
    $cmd = "db2 load from $F[2] of ixf modified by IDENTITYOVERRIDE"
     ." insert into $F[1] nonrecoverable";
    print "Query: [$cmd]\n";
    $out = `$cmd 2>&1`;
    $out =~s/^\s*//; $out =~s/\s*$//;
    print "[$out]\n";

    Cleanup($F[1]);
  }

  # Track partial rejections
  #
  if($res{rejected} > 0 && $res{inserted} > 0)
  {
    open(OUT, ">>/tmp/reject");
    print OUT "Table: $F[1] Rejected: $res{rejected} Inserted: $res{inserted}\n";
    close(OUT);
  }

  print "Date: [".Date()."]\n";
}
close(DB);
system("db2 connect reset");

sub Date
{
  my $D = `date`;
  $D =~s/\s$//;
  return($D);
}

sub Commit
{
  my $cmd = "db2 commit";
  print "Query: [$cmd]\n";
  my $out = `$cmd 2>&1`;
  $out =~s/^\s*//; $out =~s/\s*$//;
  print "[$out]\n";
}

sub Cleanup
{
  my $T = shift || '';
  return() unless($T);

  my $cmd = "db2 load from /dev/null of del terminate into $T";
  print "Query: [$cmd]\n";
my $out = `$cmd 2>&1`;
$out =~s/^\s*//; $out =~s/\s*$//;
print "Out: [$out]\n";

$cmd = "db2 set integrity for $T immediate checked";
print "Query: [$cmd]\n";
$out = `$cmd 2>&1`;
$out =~s/^\s*//; $out =~s/\s*$//;
print "Out: [$out]\n";
}
eot

Création, toujours en tant que user siebel et depuis le répertoire contenant notre export, du script perl destiné à importer les tables.

 

Les tables dont l'import a engendré un rejet partiel sont mentionnées dans le fichier /tmp/reject .

chmod 0755 /tmp/load.pl

Droits d'exécution.

/tmp/load.pl >/tmp/importTables.log 2>&1

Import. Vérifier le log.

 

Dans notre cas, un fichier /tmp/reject a été créé, contenant les informations suivantes :

Table: S_BITMAP_INTL Rejected: 472 Inserted: 9428
Table: S_BUSCOMP Rejected: 5 Inserted: 44915
Table: S_CHART_INTL Rejected: 32 Inserted: 3147
Table: S_CS_QUEST Rejected: 1041 Inserted: 2003
Table: S_DEFAULT_ADMIN Rejected: 71 Inserted: 1663
Table: S_DOC_PPSL Rejected: 4 Inserted: 259
Table: S_DOC_PPSL_BU Rejected: 4 Inserted: 41
Table: S_ESCL_GROUP Rejected: 1 Inserted: 26

 

De manière générale, on a pris soin d'écrire un autre script, destiné à comparer d'une part les tables présentes sur la base source et la base destination, et d'autre part, pour chaque table, le nombre de lignes :

cat <<"eot" >/tmp/check_imp_exp.pl
#!/usr/bin/perl -w
use strict;
use DBI;

if(-e "$0.log")
{
  my $cnt = 0;
  while(-e "$0.log.$cnt")
  {
    ++ $cnt;
  }
  for(my $i = $cnt – 1; $i >=0; $i–)
  {
    if(-e "$0.log.$i")
    {
      rename("$0.log.$i", "$0.log.".($i + 1));
    }
  }
  rename("$0.log", "$0.log.0");
}
open(LOG, ">$0.log");

LOG("Connection to the Source DB");
my $dbh = DBI->connect('dbi:DB2:DATABASE=dbsieb;HOSTNAME=SRVDB1;'
         .'PORT=50000;PROTOCOL=TCPIP;', "siebel", "xxx",
         { LongReadLen => 102400 })
  || die(" Error in connecting to the Source DB");

LOG("Connection to the Target DB");
my $dbh2 = DBI->connect("dbi:DB2:dbsieb", "siebel", "xxx990",
            { LongReadLen => 102400 })
  || die(" Error in connecting to the Target DB");

my(@Tables_S) = $dbh->tables();
my(@Tables_T) = $dbh2->tables();

LOG("Checking that all Source Tables are available on the Target DB");

my(@Tables_S_NoMissing) = ();
my(@Missing_Tables) = ();
foreach my $TS (@Tables_S)
{
  my $flag = 0;
  foreach my $TT (@Tables_T)
  {
    if(lc($TS) eq lc($TT))
    {
      ++ $flag;
      last;
    }
  }
  if($flag)
  {
    push(@Tables_S_NoMissing, $TS)
  }
  else
  {
    push(@Missing_Tables, $TS);
  }
}
foreach(@Missing_Tables)
{
  LOG(" Missing: $_");
}

LOG("Comparing each table for the number of rows");

foreach my $TS (@Tables_S_NoMissing)
{
  my $sth = $dbh->prepare("SELECT COUNT(1) FROM $TS");
  $sth->execute;
  my($cnt) = $sth->fetchrow_array || 0;
  $sth->finish;

  my $sth2 = $dbh2->prepare("SELECT COUNT(1) FROM $TS");
  $sth2->execute;
  my($cnt2) = $sth2->fetchrow_array || 0;
  $sth2->finish;

  LOG(" ".($cnt != $cnt2 ? "!!!":"")." $TS $cnt $cnt2");
}

LOG("Disconnecting from the Target DB");
$dbh2->disconnect();

LOG("Disconnecting from the Source DB");
$dbh->disconnect();

close(LOG);

sub IsNum
{
  my $T = shift || 0;
  if($T =~/^(2|3|4|5|6|7|8|-5|-6)$/)
  {
    return(1);
  }
  return(0);
}

sub IsTime
{
  my $T = shift || 0;
  if($T =~/^(93)$/)
  {
    return(1);
  }
  return(0);
}

sub To_FR
{
  my $T = shift || '';

  $T =~s/Ã\(c\)/é/g;
  $T =~s/àª/è/g;
  $T =~s/è/ê/g;
  $T =~s/àª/ê/g;

  $T =~s/Ã/à/g;

  return($T);
}

sub LOG
{
  my $msg = shift || '';
  print "$msg\n";
  print LOG "$msg\n";
}
eot

Logs : fichier check_imp_exp.pl.log .

chmod 0755 /tmp/check_imp_exp.pl

Droits d'exécution.

cd /tmp ; ./check_imp_exp.pl &

Vérifier le log.

 

Corrections à appliquer :

Pour les tables incomplètes, il a été nécessaire d'écrire un script comparant, pour chacune d'entre elles, le contenu source et le contenu destination, et procédant aux insertions nécessaires.

Les erreurs renvoyées par le script ont permis de détecter deux types de problèmes :

Le script suivant doit donc…

Moyennant quoi, l'intégralité des rejets est traitée avec succès.

Notes :

 

cat <<"eot" >/tmp/sync_rejects.pl
#!/usr/bin/perl -w
use strict;
use DBI;

if(-e "$0.log")
{
  my $cnt = 0;
  while(-e "$0.log.$cnt")
  {
    ++ $cnt;
  }
  for(my $i = $cnt – 1; $i >=0; $i–)
  {
    if(-e "$0.log.$i")
    {
      rename("$0.log.$i", "$0.log.".($i + 1));
    }
  }
  rename("$0.log", "$0.log.0");
}
open(LOG, ">$0.log");
LOG("Date: ".Date());

my($Reject_File) = @ARGV;
$Reject_File = "/tmp/reject" unless(defined($Reject_File));

my(@Tables) = ();
if(-e $Reject_File)
{
  open(DB, $Reject_File);
  while(<DB>)
  {
    next if(m/^\#/);
    my(@f) = split(/ /, $_);
    next unless(defined($f[1]));
    $f[1] =~s/\s*$//;
    next unless($f[1]);
    push(@Tables, $f[1]);
  }
  close(DB);
  LOG("Tables en rejet:");
  foreach(@Tables)
  {
    LOG(" [$_]");
  }
}
else
{
  die "Couldn't find file [$Reject_File]";
}

my $dbh = DBI->connect('dbi:DB2:DATABASE=dbsieb;HOSTNAME=SRVDB1;'
         .'PORT=50000;PROTOCOL=TCPIP;', "siebel", "xxx",
         { LongReadLen => 102400 });

my $dbh2 = DBI->connect("dbi:DB2:dbsieb", "siebel", "xxx990",
            { LongReadLen => 102400, AutoCommit => 0 });

foreach my $Table (@Tables)
{
  LOG();
  LOG("Table [$Table]");
  LOG(" Date: ".Date());

  # Getting field names and types
  #
  my $sth = $dbh->prepare("SELECT * FROM $Table WHERE 1=0");
  $sth->execute();
  my @fields = @{ $sth->{NAME} };
  my @types = @{ $sth->{TYPE} };
  $sth->finish;
  # LOG(" Colonnes:");
  for(my $i = 0; $i <= $#fields; $i++)
  {
    #LOG(" [$fields[$i]] [$types[$i]]");
  }

  # Querying the source table,
  # inserting into the target table
  #
  my $query = "SELECT * FROM $Table";
  # LOG(" Query 1: [$query]");
  $sth = $dbh->prepare($query);
  $sth->execute;

  my $intQ = 0;
  my $intI = 0;
  while(my(@row) = $sth->fetchrow_array)
  {
    # Give us an idea about speed!
    #
    if(($intQ / 1000) == int($intQ / 1000))
    {
      LOG(" Query nb [$intQ]");
      LOG(" Date: ".Date());
    }
    ++ $intQ;

    # Clean up problematic fields. In the source DBSIEB's BUSCOMP
    # table, a decimal field had null entries, thus preventing 5
    # rows from being imported by db2 import. Futhermore, some
    # timestamp-typed fields had no value, causing the same pb.
    #
    for(my $i = 0; $i <= $#row; $i++)
    {
      unless(defined($row[$i]))
      {
        if(IsNum($types[$i]))
        {
          $row[$i] = 0;
        }
        elsif(IsTime($types[$i]))
        {
          $row[$i] = '1911-11-11 11:11:11.000000';
        }
        else
        {
          $row[$i] = '';
        }
      }
      #LOG(" [$fields[$i]] [$types[$i]] [$row[$i]]");
    }

    # Find out if the same row exists in the target table.
    #
    my $query2 = "
      SELECT count(1)
      FROM $Table
      WHERE ";
    my $flag = -1;
    for(my $i = 0; $i <= $#fields; $i++)
    {
      if($fields[$i] =~/^row_id$/i)
      {
        $flag = $i;
        last;
      }
    }
    if($flag > -1)
    {
      $query2 .= "row_id = "
        .(IsNum($types[$flag])?$row[$flag]:$dbh->quote($row[$flag]));
    }
    else
    {
      for(my $i = 0; $i <= $#fields; $i++)
      {
        $query2 .= "$fields[$i] = "
         .(IsNum($types[$i])?$row[$i]:$dbh->quote($row[$i]))."\nAND ";
      }
      $query2 =~s/AND $//;
    }
    #LOG(" Query 2: [$query2]");
    my $sth2 = $dbh2->prepare($query2);
    $sth2->execute;
    my($cnt) = $sth2->fetchrow_array || 0;
    $sth2->finish;
    #LOG(" Cnt: [$cnt]");

    # Not found in the target table, then insert.
    #
    if($cnt == 0)
    {
      my $query3 = "
        INSERT INTO $Table
        (".join(', ', @fields).")
            VALUES
        (";
      for(my $i = 0; $i <= $#fields; $i++)
      {
        $query3 .= (IsNum($types[$i])?$row[$i]:$dbh->quote($row[$i])).", ";
      }
      $query3 =~s/\, $//;
      $query3 .= ")";
      $query3 = To_FR($query3);
      #LOG(" Query 3: [$query3]");
      $dbh2->do($query3) || LOG("!!! Echec query: [$query3]");
      ++ $intI;

      if(($intI / 1000) == int($intI / 1000))
      {
        $dbh2->commit();
        print "$intI inserts\n";
      }
    }
  }

  $dbh2->commit();
  LOG(" Fetched rows: [$intQ]");
  LOG(" Inserted rows: [$intI]");
  LOG(" Date: ".Date());
}

$dbh2->commit();
$dbh2->disconnect();
$dbh->disconnect();

LOG("Date: ".Date());
LOG("The end.");
close(LOG);

sub Date
{
  my $D = `date`;
  $D =~s/\s$//;
  return($D);
}

sub IsNum
{
  my $T = shift || 0;
  if($T =~/^(2|3|4|5|6|7|8|-5|-6)$/)
  {
    return(1);
  }
  return(0);
}

sub IsTime
{
  my $T = shift || 0;
  if($T =~/^(93)$/)
  {
    return(1);
  }
  return(0);
}

sub To_FR
{
  my $T = shift || '';

  $T =~s/Ã\(c\)/é/g;
  $T =~s/àª/è/g;
  $T =~s/è/ê/g;
  $T =~s/àª/ê/g;

  $T =~s/Ã/à/g;

  return($T);
}

sub LOG
{
  my $msg = shift || '';
  print "$msg\n";
  print LOG "$msg\n";
}

__END__

* SQL_CHAR 1
* SQL_NUMERIC 2
* SQL_DECIMAL 3
* SLQ_INTEGER 4
* SQL_SMALLINT 5
* SQL_FLOAT 6
* SQL_REAL 7
* SQL_DOUBLE 8
* SQL_DATE 9
* SQL_TIME 10
* SQL_TIMESTAMP 11
* SQL_VARCHAR 12
* SQL_LONGVARCHAR -1
* SQL_BINARY -2
* SQL_VARBINARY -3
* SQL_LONGVARBINARY -4
* SQL_BIGINT -5
* SQL_TINYINT -6
* SQL_BIT -7
* SQL_WCHAR -8
* SQL_WVARCHAR -9
* SQL_WLONGVARCHAR -10
eot

 

chmod 0755 /tmp/sync_rejects.pl

Droits d'exécution.

cd /tmp; ./sync_rejects.pl &

Vérifier le log, dans sync_rejects.pl.log.

 

5. Divers

Posted on février 20, 2011 at 9 h 05 min by Fabrice Scemama · Permalink
In: AIX, DB2 · Tagged with: , , , , , , ,

Leave a Reply

You must be logged in to post a comment.