Professional Documents
Culture Documents
1 - Introduction
J'ai choisi de prsenter Borcon 2004 les diffrents moyens d'utiliser Interbase:
Nous nous adressons pour cet article un programmeur Delphi ayant une ide
lmentaire de Delphi: Palette, Inspecteur, OnClick. Tout le reste sera expliqu.
Nous supposons:
que Delphi 8 est install (la version "dveloppeur": pas la version "tudiant"
qui n'a pas les bases de donnes, et pas besoin de la version "Entreprise" ou
"Architecte", mais tout marche aussi avec ces deux dernires)
qu'Interbase est install (voyez le tutorial interbase qui dtaille cette
installation). J'ai utilis la version Interbase 6 que j'ai installe et que j'utilise
couremment avecDelphi 6, mais tout fonctionne bien sr avec les versions 7
et FireBird.
2 - Architecture
Une fois les librairies .Net installes, nous pouvons utiliser des Serveurs de bases
de donnes en utilisant une couche appele Ado.Net. Cette couche dfinit des
composant pour communiquer avec des "sources de donnes". Ces sources sont trs
gnrales: des courriers Outlook, des donnes Excel et des donnes provenant
d'un Serveur Sql.
Pour les bases de donnes, Ado.Net permet de grer:
de faon native
o "Sql Data Provider" pour Sql Server
en ajoutant des modules supplmentaires, d'autres bases de donnes:
o pour Oracle, le module "Oracle Data Provider"
o pour les serveurs pour lesquels existe un pilote ODBC, le module
"ODBC Data Provider"
o
o
Notez aussi que le BDP est un module .Net gnral: il peut tre utilis avec
n'importe quel langage qui communique avec les librairies .Net (Delphi 8, bien sr,
mais aussi les autres langages via les divers outils de dveloppement).
L'architecture gnrale a donc l'allure suivante:
3 - La connection
3.1 - Prparation
Le BDP ne sait pas crer de base vierge. Seul Ibx, en mode Delphi 6, ou Ibx.Net en
mode Delphi 8 peuvent le faire. Nous allons donc utiliser une base cre
auparavant, en la copiant dans un rpertoire proche pour viter de la rechercher
niches dans des rpertoires dpendant de chaque installation. Nous allons:
crer un rpertoire _DATA au mme niveau que nos sources (dans n'importe quel
rpertoire qui vous convient)
copier une base Interbase dans ce rpertoire. Par exemple INSTITUT_PASCAL.GDB
provenant de nos tutoriaux antrieurs, ou EMPLOYEE.GDB provenant de "FICHIERS
COMMUNS" etc
renommer cette base INSTITUT_PASCAL_5.GDB
3.2 - La connection
Commenons par nous connecter note base Interbase:
lancez Delphi 8
crez une nouvelle application en cliquant "Fichiers | Nouveau | Windows Forms" et
renommez-la "p_ib_bdp_connection"
dans la page "Borland Data Provider" slectionnez un BdpConnection:
Notez que
ConnectionString contient:
assembly=Borland.Data.Interbase,
Version=1.5.0.0,
Culture=neutral,
PublicKeyToken=91d62ebb5b0d1b1b;
vendorclient=gds32.dll;
database=..\_data\INSTITUT_PASCAL_5.GDB;
provider=Interbase;
username=sysdba;
password=masterkey
ConnectionOption contient:
waitonlocks=False;
commitretain=False;
sqldialect=3;
transaction isolation=ReadCommitted;
servercharset=;
rolename=myrole
my_c_bdp_command:= my_c_bdp_connection.CreateCommand;
Nous pouvons aussi ajouter des transactions pour encadrer cette cration.
Donc:
crez une nouvelle application Windows Forms et appelez-la "p_ib_bdp_create_table"
posez un Button, appelez-le "create_", crez son vnement OnClick et tapez les
instructions de cration de table:
const k_database_file= '..\_data\INSTITUT_PASCAL_5.GDB';
k_table_name= 'formations_5';
k_connection_string= 'assembly=Borland.Data.Interbase, Version=1.5.0.0, '
+ 'Culture=neutral,PublicKeyToken=91d62ebb5b0d1b1b;vendorclient=gds32.dll
;'
+ 'database='+ k_database_file+ ';'
+ 'provider=Interbase;username=sysdba;password=masterkey';
k_sql_create= 'CREATE TABLE '+ k_table_name
+ ' (f_id INTEGER, f_name CHAR(28), f_days INTEGER, f_price DOUBLE P
RECISION )';
procedure TWinForm.create_transaction__Click(sender: System.Object; e: System.E
ventArgs);
var l_c_bdp_connection: BdpCOnnection;
l_c_bdp_transaction: BdpTransaction;
l_c_bdp_command: BdpCommand;
begin
try
try
l_c_bdp_connection:= BdpConnection.Create(k_connection_string);
Include(l_c_bdp_connection.StateChange, BdpConnection1_StateChange);
l_c_bdp_connection.Open;
l_c_bdp_transaction:= l_c_bdp_connection.BeginTransaction;
l_c_bdp_command:= l_c_bdp_connection.CreateCommand;
l_c_bdp_command.CommandText:= k_sql_create;
l_c_bdp_command.Connection:= l_c_bdp_connection;
l_c_bdp_command.Transaction:= l_c_bdp_transaction;
l_c_bdp_command.ExecuteNonQuery;
finally
l_c_bdp_transaction.Commit;
l_c_bdp_connection.Close;
end;
except
on e:exception do
begin
l_c_bdp_transaction.RollBack;
display_bug_stop(e.Message);
end;
end; // try ... except
end; // create_transaction__Click
compilez, excutez, et cliquez le bouton
Dans la foule, nous pouvons effacer la mme table avec la requte Sql suivante:
DROP TABLE formations_5
Donc:
placez un autre tButton sur la Forme, nommez-le "drop_table" et placez-y la requte de
suppression:
const k_sql_drop= 'DROP TABLE '+ k_table_name;
procedure TWinForm.drop_transaction__Click(sender: System.Object; e: System.Ev
entArgs);
var l_c_bdp_connection: BdpCOnnection;
l_c_bdp_transaction: BdpTransaction;
l_c_bdp_command: BdpCommand;
begin
try
try
l_c_bdp_connection:= BdpConnection.Create(k_connection_string);
Include(l_c_bdp_connection.StateChange, BdpConnection1_StateChange);
l_c_bdp_connection.Open;
l_c_bdp_transaction:= l_c_bdp_connection.BeginTransaction;
l_c_bdp_command:= l_c_bdp_connection.CreateCommand;
l_c_bdp_command.CommandText:= k_sql_drop;
l_c_bdp_command.Connection:= l_c_bdp_connection;
l_c_bdp_command.Transaction:= l_c_bdp_transaction;
l_c_bdp_command.ExecuteNonQuery;
finally
l_c_bdp_transaction.Commit;
l_c_bdp_connection.Close;
end;
except
on e:exception do
begin
l_c_bdp_transaction.RollBack;
display_bug_stop(e.Message);
end;
end; // try ... except
end; // drop_transaction__Click
try
l_table_name:= ListBox2.Items[ListBox2.SelectedIndex].ToString;
l_c_data_table:= l_c_bdp_connection.GetMetaData.GetColumns(l_table_name,
'', Borland.Data.Schema.ColumnType.Unknown);
DataGrid1.DataSource:= l_c_data_table;
finally
l_c_bdp_connection.Close;
end;
except
on e:exception do
DataGrid1.CaptionText:=e.Message;
end;
end; // ListBox2_MouseDown
compilez et excutez. Cliquez "table_" et cliquez "FORMATIONS_5"
voici le rsultat:
Nous pouvons automatiser ces ajouts en paramtrant la procdure qui envoie les
valeurs littrales. Voici un exemple:
posez un Button, appelez-le "insert_several_", crez son vnement OnClick et tapez les
end;
except
on e:exception do
display_bug_stop(e.Message);
end; // try ... except
end; // insert_several__Click
compilez, excutez, et cliquez le bouton
6 - Lire et Afficher
6.1 - Affichage par code
Nous allons maintenant afficher les donnes.
Une premire technique consiste lire les donnes en utilisant un DataReader.
Plaons cet affichage dans le projet prcdent:
posez un Button, appelez-le "select_", crez son vnement OnClick et tapez les
instructions qui afficheront les lignes dans un TextBox:
procedure TWinForm.select__Click(sender: System.Object; e: System.EventArgs);
var l_c_bdp_connection: BdpConnection;
l_c_bdp_command: BdpCommand;
l_c_data_reader: BdpDataReader;
l_field_index: Integer;
l_line: String;
l_formatted_value: String;
begin
try
try
l_c_bdp_connection:= BdpConnection.Create(k_connection_string);
Include(l_c_bdp_connection.StateChange, BdpConnection1_StateChange);
l_c_bdp_connection.Open;
l_c_bdp_command:= l_c_bdp_connection.CreateCommand;
l_c_bdp_command.CommandText:= k_sql_select;
l_c_data_reader:= l_c_bdp_command.ExecuteReader;
while l_c_data_reader.Read do
begin
l_line:= '';
connectez le Serveur:
pour afficher les donnes sur la Forme, nous crons un DataSet qui sera rempli
par le BdpDataprovider.
Pour cela, slectionnez l'onglet "Dataset" du configurateur, choisissez le bouton
"New Data":
8 - Evaluation
Voici quelques commentaires sur cette premire utilisation du BDP
Et ce qui change:
avec le BDP, la relation entre l'adaptateur et le DataSet est initialise
par l'Adaptateur. C'est en fait toute l'architecture des composants de
visualisation qui a t gnralise, et ceci explique ce changement de
liaison
o le DataGrid a 2 proprits (DataSource ET DataMember)
d'une faon plus gnrale, la masse de code gnre par Delphi 8 pour faire
fonctionner l'ensemble est la fois impressionnant et, mon avis, un peu
o
inquitant: soit cette masse est imprative et c'est un dfaut, soit Borland a
forc le comportement trs gnral de Ado.Net pour le faonner au
moule Delphi 6 et cela m'incite voir quel serait le fonctionnement sans tout
cela...
Cet explorateur est en fait un .EXE autonome. Mais je n'ai pas trs bien su
l'exploiter:
1 - Introduction
Cet article va indiquer comment extraire d'une base de donnes existante un script
SQL capable de recrer la mme base.
Cet utilitaire permet:
Nous avons utilis cet utilitaire dans notre article sur MastApp, la base de
dmonstration de Delphi
2 - Principe
Nous pouvons utiliser plusieurs techniques:
analyser les tables systme qui contiennent tout les informations sur la base
utiliser des composants Delphi qui sont capables d'extraire le schma
utiliser des outils externes tels que IbExpert
3 - Le Projet Delphi
3.1 - L'Objectif
Nous devons crer un script qui permettra :
de crer les tables ainsi que toutes leurs annexes (gnrateurs, triggers etc)
de remplir les donnes des tables
En ce qui nous concerne, nous esprions pouvoir tout extraire (les requtes de
cration de tables, les triggers etc et les donnes) par:
IbExtract1.ExtractObject(eoDataBase, '', []);
mais cet appel fournit bien le script de toutes les crations, mais pas le script pour
les donnes.
fournit bien le script des donnes de la table ORDERS, mais aussi au dbut le script
de cration de cette table. En combinant les deux appels, nous obtenons finalement
notre rsultat.
begin
open_database_Click(Nil);
with IBExtract1 do
begin
ExtractObject(eoDataBase, '', []);
Memo1.Lines.Assign(Items);
end;
end; // complete_schema_Click
compilez, excutez et cliquez "complete_schema_"
le schma complet s'affiche dans Memo1
matriel utilis : Pentium 2.800 Mhz, 512 Meg de mmoire, 250 Giga
disque dur
champ d'application : Delphi 1 2006 sur Windows, Interbase
niveau : dveloppeur Delphi / Interbase
plan :
o Les UDF Interbase
o Le Projet Delphi
o Ajout d'une UDF
o Tlcharger le code source Delphi
ajouter la routine en tant que EXTERNAL FUNCTION aux objets des bases
qui souhaitent l'utiliser
3 - Le Projet Delphi
3.1 - L'criture de l'UDF
Les fonctions externes doivent tre places dans une .DLL Windows. Cette .DLL
peut tre ralise avec n'importe quel outil.
En gnral, n'importe lequel n'est pas assez bon, et c'est pourquoi nous
utiliserons Delphi.
L'unit qui calcule les chanes est la suivante:
unit u_udf_string;
interface
uses SysUtils, Windows, Classes;
exports
f_trim_right,
f_right_pad,
f_string_length,
f_sub_string ;
end.
Il faut donc
compiler cette librairie
compiler le fichier d_string_udf.dll dans le rpertoire d'Interbase qui contient toutes les .DLL qui
seront intgres au moteur. Dans notre cas, il s'agit de
C:\Program Files\Borland\InterBase\UDF\
rebooter le PC pour que le moteur Interbase prenne cette .DLL en compte
Nous allons crer une base spcialement pour tester nos UDF. Vous pouvez trs
bien utiliser une base prexitante de votre choix.
Le dtail de la cration de la base, de la cration et du remplissage d'une table
contenant quelques CHAR et VARCHAR se trouve dans le .ZIP tlchargeable.
Quoi qu'il en soit, il s'agit d'une base de cours de formations contenant
la table suivante:
(
f_id INTEGER,
f_name CHAR(30),
f_location VARCHAR(10),
f_days INTEGER,
f_price FLOAT
)
Paris
London
Hong Kong
Montreal
Sao Paulo
Dallas
3
3
3
3
3
3
1400
1400
1400
1400
1400
1400
Nous allons ajouter aux UDF connues du moteur Interbase la fonction qui calcule
la taille d'une string:
Pour utiliser une fonction externe, nous l'appelons depuis une requte SQL, que
celle-ci soit lance depuis le Client ou depuis une procdure catalogue.
Dans le cas de StrLen, nous pouvons appeler, par exemple:
Pour certaines fonctions (RPad, par exemple), nous avons eu un peu de mal faire
fonctionner le tout. Nous avons alors test la fonction de la .DLL sparment, pour
nous assurer que le code tait correct.
Pour cela nous avons utilis une unit d'importation qui permettait d'appeler
facilement les fonctions de la .DLL:
unit u_import_udf_string;
interface
const k_udf_string= 'd_string_udf.dll';
Pour la fonction RPAD, nous avions mme du mal comprendre ce que la fonction
faisait (c'tait une fonction que nous n'avions pas crite initialement), et nous avons
test la fonction dans le projet mme (pour bnficier de tous les affichages de mise
au point), avant de la rinjecter dans la .DLL
Car il y a, en effet des UDF fournies par dfaut par Interbase. Pour l'anectdote,
nous nous en sommes apperus, car le projet fonctionnait sans avoir copier la
.DLL dans le rpertoire UDF, car les fonctions existaient dans la .DLL par dfaut
IB_UDF.DLL. Toutes sauf RPAD, qui a donc provoqu une erreur (pas lors
de CREATE EXTERNAL, mais lors de l'appel dans un SELECT )
La preuve, voici le rpertoire des UDF (avant ajout de notre .DLL):
Pour connatre le contenu de ces UDF, nous avons utiliser notre analyseur de
fichier PE (Portable Executable), qui affiche les fonctions exports par une .DLL
(ou tout autre .EXE). Voici ce qu'il nous a fourni pour IB_UDF.DLL:
Mais quelle est la syntaxe de ces UDF: en fait elles sont fournies comme exemple
d'UDF dans le rpertoire:
Vous trouverez le source (C) des UDF, avec des commentaires bien crits, ainsi
que le script qui incorpore ces UDF dans une base quelconque.
1 - Introduction
2 - Principe
Le texte du script contient les requtes les unes aprs les autres, avec un
terminateur quelconque aprs chaque requte.
En ce qui concerne Interbase:
Notez que
o
o
3 - Le Projet Delphi
Le travail de l'analyseur
Il s'agit l d'une version de plus du scanner de base, qui dtecte les commentaires
de script, et les mots cls qui nous intressent: SET TERM . Nous avons aussi
dcouvert que d'autres pseudo instructions devaient tre traites (limines, dans
notre cas):
L'analyseur de requte
Voici l'analyseur
t_symbol_type= (e_unknown_symbol,
e_identifier_symbol, e_integer_symbol, e_operator_symbol,
e_string_litteral_symbol,
e_comment_symbol,
e_end_symbol);
c_ib_script= class(c_text_file)
m_symbol_type: t_symbol_type;
m_blank_string, m_symbol_string: String;
_m_previous_index: Integer;
m_c_result_list: tStringList;
m_request_index: Integer;
m_is_SET_TERM, m_is_COMMIT_WORK, m_is_SET_AUTODDL: Boolean;
m_terminator: Char;
Constructor create_ib_script(p_name, p_file_name: String);
function f_initialized: Boolean;
procedure initialize_scanner;
function f_read_symbol: Boolean;
procedure test_scanner;
function f_remove_comment: String;
procedure initialize_request_scanner;
function f_next_request: String;
function f_get_request: String;
Destructor Destroy; Override;
end; // c_ib_script
// -- here get_request()
begin // f_get_request
m_is_SET_TERM:= False;
m_is_COMMIT_WORK:= False;
m_is_SET_AUTODDL:= False;
repeat
get_request;
until (m_symbol_type= e_end_symbol)
or (m_symbol_type<> e_comment_symbol);
if m_symbol_type= e_end_symbol
then l_request:= '';
Result:= l_request;
end; // f_get_request
// -- here execute_request()
var l_request: String;
l_trimmed_request: String;
begin // execute_script_Click
original_memo_.Lines.LoadFromFile(g_script_path+ g_script_file_name);
if not FileExists(g_script_path+ g_script_file_name)
then display_bug_stop('not_found '+ g_script_path+ g_script_file_name);
connect_database_Click(Nil);
with c_ib_script.create_ib_script('ib_script',
g_script_path+ g_script_file_name) do
begin
if f_initialized
then begin
initialize_scanner;
repeat
l_request:= f_get_request;
if not (m_is_SET_TERM or m_is_COMMIT_WORK or m_is_SET_AUTODDL)
then begin
l_trimmed_request:= f_add_return_line_feed(l_request);
l_trimmed_request:= f_change_returns_in_spaces(l_trimmed_request);
l_trimmed_request:= Trim(f_remove_double_spaces(l_trimmed_request));
if exec_.Checked
then begin
if (Pos('DIALECT', l_request)<= 0)
and
(Trim(l_request)<> '')
then
execute_request(l_request)
end
else display(l_request);
end;
until l_request= '';
end
else display_bug_stop('not_found '+ g_script_path+ g_script_file_name) ;
end; // with c_ib_script
end; // execute_script_Click
IbDatabase1.DefaultTransaction.StartTransaction;
IbSql1.Sql.Text:= p_request;
// -- for stored procedures
IbSql1.ParamCheck:= False;
IbSql1.ExecQuery;
IbDatabase1.DefaultTransaction.Commit;
except
on e: Exception do
begin
display_bug_stop('*** pb_'+ e.Message);
end;
end; // try except
end; // execute_request
Min manuel
Le script
HowTo
Quelques soucis
Parmi les petites misres:
les valeurs littrales des dates doivent tre un format commestible pour
le moteur. Donc soit "mois, jour, anne", soit, et c'est nouveau pour nous,
"anne, mois, jour"
les guillemets sont placs dans le script du gnrateur de script, mais
doivent tre retirs pour l'excution des scripts
les blobs doivent faire l'objet d'un traitement spar (mettant en oeuvre
des tStreams)
En tant un rien cynique, nous pourrions rcuprer les sources de IbConsole, qui
sait bien franchir toutes ces barrires sans souci. En attendant, cet utilitaire a
rempli les missions que nous avions envisages.
1 - Introduction
Ce tutorial va vous indiquer comment utiliser le Serveur Interbase fourni avec
Delphi. Ce tutorial a plusieurs objectifs:
effectuer toutes les oprations en Delphi, plutt que de prsenter une srie
d'outils annexes dont la prsentation alongerait l'expos
insister sur les points qui posent problme (cration d'une base, chane de
connection, modification de dbGrid) plutt que sur les composants visuels
assez intuitifs au demeurant
prsenter les composants rellement utiliss pour grer des tables Sql
(des tIbQuery) plutt que des composants gnriques (tIbTable) dont les
traitements automatiques masquent le fonctionnement rel d'un Serveur Sql
limiter au maximum le nombre de composants utiliss pour manipuler les
donnes du Serveur sans perdre en fonctionnalit
2 - Installation
2.1 - Principe
Le logiciel Interbase comporte essentiellement deux parties:
le programme Serveur (le moteur), qui en gnral est plac sur un PC distant
le programme Client, qui dialogue avec les programme applicatifs
(Delphi ou autre).
Il faut donc installer les deux parties (sur la mme machine ou sur des PC spars).
Interbase peut fonctionner selon deux modes:
le mode dit "local", pour lequel le moteur et le programme client sont sur le
mme PC. La machine n'a pas besoin d'avoir les couches rseau (TCP\IP,
Novell ou autre), ni de carte rseau (carte Ethernet ou liaison srie). Le
programme applicatif communique avec le Client, qui appelle directement
les routines du serveur (sans passer par des appels TCP\IP)
Dans les deux cas, l'installation se fait en utilisant l'installateur du CD Delphi (ou
du CD Interbase). Nous prsenterons l'instalation partir du CD Delphi.
3 - Crer la Base
3.1 - SQL et la cration de bases
Pour crer une base, il faut, pour tous les moteurs, utiliser des outils spciaux, le
langage SQL ne contenant pas de requte spcifique pour cette opration
Pour Interbase, ce sont des primitives de l'API native du moteur qui permettent
cette cration. Elle n'est pas possible depuis les composants gnrique d'accs aux
donnes (tTable, tQuery). En revanche, Jeff Overcash a ajout tIbDatabase la
mthode qui utilise les API Interbase natifs et permet la cration de la base.
Plus prcisment:
compilez et excutez
cliquez Button1
le rpertoire ..\data\ contient bien le fichier "Institut_Pascal.GDB" dont la taille est
d'environ 580 K
Notez que:
fermez l'diteur
slectionnez Connected et basculez sa valeur sur True
au bout d'un "petit" instant, la valeur bascule sur True
Notez que:
Pour cela nous devons envoyer une requte en langage SQL vers
le Serveur Interbase.
La syntaxe de cette requte est:
CREATE TABLE formations
(f_numero INTEGER, f_nom CHARACTER(11), f_jours INTEGER,
f_prix NUMERIC(5, 2) )
Il suffit donc de choisir un nom de table, et le nom de chaque colonne avec son
type.
Parmi les types autoriss par Interbase citons:
nous pouvons utiliser Add pour ajouter une ligne de requte, Text pour
affecter une requte, Clear pour purger tout texte antrieur, ou
mme LoadFromFile pour lire un fichier .txt contenant la requte:
IbQuery1.Sql.LoadFromFile('cree_formation.txt');
La mise en page n'a aucune importance pour le Serveur: la requte peut tre
rpartie en plusieurs lignes:
tIbQuery.Sql.Add('CREATE TABLE');
tIbQuery.Sql.Add(' formations ');
tIbQuery.Sql.Add(' (f_numero INTEGER, f_nom CHARACTER(11))');
nous pouvons aussi crer la String en plusieurs tapes par toutes les
primitives de String telles que la concatnation, Insert, le test par Pos ou
autre. Par exemple:
l_requete:= 'CREATE TABLE '+ Edit1.Text+ ' (';
l_requete:= l_requete+ Edit2.Text+ ')';
tIbQuery.Sql.Add(l_requete);
C'est une tStrings comme n'importe quelle autre. Ce qui explique qu'aucune
vrification de syntaxe n'est effectue.
Lorsque nous excutons:
IbQuery1.ExecSql;
alors:
o
o
Notez que l'envoi de toute requte qui modifie des donnes du Serveur (et la
cration d'une nouvelle table est bien une modification) ne peut se faire que par du
code (PAS en basculant IbQuery1.Active sur True en mode conception)
IF NOT IbTransaction1.InTransaction
THEN IbTransaction1.StartTransaction;
4.5 - L'application
Pour crer notre table
crez une nouvelle application et appelez-la "ib_create_table"
placez un tIbDataBase sur la Forme. Cliquez deux fois sur IbDataBase1, renseignez
"local", "DataBase", "User Name" "Pass Word" et "Login Prompt":
au moteur. Nous verrons cette requte SELECT en dtail plus bas, mais voici
comment procder pour notre test:
ajoutez un second tIbQuery sur la tForme
slectionnez sa proprit DataBaseName et initialisez-la
IbDataBase1
placez un second tButton sur la Forme et placez-y la requte de lecture:
procedure TForm1.select_Click(Sender: TObject);
begin
with IbQuery2 do
begin
Close;
with Sql do
begin
Clear;
Add('SELECT * FROM formations');
Try
Open;
display('ok');
except
On e: Exception do
display('not_there '+ e.Message);
end;
end; // with Sql
end; // with IbQuery2
end; // select_Click
compilez, excutez, et cliquez le bouton
Donc:
ajoutez un troisime tIbQuery sur la tForme
slectionnez sa proprit DataBaseName et initialisez-la
IbDataBase1
placez un autre tButton sur la Forme et placez-y la requte de suppression:
procedure TForm1.drop_table_Click(Sender: TObject);
begin
IbDatabase1.Open;
with IbQuery3 do
begin
Close;
with Sql do
begin
Clear;
Add('DROP TABLE formations');
end;
Try
if ibtransaction1.InTransaction
then ibTransaction1.Commit;
ibtransaction1.StartTransaction;
ExecSql;
ibtransaction1.Commit;
display(' ok');
except
on e: exception do
display('pb_drop '+ e.Message);
end;
end; // with IbQuery3
end; // drop_table_Click
compilez, excutez, et cliquez le bouton
Notez que:
nous avons utilis 3 IbQuery spars. Nous aurions aussi bien pu utiliser le
mme
nous aurions mme pu utiliser un IbSql. Pour ce tutorial que nous souhaitons
minimal, nous avons prfr un IbQuery qui permet la fois la modification
lire le fichier
gnrer la requte pour crer chaque table
la cration de la table est ralise par une classe dont voici la dfinition:
Et:
DataBase.DefaultTransaction.StartTransaction;
ExecSql;
DataBase.DefaultTransaction.Commit;
display(' ok '+ m_table_name);
except
on e: Exception do
display(' *** pb_create '+ e.Message);
end // try ... Except
else display('did_not_ask_to_create');
end; // with m_c_ib_query_ref, Sql
end; // create_table
cette mthode utilise la liste de dfinition des champs qui est charge partir
du fichier par la procdure suivante
procedure TForm1.create_script_Click(Sender: TObject);
var l_list_index: Integer;
l_line, l_trimmed_line: String;
l_c_create_ib_table: c_create_ib_table;
l_table_index: Integer;
begin
with tStringList.Create do
begin
LoadFromFile(k_script_path+ k_script_name);
l_c_create_ib_table:= Nil;
l_table_index:= 0;
for l_list_index:= 0 to Count- 1 do
begin
l_line:= Strings[l_list_index];
l_trimmed_line:= Trim(l_line);
if l_trimmed_line<> ''
then begin
if l_trimmed_line= l_line
then begin
if Assigned(l_c_create_ib_table)
then begin
l_c_create_ib_table.create_table;
l_c_create_ib_table.Free;
Inc(l_table_index);
end;
display_line;
l_c_create_ib_table:=
c_create_ib_table.create_ib_table('', l_line, IbQuery1);
end
else begin
l_c_create_ib_table.m_c_fields.Add(l_trimmed_line);
end;
end;
end; // for l_list_index
// -- the last table
if Assigned(l_c_create_ib_table)
then begin
l_c_create_ib_table.create_table;
l_c_create_ib_table.Free;
end;
Free;
end; // with tStringList
end; // create_script_Click
Notez que:
ou
VALUES (3, "Interbase Delphi")
De plus si notre valeur est niche dans une String Pascal, il faut ddoubler les
guillemets
IbQuery1.Sql.Add(' VALUES (3, ''Interbase Delphi'')');
aux US, la partie entire est spare de la partie dcimale par un point:
3.1415
alors qu'en Europe nous disons
3,1415
les valeurs que nous tapons en PASCAL doivent donc respecter la syntaxe
US
mais si nous utilisons des primitives de conversion interface utilisateur
<=> Delphi, Delphi lit les paramtres de localisation dans la base de registre
Windows. Pour ma machine il est dit que le sparateur dcimal est la virgule.
Par consquent les fonctions telles que:
FloatToStr
attendent une virgule
Nous pouvons imposer le sparateur utiliser en spcifiant:
DecimalSeparator:= '.';
En supposant que nous souhaitions fournir la date du 29 Mars 2004, nous pouvons
utiliser:
INSERT INTO dates
(d_numero, d_date)
VALUES (3, '2004/03/29')
et:
IbQuery1.Sql.Add('INSERT INTO dates');
IbQuery1.Sql.Add(' (d_numero, d_date');
IbQuery1.Sql.Add(' VALUES (3, ''2004/03/29'')');
Notez que:
la procdure appelante pourrait aussi bien lire ses donne d'une autre source
(un fichier FILE OF, un fichier ASCII ("comma separates values" ou autre),
un autre table (Oracle, Sql Serveur ou mme une autre table Interbase...)
le paramtres p_cost est de type Double:
o la procdure appelante envoie une valeur littrale avec un point
dcimal
insert_generic(2, 'Bases de Donnes Delphi', 3, 1.400);
o
6 - Lire et Afficher
6.1 - 5.1- Principe
Pour afficher un enregistrement, nous devons d'abord rcuprer ses valeurs du
Serveur.
Pour lire les donnes contenues dans une table, SQL utilise l'instruction SELECT.
Par exemple:
SELECT f_numero, f_nom
FROM formations
il vrifie sa syntaxe
il construit une table contenant les valeurs demandes
ces donnes sont envoyes au Client
Plus concrtement:
crez une nouvelle application et appelez-la "ib_select"
cette table rsultat est envoye via le rseau au Client Interbase. Celui ci la
transmet ensuite l'application. Delphi place alors ce rsultat dans un
tampon mmoire associ tIbQuery:
6.3 - Affichage
Une fois que IbQuery a rcupr les donnes nous pouvons les afficher ou les
traiter en mmoire.
Pour afficher les donnes nous utilisons:
Par consquent:
slectionnez dans la page "Data Access" de la Palette le composant tDataSource:
Donc:
slectionnez IbQuery1
cliquez sur sa proprit Sql
Delphi ouvre l'diteur de Sql. A prsent les tables cres sont affiches:
6.5 - SELECT
SELECT est la seule instruction de lecture de donnes du Serveur. Sa structure
gnrale est:
SELECT colonnes
FROM tables
WHERE conditions
et:
colonnes indique quelles colonnes nous voulons voir figurer dans le rsultat.
Nous pouvons
o citer explicitement les colonnes souhaites, dans l'ordre qui nous
convient:
SELECT f_nom, f_numero
FROM formations
o
SELECT f_nom
FROM formations
o
SELECT *
FROM formations
o
SELECT COUNT(*)
FROM formations
le rsultat est alors une table d'une ligne, une colonne avec le nombre
de formations
tables contient le noms des tables utiliser pour calculer le rsultat. Par
exemple:
o
SELECT *
FROM formations, dates
WHERE f_nom='UML ET DELPHI'
conditions permet
o de ne retenir que certaines lignes du rsultat. Par exemple
SELECT *
FROM dates
WHERE f_date> '2004/05/01'
o
de trier le rsultat:
SELECT *
FROM dates
ORDER BY f_date
o
Dans le premier temps, le Serveur calcule sa mthode d'accs, mais n'excute rien
car il lui manque la valeur des paramtres. Lorsque le Serveur reoit les paramtres,
il lance le calcul en utilisant son plan d'valuation, et retourne le rsultat. Et ceci
autant de fois que le squelette de la requte ne change pas.
Pour effectuer ce travail en deux temps:
nous rdigeons une requte qui contient des paramtres. En Delphi, ces
paramtres sont dsigns par un identificateur prcd de ":". Par exemple
SELECT *
FROM dates
WHERE f_date= : ma_date
Notez que:
o l'identificateur n'a pas besoin d'avoir le mme nom que la colonne
o les paramtres peuvent seulement apparatre dans la
clause WHERE (pas dans les champs ou pour le nom des tables)
o ":" et ma_date sont colls (pas d'espace entre les deux)
la requte est envoye vers le Serveur par
IbQuery1.Prepare;
ou
IbQuery1.ParamByName('ma_date').AsString:= Edit3.Text;
En pratique:
crez une nouvelle application et appelez-la "p_ib_parametrized"
placez un tIbTransaction sur la Forme
placez un tIbDataBase sur la Forme. Cliquez deux fois sur IbDataBase1, renseignez
"local", "DataBase", "User Name" "Pass Word" et "Login Prompt".
Vrifiez la connection en basculant IbDataBase1.Connected sur True, puis fermez la
connection.
Slectionnez DefaultTransaction et initialisez-la IbTransaction1
placez un tIbQuery sur la tForme
slectionnez sa proprit DataBaseName et initialisez-la IbDataBase1
placez un tButton sur la Forme et crez sa mthode OnClick. Placez-y les instructions de
prparation:
procedure TForm1.prepare_Click(Sender: TObject);
begin
with IbQuery1 do
begin
Close;
with Sql do
begin
Clear;
Add('SELECT * FROM formations WHERE f_nom= :le_nom');
end; // with Sql
Prepare;
end; // with IbQuery1
end; // prepare_Click
placez un tButton sur la Forme et crez sa mthode OnClick. Placez-y les instructions qui
initialisent les paramtres et ouvrent la table:
procedure TForm1.close_params_open_Click(Sender: TObject);
begin
with IbQuery1 do
begin
// -- close in case has done a previous request
Close;
// -- set the parameter values
with Sql do
ParamByName('le_nom').AsString:= parameter_edit_.Text;
// -- send the parameter to the database
Open;
end; // with IbQuery1
end; // close_params_open_Click
compilez, excutez, et cliquez le bouton qui lance la requte
Cette requte qui modifie les donnes du Serveur est envoye vers le Serveur en
utilisant tIbQuery1.ExecSql
En dtail:
crez une nouvelle application "p_update_data"
placez un tIbTransaction sur la Forme
placez un tIbDataBase sur la Forme. Cliquez deux fois sur IbDataBase1, renseignez
"local", "DataBase", "User Name" "Pass Word" et "Login Prompt".
Vrifiez la connection en basculant IbDataBase1.Connected sur True, puis fermez la
connection.
Slectionnez DefaultTransaction et initialisez-la IbTransaction1
placez un tIbQuery sur la tForme
slectionnez sa proprit DataBaseName et initialisez-la IbDataBase1
placez un tButton sur la Forme et crez sa mthode OnClick. Placez-y les instructions de
modification:
procedure TForm1.Button1Click(Sender: TObject);
begin
with IbQuery1 do
begin
Close;
with Sql do
begin
Clear;
Add('UPDATE formations SET f_nom=''Interbase'' where f_numero= 3');
end; // with Sql
Try
ExecSql;
except
on e:exception do
display(' *** pb_update'+ e.Message );
end; // Try...Except
end; // with IbQuery1
end; // Button1Click
compilez, excutez, et cliquez le bouton
que chaque ligne de chaque table ait un identificateur unique pour que nous
puissions dsigner cette ligne en cas de modification
que nous indiquions dans UPDATE les lignes modifier
omettre WHERE. Par exemple, pour passer tous les noms en majuscule:
UPDATE formations
SET f_nom= UPPER(f_nom)
Toutefois:
o ne rptez pas cette requte de rduction trop souvent: il faut bien que
je mange un peu !
o nous faisons des conditions tarifaires particulires (groupes,
formations intra, tudiant, particulier, rinsertion...), que nous sommes
prts vous prsenter si vous me tlphonez directement l'Institut
Pascal au 01.42.83.69.36.
7.4 - tIbUpdateSql
Ce composant a pour vocation de contenir la requte SQL qui doit tre excute
lorsque le tIbQuery doit tre modifi. Cette requte est place
danstIbUpdaateSql.ModifySql.
Automatisons par exemple la mise jour de f_nom lorsque nous tapons une valeur
dans un tDbGrid:
crez une nouvelle application et appelez-la "p_update_sql"
placez un tIbTransaction sur la Forme
placez un tIbDataBase sur la Forme. Cliquez deux fois sur IbDataBase1, renseignez
"local", "DataBase", "User Name" "Pass Word" et "Login Prompt".
Vrifiez la connection en basculant IbDataBase1.Connected sur True, puis fermez la
connection.
Slectionnez DefaultTransaction et initialisez-la IbTransaction1
placez un tIbQuery sur la tForme
compilez, excutez:
Notez que:
pour dsigner les valeur des champs utiliser, nous avons employ une
requte paramtre, en dsignant les paramtres par le nom du champ:
f_nom= :f_nom
Si nous souhaitons pouvoir modifier tous les enregistrements, nous utilisons donc
dans tIbUpdateSql.ModifySql une requte du type:
UPDATE formations
SET f_numero= :f_numero, f_nom= :f_nom
WHERE f_numero= :old_f_numero
Ce concept de "old values" est fondamental pour la mise jour concurrente que
nous prsenterons voir ci-dessous.
8 - Effacer de Donnes
8.1 - Principe de l'effacement
Pour effacer l'enregistrement ayant le numro 8, nous excutons une requte
DELETE
FROM formations
WHERE f_numero= 3
En dtail:
De faon naturelle:
9 - Plusieurs Tables
9.1 - La Normalisation des Tables
Lorsque nous crons une application, nous rpartissons les donnes dans des tables:
les factures, les articles, les adresses des fournisseurs etc.
Cette activit de rpartition peut devenir trs complexe. Imaginez la modlisation
de l'activit de Renault ou des Galeries Farfouillettes: faut-il placer l'adresse des
fournisseurs avec les pices du stock, ou crer un table spare, combien de tables
faut-il alors crer etc.
Pour des projets plus modestes, la rpartition est souvent intuitive, et se rsume
souvent adapter des structures utilises dans d'autres projets.
Nanmoins, les donnes utilises par SQL doivent obir un nombre minimal de
contraintes:
nombre de colonnes
redondance / dpendances
Prenons le cas simple de formations dont le calendrier est le suivant (le vrai
calendrier se trouve <%dates_des_formations>):
Initiation Delphi:
Mars
2 au 4 Metz
Delphi Interbase:
Delphi UML:
Avril
6 au 8 - Paris
23 au 25 Paris
20 au 22 Chlons
Mai
4 au 6 Toulouse
25 au 27 Lyon
nous crons une table avec les dates et les villes, en plaant le code de la
formation pour dsigner le nom des formations
D'autre part, si le stage de Mars a eu lieu, nous effaons la ligne "1, 2004/03/02,
Metz". Ceci supprime aussi le fait que nous ralisons des stages Metz.
Le fait que la suppression d'une ligne fasse disparatre une information est appel
"anomalie de suppression".
Si nous souhaitons prsenter les villes o les stages peuvent avoir lieu,
indpendamment de sessions programmes dans les trois prochains mois, il faut
sparer les villes dans une table diffrente:
9.2 - Jointure
Ayant rparti les donnes dans plusieurs tables pour rpondre aux exigences SQL
et au souci de non-redondance / absence d'anomalies, nous avons prsent
l'obligation de recoller les morceaux pour reconstituer l'information de dpart: pour
savoir o et quand se droulent les formations "Interbase" nous devons:
nous obtenons:
le rsultat est:
maintenant que les lignes sont correctement associes, il est inutile d'afficher
deux fois le numro du stage. Nous pouve effectuer une projection en
supprimant la colonned_formation du rsultat:
SELECT f_numero, f_nom, d_date, d_ville
FROM formations, dates
WHERE f_numero= d_formation
comme nous ne nous intressons qu' Interbase, il faut liminer les lignes ne
concernant pas interbase (filtrage) en ajoutant une condition WHERE:
SELECT f_numero, f_nom, d_date, d_ville
FROM formations, dates
WHERE f_numero= d_formation AND f_nom= 'Interbase Delphi'
finalement pour voir le nom de la ville, il faut faire entrer la troisime table
dans la danse:
SELECT f_numero, f_nom, d_date, v_nom
FROM formations, dates
WHERE f_numero= d_formation
AND d_ville= v_numero
AND f_nom= 'Interbase Delphi'
le rsultat n'est pas trs satisfaisant: le nom du stage est rpt chaque ligne
le calcul est de plus inefficace: le Serveur ne peut nous retourner le rsultat
que lorsque tout le calcul est ralis.
Nous pouvons provoquer le calcul Matre Dtail chaque fois que nous dtectons
une modification d'enregistrement dans la table Matre: c'est
l'vnementDataSourceMatre.OnDataChange qui nous signale ce changement.
Par consquent:
Par consquent:
crez une nouvelle application et appelez-la "p_master_detail"
placez un tIbTransaction sur la Forme
placez un tIbDataBase sur la Forme. Cliquez deux fois sur IbDataBase1, renseignez
"local", "DataBase", "User Name" "Pass Word" et "Login Prompt".
pour le Dtail:
sString);
end; // with Sql
Open;
end; // with IbQuery1
end; // TForm1.DataSource1DataChange
petite prcaution: lorsque la Forme sera cre, IbQuery1 sera ouverte, les lignes
remplies, et DataSource1.OnDataChange appel. Il est donc impratif
queIbQuery2 existe AVANT IbQuery1. Pour vous assurez que c'est le cas,
slectionnez dans le menu "Edit" le sous-menu "Creation Order" et dplacez les
composants pour que cette contrainte soit respecte:
pour le Dtail:
Notez que:
Soit:
Soit:
adresse IP si ncessaire
chemin et ventuellement nom du fichier contenant les donnes
peut tre des noms d'utilisateurs et des mots de passe
cliquez "Build..."
la liste des fournisseurs est prsente:
slectionnez "Microsoft Jet 4.0 Ole Db Provider". Le mot important est JET qui est le
nom gnrique du moteur d'accs
cliquez "Suivant >>"
l'onglet "Connexion" est affich
dans "1 slectionnez le nom de base de donnes", fournissez le chemin des tables
Paradox. Dans notre cas
C:\programs\fr\bdd\paradox_via_ado\_data\
puis, pour Paradox:
Paradox 7.x
et cliquez "Ok"
retournez dans l'onglet "Connexion"
la valeur Paradox a bien t entre
cliquez "Tester la connection"
cliquez une Table, "Add table", les colonnes (par exemple "*") et "Add Field". Dans
notre cas la requte est:
SELECT *
FROM customer
slectionnez Active et basculez sa valeur sur True
posez un tDataSource sur la Forme
voici le rsultat:
Pour Paradox, ADO est alors une bonne alternative. De plus ADO permet une
utilisation plus facile d'ASP.
Pour les chanes de connexion, nous avons parl de Paradox, mais de nombreuses
autres possibilits pour le "Microsoft Jet 4.0" existent:
Microsoft Jet 1.0, Microsoft Jet 1.1, Microsoft Jet 2.0, Microsoft Jet 3.x,
Microsoft Jet 4.x
dBASE III, dBASE 4, dBASE 5
Excel 3.0, Excel 4.0, Excel 5.0, Excel 8.0, Excel 9.0
Exchange 4
Lotus WK1, Lotus WK3, Lotus WK4
Paradox 3.x, Paradox 4.x, Paradox 5.x, Paradox 7.x
Text 1.x
Html 1.x
soit pour migrer de Paradox vers d'autres moteurs Sql (Interbase / Firebird,
Sql Server, Oracle etc)
soit, en conservant les donnes Paradox, pour utiliser Ado comme
composants d'accs