menu
  Home  ==>  articles  ==>  bdd  ==>  interbase  ==>  ib_blob_extraction   

Interbase Blob Extraction - John COLIBRI.

  • résumé : utilitaire générant un Script SQL contenant les données de champs BLOB Interbase
  • mots clé : Blob - Binary Large Object - Interbase - Script SQL
  • logiciel utilisé : Windows XP personnel, Delphi 6.0, Interbase 6
  • matériel utilisé : Pentium 2.800 Mhz, 512 Meg de mémoire, 250 Giga disque dur
  • champ d'application : Delphi 1 à 2006 sur Windows / Interbase
  • niveau : développeur Delphi
  • plan :


1 - Introduction

Pour pouvoir regénérer une base, le plus simple est de partir de son script SQL. Ce script permet en général de recréer la base sur des versions différentes du même moteur SQL, et, après quelques adaptations, de porter une base d'un moteur à un autre.

Nous avons déjà présenté comment extraire un script SQL pour les champs autres que les champs Blobs.

Nous allons présenter ici comment construire un script contenant les valeurs de champs BLOB Ascii.




2 - Principe

2.1 - Ecriture de Blob

La gestion des Blobs Interbase a été présentée en grand détail dans l'article cité.

Dans notre cas, notre but est d'obtenir un script qui permettra d'insérer dans une Table ayant un ou plusieurs champs Blob des lignes contenant la valeur des champs Blob ou non.

Prenons la table suivante (partie de PROJECT de EMPLOYEE.GDB) définie par:

 
CREATE TABLE PROJECT
  (
    PROJ_ID CHAR(5),
    PROJ_NAME VARCHAR(20),
    PROJ_DESC BLOB SUB_TYPE TEXT SEGMENT SIZE 800
  )

