Convertisseur Oracle SQLite

 

Kroc - 18 Octobre 2006 : Avec le script ci-dessous, vous pourrez importer une table Oracle dans une table SQLite.


La version 1.x a été élaborée et testée avec :


    ################################################################################
    #
    # Convertisseur de table Oracle vers SQLite
    #
    # Copyright © 2006 - David Zolli http://www.zolli.fr
    #
    # Ce script est sous licence NOL : http://wfr.tcl.tk/NOL
    #
    ################################################################################
    #
    # Historique des révisions :
    #
    #    18 Octobre 2006    : Version 1.0
    #    19 Octobre 2006    : Version 1.1 - Ajout du support des types
    #
    ################################################################################
    #
    # Utilisation :
    #
    #     updateOracle Matable primary_key fichierSQL oraUSER oraPWD oraSID
    #
    # Avec :
    #
    #    - Matable       = le nom de la table à transférer
    #    - primary_key   = le nom de la clé selon laquelle la table est indexée
    #    - fichierSQL    = le nom du fichier de base de données SQLite
    #    - oraUSER       = le nom d'utilisateur Oracle
    #    - oraPWD        = le mot de passe Oracle pour oraUSER
    #    - oraSID        = le SID Oracle auquel se connecter
    #
    ################################################################################

    # à adapter selon votre propre installation d'Oracle instant client :
    if {![info exists ::env(ORACLE_HOME)} {
        set ::env(ORACLE_HOME) [file normalize ~/Oracle_8.1.7.1_Client]
    }

    # Ne rien modifier en dessous de cette ligne.

    package require -exact sqlite3 3.2.8
    package require Oratcl

    proc updateOracle {Matable primary_key fichierSQL oraUSER oraPWD oraSID} {

        # Connexion au serveur :
        if {![catch "oralogon ${oraUSER}/${oraPWD}@${oraSID}" lda] &&
            ![catch "oraopen $lda" sth]} {
            puts "Connecté.."

            # Initialisation de la table SQLite si elle n'existe pas déjà :
            if {![file exists $fichierSQL]} {
                # Structure de la table Oracle :
                set oracle_desc [oradesc $lda $Matable]
                initDB $Matable $fichierSQL $oracle_desc $primary_key
            }

            # Récupération de la structure de la table SQLite :
            set listCols [getSTy $Matable $fichierSQL]

            # Récupération de la table Oracle :
            oraparse $sth "SELECT * FROM $Matable ORDER BY $primary_key"
            oraexec $sth

            # Traitement :
            set nblignes 0
            set fout [open ./tmp.csv w]
            while {[orafetch $sth -dataarray AR]==0} {
                incr nblignes
                # Conversion des données selon le type attendu :
                set values {}
                foreach col $listCols {
                    if {![info exists AR($col)]} {set AR($col) NULL}
                    switch -exact [lindex $::STy($col) 0] {
                        char {
                            # On ne conserve que la longueur définie dans la structure :
                            lappend values [string range $AR($col) 0 [lindex $::STy($col) 1]]
                        }
                        varchar -
                        real -
                        tinytext {
                            # On enlève les espaces inutiles :
                            lappend values [string trim $AR($col)]
                        }
                        timestamp {
                            # Conversion en Epoch :
                            if {![catch "clock scan $AR($col)" tstamp]} {
                                lappend values $tstamp
                            } else {
                                lappend values [clock second]
                            }
                        }
                    }
                }
                puts $fout [join $values \t]

                # Affichage / log :
                if {![expr {$nblignes%50}]} {
                    puts stdout ".\t$nblignes" ; flush stdout
                } elseif {![expr {$nblignes%10}]} {
                    puts -nonewline stdout ". " ; flush stdout
                } else {
                    puts -nonewline stdout . ; flush stdout
                }
            }

            # Déconnexion :
            oraclose $sth
            oralogoff $lda
            close $fout

            if {$nblignes} {
                puts stdout "\n$nblignes fiches récupérées."
                updateSQLite $Matable $fichierSQL
            } else {
                puts stdout "Aucune nouvelle fiche."
            }
        } else {
            # Echec :
            puts stdout "La connexion a échouée."
        }
    }

    # Création d'une nouvelle base de données SQLite si elle n'existe pas encore :
    proc initDB {Matable fichierSQL oracle_desc primary_key} {
        # Initialisation de la base SQLite :
        sqlite3 DB $fichierSQL

        # Structure de la table SQLite à partir de la structure Oracle :
        set struct {}
        foreach l $oracle_desc {
            foreach "nom taille type A B C" $l {
                switch -exact $type {
                    CHAR     {set TY char      ; set TA "($taille)"}
                    VARCHAR2 {set TY varchar   ; set TA "($taille)"}
                    NUMBER   {set TY real      ; set TA ""}
                    DATE     {set TY timestamp ; set TA ""}
                    default  {set TY tinytext  ; set TA ""}
                }
                if {$nom eq $primary_key} {
                    lappend struct "$nom $TY $TA PRIMARY KEY"
                } else {
                    lappend struct "$nom $TY $TA"
                }
            }
        }
        eval DB eval [list "CREATE TABLE [set Matable]([join $struct ", "])"]
        DB close
        puts "Table $Matable créée à partir de la structure suivante :"
        puts $oracle_desc
    }

    # Récupération de la structure des types d'une table (dans un tableau global) :
    proc getSTy {Matable fichierSQL} {
        unset -nocomplain ::STy
        set ordre {}
        # Récupération de la structure de la table SQLite :
        sqlite3 DB $fichierSQL
        set R [DB eval [list SELECT sql FROM SQLITE_MASTER WHERE name='$Matable']]
        DB close
        set R [string range $R [expr {[string first ( $R]+1}] [expr {[string last ) $R]-1}]]
        foreach v [split $R ,] {
            foreach "nom type taille P K" $v {
                lappend ordre $nom
                set ::STy($nom) [list $type [string map {( "" ) ""} $taille]]
            }
        }
        return $ordre
    }

    # Met à jour une table SQLite avec un CSV :
    proc updateSQLite {Matable fichierSQL} {
        set rec 0
        if {[file exists $fichierSQL] && [file exists ./tmp.csv]} {
            # Mise à jour avec "copy" (ne marche qu'avec SQlite 3.2.8) :
            sqlite3 DB $fichierSQL
            set rec [DB copy REPLACE $Matable ./tmp.csv "\t" "NULL"]
            DB close
            # Le fichier a été traité, on peut l'effacer :
            file delete -force ./tmp.csv
        }
        puts "$rec fiches ajoutées à la base SQLite."
        return
    }

Catégorie Exemple