Pour insérer les deux premiers champs, nous pouvons utiliser le script:

 
INSERT INTO PROJECT 
  (PROJ_IDPROJ_NAME
  VALUES ('VBASE', 'Video Database')

et pour utiliser cette requête en Delphi, nous plaçons cette requête dans un IbSql, et l'envoyons au moteur:

PROCEDURE insert_into;
  BEGIN    
    WITH IbQuerySql DO
    BEGIN
      Clear;
      Add('INSERT INTO PROJECT'); 
      Add('  (PROJ_ID, PROJ_NAME)'); 
      Add('  VALUES (''VBASE'', ''Video Database'')' );

      ExecQuery;
    END// WITH IbQuery, Sql
  END// insert_into



Pour ajouter une ligne avec une valeur de Blob, le script serait, par exemple:

 
INSERT INTO PROJECT 
  (PROJ_IDPROJ_NAMEPROJ_DESC
  VALUES ('VBASE', 'Video Database', 'Design a video data base management system')

mais nous ne pouvons pas envoyer la requête telle quelle au moteur. Il faut utiliser une requête paramétrée et un tStream:

procedure insert_into_with_stream;
  var l_c_string_streamtStringStream;
  begin
    l_c_string_stream:= tStringStream.Create(
        'Design a video data base management system');

    with IbQuery1Sql do
    begin
      Clear;

      Add('INSERT INTO PROJECT');
      Add('  (PROJ_ID, PROJ_NAME, PROJ_DESCRIPTION)');
      Add('  VALUES (''VBASE'', ''Video Database'', :PROJ_DESCRIPTION)' );

      ParamByName('PROJ_DESCRIPTION').LoadFromStream(l_c_string_streamftMemo);

      ExecQuery;
    end// with Query1, Sql

    l_c_string_stream.Free;
  end// insert_with_stream

Par conséquent

  • le script pour une table ayant des Blobs est identique à celui d'une table sans Blob
  • l'envoi de la requête INSERT INTO elle est différente. Mais dans cet article nous nous préoccupons surtout de la génération de la requête. L'article qui suit script ajoutant des blobs indiquera comment envoyer les requêtes vers le moteur


2.2 - Récupération de la valeur d'un Blob

La récupération de la valeur d'un Blob nécessite cependant l'utilisation d'un tStream. Pour récupérer la valeur du champ PROJ_DESCRIPTION, nous utilisons:

procedure select_blob_value;
  var l_c_memory_streamtMemoryStream;
  begin
    l_c_memory_stream:= tMemoryStream.Create;

    with IbQuery1Sql do
    begin
      Close;
      Clear;
      Add('SELECT proj_description');
      Add('  FROM PROJECT');
      Add('  WHERE PROJ_N0= 101');

      Open;

      (FieldByName('proj_description'as tBlobField)
          .SaveToStream(l_c_memory_stream);
    end// with Query1, Sql

    // -- use the l_c_memory_stream content
    l_c_memory_stream.Position:= 0;
    // -- ...
  end// select_blob_value



2.3 - Analyse d'une Base

Pour générer un script contenant les valeurs littérales des Blob, il faut:
  • détecter quelles tables contiennent des champs blobs
  • générer la requête INSERT INTO en extrayant la valeur littérale
    • par tField.AsString pour les champs non Blobs
    • à l'aide d'un tStream pour les champs Blobs
Notre utilitaire va créer le script uniquement pour les Tables contenant des Blobs. Pour arriver à détecter ces Tables
  • nous calculons le nom de toutes les Tables utilisateur d'une base par la requête

     
    SELECT rdb$relation_name
      FROM rdb$relations
      WHERE
          (
             (rdb$system_flag = 0)
            OR
              (rdb$system_flag IS NULL)
           )
         AND
          (rdb$view_source IS NULL)
      ORDER BY rdb$relation_name

  • pour chaque Table, nous devrons utiliser un IbQuery pour récupérer les valeurs littérales. Nous utilisons alors cet IbQuery pour analyser les tFieldDefs, dont la propriété DataType permet de détecter les champs Blob



3 - Le Projet Delphi

3.1 - La classe d'extraction

La classe qui extrait la valeur littérale et construit la requête INSERT INTO est définie par

c_ib_blob_script_extractor=
    class(c_basic_object)
      m_c_ibdatabase_reftibDatabase;
      m_c_result_scripttStringList;

      Constructor create_ib_blob_script_extractor(p_nameString;
          p_c_ibdatabase_reftIbDatabase);
      procedure extract_script(p_table_nameString);

      Destructor DestroyOverride;
    end// c_ib_blob_script_extractor

Et:

  • La procédure extract_script, récupère le début de la requête, puis récupère toutes les lignes:

    procedure c_ib_blob_script_extractor.extract_script(p_table_nameString);
      var l_c_ibquerytIbQuery;

      // -- procedure open_table;
      // -- procedure build_start_insert_into_request;
      // -- procedure generate_script;

      begin // extract_script
        m_c_result_script.Free;
        m_c_result_script:= tStringList.Create;

        open_table;
        // -- get the table fields
        build_start_insert_into_request;
        generate_script;
      end// extract_script

  • la construction de la partie fixe de INSERT INTO est obtenue par:

    var l_insert_intoString;

    procedure build_start_insert_into_request;
      var l_field_def_indexInteger;
          l_field_name_listString;
      begin
        l_field_name_list:= '';

        with l_c_ibqueryFieldDefs do
          for l_field_def_index:= 0 to Count- 1 do
            with FieldDefs[l_field_def_indexdo
            begin
              l_field_name_list:= l_field_name_listName;
              if l_field_def_indexCount- 1
                then l_field_name_list:= l_field_name_list', ';
            end;
        l_insert_into:= 'INSERT INTO 'p_table_name
            + ' ('l_field_name_list' ) ';

        display(l_insert_into);
      end// build_start_insert_into_request

  • et la procédure qui récupère la partie VALUES de chaque INSERT INTO est:

    procedure generate_script;

      procedure generate_the_script;
          // -- generate the values for the current line
        var l_field_indexInteger;
            l_valuesString;

            l_c_string_streamtStringStream;
        begin
          l_values:= '';

          with l_c_ibqueryFieldDefs do
            for l_field_index:= 0 to Count- 1 do
            begin
              case FieldDefs[l_field_index].DataType of
                ftBlob :
                  begin
                    // l_c_field_value.m_c_stream:= tMemoryStream.Create;
                  end;
                ftMemo :
                  begin
                    l_c_string_stream:= tStringStream.Create('');
                    (Fields[l_field_indexas tMemoField)
                        .SaveToStream(l_c_string_stream);
                    l_values:= l_valuesQuotedStr(l_c_string_stream.DataString);
                    l_c_string_stream.Free;
                  end;

                ftString :
                    l_values:= l_valuesQuotedStr(Fields[l_field_index].AsString);
                ftSmallint :
                    l_values:= l_valuesFields[l_field_index].AsString;
                ftFloat :
                    l_values:= l_valuesFields[l_field_index].AsString;

                else
                  display(f_fieldtype_name(FieldDefs[l_field_index].DataType));
              end// case

              if l_field_indexCount- 1
                then l_values:= l_values', ';
            end// with l_c_ibquery, FieldDefs, for l_field_index

          with m_c_result_script do
          begin
            Add(l_insert_into);
            // -- append VALUES AND a script terminator
            Add('  VALUES ('l_values')' + ';');
          end;
        end// generate_the_script

      begin // generate_script
        with l_c_ibquery do
          while not Eof do
          begin
            generate_the_script;
            Next;
          end// with l_c_ibquery, while not eof
      end// generate_script




3.2 - Le programme principal

Le projet permet alors
  • de sélectionner la base
  • de lister le nom des tables
  • de rechercher quelles tables contiennent des Blobs:

    procedure TForm1.blob_table_names_Click(SenderTObject);
      var l_table_name_indexInteger;
          l_table_nameString;
      begin
        if g_c_tablename_listNil
          then table_names_Click(Nil);

        blob_table_name_listbox_.Items.Clear;
        with g_c_tablename_list do
          for l_table_name_index:= 0 to Count- 1 do
          begin
            l_table_name:= Strings[l_table_name_index];
            with f_c_field_info_ibquery(IbDatabase1l_table_namedo
            begin
              display(l_table_name);
              while not Eof do
              begin
                if Trim(Fields[1].AsString)= 'BLOB'
                  then blob_table_name_listbox_.Items.Add(l_table_name);

                Next;
              end// while not Eof

              Free;
            end// with f_c_field_info_ibquery
          end// with g_c_tablename_list, for l_table_name_index
      end// blob_table_names_Click

  • et pour ces tables là, nous utilisons la CLASS précédente pour générer le INSERT INTO adéquat


3.3 - Mini manuel

   compilez le projet
   sélectionnez la base dans le DirectoryListBox et FileListBox de l'onglet "dir_"
   créez la liste des Tables en cliquant "table_names_" de l'onglet "extract_"
   extrayez les Tables contenant des Blobs en cliquant "blob_table_names_"

image

   générez le script en cliquant "extract__"
   le script se trouve dans l'onglet "script_"

image




4 - Télécharger le code source Delphi

Vous pouvez télécharger:
  • ib_blob_extractor.zip : le projet complet qui extrait le script des tables contenant des Blobs d'une base Interbase, ainsi que les 3 scripts Sql, à titre d'exemple, pour la table EMPLOYEE.GDB (37 K)

Ce .ZIP qui comprend:

  • le .DPR, la forme principale, les formes annexes eventuelles
  • les fichiers de paramètres (le schéma et le batch de création)
  • dans chaque .ZIP, toutes les librairies nécessaires à chaque projet (chaque .ZIP est autonaume)
Ces .ZIP, pour les projets en Delphi 6, contiennent des chemins RELATIFS. Par conséquent:
  • créez un répertoire n'importe où sur votre machine
  • placez le .ZIP dans ce répertoire
  • dézippez et les sous-répertoires nécessaires seront créés
  • compilez et exécutez
Ces .ZIP ne modifient pas votre PC (pas de changement de la Base de Registre, de DLL ou autre). Pour supprimer le projet, effacez le répertoire.

La notation utilisée est la notation alsacienne qui consiste à préfixer les identificateurs par la zone de compilation: K_onstant, T_ype, G_lobal, L_ocal, P_arametre, F_unction, C_lasse. Elle est présentée plus en détail dans l'article La Notation Alsacienne



Comme d'habitude:

  • nous vous remercions de nous signaler toute erreur, inexactitude ou problème de téléchargement en envoyant un e-mail à jcolibri@jcolibri.com. Les corrections qui en résulteront pourront aider les prochains lecteurs
  • tous vos commentaires, remarques, questions, critiques, suggestion d'article, ou mentions d'autres sources sur le même sujet seront de même les bienvenus à jcolibri@jcolibri.com.
  • plus simplement, vous pouvez taper (anonymement ou en fournissant votre e-mail pour une réponse) vos commentaires ci-dessus et nous les envoyer en cliquant "envoyer" :
    Nom :
    E-mail :
    Commentaires * :
     

  • et si vous avez apprécié cet article, faites connaître notre site, ajoutez un lien dans vos listes de liens ou citez-nous dans vos blogs ou réponses sur les messageries. C'est très simple: plus nous aurons de visiteurs et de références Google, plus nous écrirons d'articles.



5 - Références

Le manuel Interbase qui contient les informations sur les requêtes Sql: LANGREF.PDF




6 - L'auteur

John COLIBRI est passionné par le développement Delphi et les applications de Bases de Données. Il a écrit de nombreux livres et articles, et partage son temps entre le développement de projets (nouveaux projets, maintenance, audit, migration BDE, migration Xe_n, refactoring) pour ses clients, le conseil (composants, architecture, test) et la formation. Son site contient des articles avec code source, ainsi que le programme et le calendrier des stages de formation Delphi, base de données, programmation objet, Services Web, Tcp/Ip et UML qu'il anime personellement tous les mois, à Paris, en province ou sur site client.
Créé: oct-06. Maj: aou-15  148 articles, 471 sources .ZIP, 2.021 figures
Contact : John COLIBRI - Tel: 01.42.83.69.36 / 06.87.88.23.91 - email:jcolibri@jcolibri.com
Copyright © J.Colibri   http://www.jcolibri.com - 2001 - 2015
Retour:  Home  Articles  Formations  Développement Delphi  Livres  Pascalissime  Liens  Download
l'Institut Pascal

John COLIBRI

+ Home
  + articles_avec_sources
    + bases_de_donnees
      + programmation_oracle
      + interbase
        – interbase_blobs
        – interbase_tutorial
        – interbase_dbexpress
        – interbase_ibx_net
        – ib_dbexpress_net
        – delphi_8_ado_net
        – borland_data_provider
        – sql_script_extraction
        – interbase_udf
        – sql_script_executer
        – ib_blob_extraction
        – insert_blob_script
        – ib_stored_procedures
      + sql_server
      + firebird
      + mysql
      + xml
      – paradox_via_ado
      – mastapp
      – delphi_business_objects
      – clientdataset_xml
      – data_extractor
      – rave_report_tutorial
      – visual_livebindings
      – migration_bde
    + web_internet_sockets
    + prog_objet_composants
    + office_com_automation
    + colibri_utilities
    + uml_design_patterns
    + graphique
    + delphi
    + outils
    + firemonkey
    + vcl_rtl
    + colibri_helpers
    + colibri_skelettons
  + formations
  + developpement_delphi
  + présentations
  + pascalissime
  + livres
  + entre_nous
  – télécharger

contacts
plan_du_site
– chercher :

RSS feed  
Blog

Architecte Delphi Architecture, Refactoring, choix de technologies, revue de code, mise en place de test, optimisation - Tél 01.42.83.69.36