Difference between revisions of "SQLdb Tutorial1"

From Lazarus wiki
Jump to navigationJump to search
m (Fixed syntax highlighting; deleted category included in page template)
(133 intermediate revisions by 18 users not shown)
Line 1: Line 1:
{{SQLdb Tutorial}}
+
{{SQLdb Tutorial1}}
  
 +
{{Infobox databases}}
 
== Introduction ==
 
== Introduction ==
  
This tutorial has the intention to show the usage of the [[SQLdb Package]] on the basis of practical examples. It is primarily targeted at newbies. If somebody is looking for basics about databases and SQL, he should read the corresponding books.  
+
This tutorial shows you how to program databases using practical example code based on the [[SQLdb Package]]. It is primarily targeted at newbies. If somebody is looking for basics about databases and SQL, he should read relevant books/documentation.  
For this tutorial I use Firebird with the example database employee.fdb.
+
For this tutorial I use Firebird with the example database employee.fdb. Other databases can also be used; some adjustments will need to be made which are mentioned in the text.
  
Thanks to [[User:Loesje|Joost]] and Michael. Without their help this tutorial probably never has come about.
+
While this tutorial may seem long, it mostly is just a lot of text that explains why you should type what you type. As you can see at the end, the amount of actual code you will need for a working application is not that great. More experienced developers will hopefully be able to glance through the instructions and quickly understand what's going on.
 +
Also, you can stop at the end of the [[#Basic example|Basic example]] chapter and have a working program.
 +
 
 +
This tutorial is based on a [[SQLdb Tutorial1/de|German tutorial]] by [[User:Swen|Swen]], but it is extended, especially after the [[#Basic example|Basic example]]. [[User:Swen|Swen]] wants the German version to remain as-is. If this is a problem, we can rename this version and base a new German translation on that.
 +
 
 +
From Swen: thanks to [[User:Loesje|Joost]] and Michael. Without their help this tutorial probably never would have come about.
  
 
== Requirements ==
 
== Requirements ==
  
If possible you should use a recent Lazarus version (with FPC 2.2.2 or newer) for this tutorial. If the SQLdb package isn't already installed, you should do it now (Components -> Installierte Packages einrichten ... -> SQLDBLaz 1.0). Furthermore you need [http://sourceforge.net/project/showfiles.php?group_id=9028 Firebird] (if possible version 2.0 or newer). The examples assume, that the standard settings (SYSDBA and masterkey) were not changed.
+
This tutorial is written for use with recent Lazarus versions (Laz 1.0); it should also work on older versions Lazarus 0.9.30.
 +
 
 +
Please see [[SQLdb_Tutorial0]], which will walk you through making sure you have the right sample database set up.
 +
 
 +
== Basic example ==
 +
 
 +
=== Project and components ===
 +
First you should create a new Lazarus project.
 +
 
 +
To get access to our database we need one [[TIBConnection]], one [[TSQLTransaction]] and one [[TSQLQuery]] component from the '[[SQLdb tab]]' in the component palette:
 +
 
 +
[[File:sqldbcomponents.png‎]]
 +
 
 +
[[TIBConnection]] is an Interbase/Firebird specific connection component.
 +
If you are using a different database, substitute the proper component from the '[[SQLdb tab]], e.g. a [[TSQLite3Connection]]' for an SQLite database, [[TPQConnection]] for a PostgreSQL database. Discussion of setting up any database access libraries is out of scope for this tutorial; see e.g. [[Databases]] for that.
 +
 
 +
Click on the [[TIBConnection]] (or equivalent connection component) on your form, and in the Object Inspector, change the name to ''DBConnection''. This will simplify the rest of the tutorial when using different databases.
 +
It's also generally a good idea to name your components for something useful in your program (e.g. MainframeDBConnection) so you know what it stands for.
 +
 
 +
The other two components, [[TSQLTransaction]] and [[TSQLQuery]], can be used for all databases that are supported by SQLdb.
 +
 
 +
To display the data, we use a [[TDBGrid]] component, which can be found on the 'Data Controls' tab. To connect this component to the database components we need a [[TDataSource]] component from the '[[Data Access tab]]'.
 +
 
 +
Now we have all database components needed for the first example. You can enlarge the TDBGrid to have enough space to display all data.
 +
 
 +
=== Link the components ===
 +
Next we need to connect our components. A very simple way is to use the object inspector, but you can also do this in your source code.
 +
 
 +
Change the ''Transaction'' property of DBConnection to 'SQLTransaction1'. This causes the ''Database'' property of SQLTransaction1 to automatically change to 'DBConnection'.
 +
 
 +
Then, change the ''Database'' property of SQLQuery1 to 'DBConnection'. Lazarus automatically adds the value for the 'Transaction' property.
 +
 
 +
Next, change the ''Dataset'' property of Datasource1 to 'SQLQuery1'.
 +
 
 +
Finally we change the ''Datasource'' property of DBGrid1 to 'Datasource1'.
 +
 
 +
We now end up with a connection that links its default transaction to a transaction component. The transaction component links its database property to the connection object. These two components are enough to connect and execute instructions, but not enough to show queries. For this, an SQLQuery component is used, which points to the database (and links to its default transaction). With the SQLQuery, we'll later on retrieve data and post it back to the database.
 +
 
 +
Finally, the datasource component, which is linked to the query component, is a sort of place holder. It keeps track of where in the query dataset we are and the GUI components are linked to that so they all show the same record.
 +
 
 +
If this is gibberish to you, don't despair: with just some more work, we'll be able to show our first data.
 +
 
 +
=== Connecting to the database ===
 +
How can we now show the data from our database on the screen?
 +
 
 +
First we need to tell DBConnection where the employee.fdb database is located. Locations of that db differ depending on operating system, it could be something like:
 +
* .../examples/empbuild/ subdirectory of your Firebird installation on Linux
 +
* C:\Program Files\Firebird\Firebird_2_5\examples\empbuild\EMPLOYEE.FDB on a Windows machine
 +
* Using Firebird embedded, the file should be in your project directory
 +
 
 +
Again you have the choice: you can use the object inspector to assign the path or do it directly in your source code.
 +
 
 +
We choose to use the object inspector: set the DBConnection 'HostName' property to the Firebird server name or IP adddress. Use localhost if a Firebird server is running on your development machine; use a blank value if you use the embedded Firebird client.
 +
Change the ''DatabaseName'' property of DBConnection to the path to the employee.fdb file on the database server. If you use embedded Firebird, the path part should be empty and you should just specify the filename.
 +
 
 +
Before the database server grants access to the data, it will check authorisation via username and password. A serious database application will ask the user for both values when the application is started, and send these to the server when connecting. A possible way of doing this is shown in [[SQLdb Tutorial3]].
  
== Example 1 ==
+
However, for now, to simplify matters, we use the object inspector again to hard code these. Change the 'UserName' property to 'SYSDBA' and 'Password' to 'masterkey' (of course, adjust if your database installation has a different username/password).
  
First you should create a new Lazarus project. For the access to the database we need one ''TIBConnection'', one ''TSQLTransaction'' and one ''[[Working With TSQLQuery|TSQLQuery]]'' component from the 'SQLdb' tab in the component palette. The first component is specified for the access to Interbase or Firebird databases. The other two components can be used for all databases, which are supported by SQLdb. To display the data we use a ''TDBGrid'' component, which can be found on the 'Data Controls' tab. To connect this component with the database components we need a ''TDatasource'' component from the 'Data Access' tab. To trigger the actions we use a ''TButton'' from the 'Standard' tab. Now we have all components, that we need for the first example. You can enlarge the TDBGrid to have enough space to display all data.
+
Now check if all settings so far are correct: set the 'Connected' property to 'True'. If the database path isn't correct or if username or password are wrong, you will get an error message. If the connection was successful, you should cut it now (set 'Connected' to 'False').
  
Next we need to connect our components. A very simple way is to use the object inspector. But you also can do the connections in your source code. Change the 'Transaction' property of IBConnection1 to 'SQLTransaction1'. This cause also, that the 'Database' property of SQLTransaction1 is automatically changed to 'IBConnection1'. In the next step you should change the 'Database' property of SQLQuery1 to 'IBConnection1'. Lazarus automatically adds the value for the 'Transaction' property. Now we change the 'Dataset' property of Datasource1 to 'SQLQuery1'. Finally we change the 'Datasource' property of DBGrid1 to 'Datasource1'.
+
==== PostgreSQL ====
 +
The situation with PostgreSQL is very similar to that on Firebird. The database name does not have a path - you just specify a name part (e.g. 'employee'). PostgreSQL has no embedded mode, so you need to fill out the ''HostName'' property for the connection test to work.
  
But how can we now show the data from our database on the screen? First we need to inform IBConnection1, where the database employee.fdb is located (usually in the .../examples/empbuild/ subdirectory of your Firebird installation). Again you have the choice, if you want to use the object inspector to assign the path or if you want to do it directly in your source code. We choose to use the object inspector. Change the 'DatabaseName' property of IBConnection1 to the path to the employee.fdb file (e.g. C:\Program Files\Firebird\Firebird_2_0\examples\empbuild\EMPLOYEE.FDB). Before the database server is granting the access to the data, he will check the authorisation via username and password. A serious database application will ask the user for both values, when the application is started, to forward them to the server in the appropriate moment. To simplify matters we use the object inspector again. Change the 'UserName' property to 'SYSDBA' and 'Password' to 'masterkey'. To check, if all settings so far are correct, we can set the 'Connected' property to 'True'. If the path isn't correct or if username or password are wrong, you will get an error message. If the connection was successful, you should cut it now (set to 'False').
+
==== SQLite ====
 +
For SQLite, you can leave the 'HostName', 'UserName', and 'Password' properties empty. Set the 'DatabaseName' to the name of your SQLite file, e.g. employee.sqlite. Note: sqlite will create the database specified if it doesn't exist, so be careful here.
  
Although the connection was successful, there were no data displayed. The reason is simple. We haven't told to the database server, which data he should return. The database employee.fdb contains several tables. If you don't know the structure of a database, you can use tools like [http://www.flamerobin.org/index.php FlameRobin], to display the contents. Even Lazarus provides such a tool - the DataDesktop. You can find it in the /tools/lazdatadesktop/ subdirectory of Lazarus. Open the project lazdatadesktop.lpi and compile it (FPC 2.3.x is currently required) (of course you have saved our example project before).  
+
You should now have something like the following screenshot - todo: this screenshot is actually further along, we only have a button now:
 +
[[Image:SQLTut1ComponentsSetUp.png|framed|center|Form and components set up]]
 +
 
 +
=== Choosing what data to show ===
 +
Although the connection was successful, no data was displayed. The reason is simple. We haven't told the database server which data to return: the employee.fdb database contains several tables, and we haven't told Firebird the table we want to see. If you don't know the structure of a database, you can use tools like [http://www.flamerobin.org/index.php FlameRobin], to display the contents. Lazarus also provides such a tool - the [[DataDesktop]]. You can find it in the /tools/lazdatadesktop/ subdirectory of Lazarus. Save our project and then open the project lazdatadesktop.lpi and compile it.  
  
 
[[Image:DataDictonary1.png|framed|center|The DataDesktop in action]]
 
[[Image:DataDictonary1.png|framed|center|The DataDesktop in action]]
  
Back to our example. We want to display all data from the table 'CUSTOMER'. The SQL instruction for that is:
+
Back to our example.  
select * from CUSTOMER
+
 
This instruction we have to assign to the 'SQL' property of SQLQuery1. In the source code of our project this would look like:
+
We want to display all data from the table 'CUSTOMER'. The SQL instruction for that is:
SQLQuery1.SQL.Text := 'select * from CUSTOMER';
+
<syntaxhighlight lang="sql">
The SQL instruction must be enclosed by single quotes. You also have the ability to assign the content of an other component (e.g. Edit1.Text).
+
select * from CUSTOMER
 +
</syntaxhighlight>
 +
 
 +
We need to assign this command to the 'SQL' property of SQLQuery1. In the source code of our project this would look like:
 +
 
 +
<syntaxhighlight lang=pascal>
 +
SQLQuery1.SQL.Text := 'select * from CUSTOMER';
 +
</syntaxhighlight>
 +
 
 +
The SQL instruction must be enclosed by single quotes. You also have the ability to assign the content of another component (e.g. Edit1.Text). This is not always a good idea; see [[Secure programming]] (a more advanced text) for details on SQL injection.
 +
 
 +
Let's add a ''TButton'' from the 'Standard' tab on the form. When the user clicks on the button, data retrieval should start. Change its ''Caption'' property from "Button1" to Show data".
  
The request of the data should start, when the user clicks on the button. With a double click on Button1 Lazarus creates the skeleton of the necessary procedure. In our source code we should find the following lines:
+
We will need some code for this. Double click on Button1. Lazarus then creates the skeleton of the necessary procedure. In our source code we should find the following lines:
  
<pascal>
+
<syntaxhighlight lang=pascal>
 
procedure TForm1.Button1Click(Sender: TObject);
 
procedure TForm1.Button1Click(Sender: TObject);
 
begin
 
begin
  
 
end;             
 
end;             
</pascal>
+
</syntaxhighlight>
 +
 
 +
Between ''begin'' and ''end'' we must enter the instructions needed to display the data.... obviously that will be something to do with SQLQuery1..
 +
 
 +
The 'SQL' property of SQLQuery1 can only be changed, if SQLQuery1 is not active. That's why we close the component first:
 +
 
 +
<syntaxhighlight lang=pascal>
 +
SQLQuery1.Close;
 +
</syntaxhighlight>
 +
 
 +
Then we assign our SQL instruction to the 'SQL' property, overwriting any previous SQL commands:
 +
 
 +
<syntaxhighlight lang=pascal>
 +
SQLQuery1.SQL.Text := 'select * from CUSTOMER';
 +
</syntaxhighlight>
 +
 
 +
Now we need to establish the connection to the database, activate the transaction and open the query:
  
Between ''begin'' and ''end'' we must now enter the instructions, which are needed to display the data. The 'SQL' property of SQLQuery1 can only be changed, if SQLQuery1 is not active. That's why we close the component first:
+
<syntaxhighlight lang=pascal>
SQLQuery1.Close;
+
DBConnection.Connected := True;
Because we can't be sure, if SQLQuery1 still contains any data, we call the 'Clear' procedure:
+
SQLTransaction1.Active := True;
SQLQuery1.SQl.Clear;
+
SQLQuery1.Open;
Then we assign our SQL instruction to the 'SQL' property:
+
</syntaxhighlight>
SQLQuery1.SQL.Text := 'select * from CUSTOMER';
+
You can omit the first two instructions, because they are done automatically by the third instruction. If you compile the project at this point, you could already see the data from the 'CUSTOMER' table.  
Now we need to establish the connection to the database, activating the transcation and open the query:
 
IBConnection1.Connected := True;
 
SQLTransaction1.Active := True;
 
SQLQuery1.Open;
 
You can leave the first two instructions, because they are done automatically by the third instruction (but this will not happen in the contrary case, when you cut the connection). If you would now compile the project, you could already see the data from the table 'CUSTOMER'. But a serious application will take care at the latest, when the application is closed, that all open connections to the database will be closed. Else the secondary effects would not be foreseeable. We use the OnClose event of our form (create it with a double click in the object inspector):
 
  
<pascal>
+
However, a serious application must make sure that all open database connections are properly closed when not needed anymore. Otherwise the secondary effects would not be foreseeable. So, we use the OnClose event of our form (create it with a double click in the object inspector):
 +
 
 +
<syntaxhighlight lang=pascal>
 
procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
 
procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
 
begin
 
begin
  
 
end;             
 
end;             
</pascal>
+
</syntaxhighlight>
 +
 
 +
To close the connection we use the reverse order compared to our opening code:
  
To close the connection we use the contrary oder as during the opening:
+
<syntaxhighlight lang=pascal>
SQLQuery1.Close;
+
SQLQuery1.Close;
SQLTransaction1.Active := False;
+
SQLTransaction1.Active := False;
IBConnection1.Connected := False;
+
DBConnection.Connected := False;
 +
</syntaxhighlight>
  
=== Summary ===
+
If you set DBConnection.Connected to False, the Transaction and the Query is automatically closed and you can omit closing them manually.
  
Until now we have learned, how to connect to a Firebird database using the SQLdb package and how to display the content of a table on the screen.
+
== Summary ==
 +
Up to now we have learned how to connect to a database using the SQLdb package and how to display the contents of a table on the screen.
 +
If you want to add more functionality such as editing, please continue with [[SQLdb Tutorial2]]
  
== Enhancement of example 1 ==
+
If you followed the previous steps, then your code should look like:
  
Wenn sie sich an die bisherigen Schritte gehalten haben, dann sollte ihr Quelltext etwa so aussehen:
+
<syntaxhighlight lang=pascal>
<delphi>
 
 
unit Unit1;  
 
unit Unit1;  
  
Line 78: Line 173:
  
 
uses
 
uses
   Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs,
+
   Classes, SysUtils, IBConnection, sqldb, db, FileUtil, Forms, Controls,
  IBConnection, sqldb, DBGrids, db, StdCtrls;
+
  Graphics, Dialogs, DBGrids, StdCtrls;
  
 
type
 
type
Line 89: Line 184:
 
     Datasource1: TDatasource;
 
     Datasource1: TDatasource;
 
     DBGrid1: TDBGrid;
 
     DBGrid1: TDBGrid;
     IBConnection1: TIBConnection;
+
     DBConnection: TIBConnection;
 
     SQLQuery1: TSQLQuery;
 
     SQLQuery1: TSQLQuery;
 
     SQLTransaction1: TSQLTransaction;
 
     SQLTransaction1: TSQLTransaction;
Line 104: Line 199:
  
 
implementation
 
implementation
 +
 +
{$R *.lfm}
  
 
{ TForm1 }
 
{ TForm1 }
Line 110: Line 207:
 
begin
 
begin
 
   SQLQuery1.Close;
 
   SQLQuery1.Close;
  SQLQuery1.SQL.Clear;
 
 
   SQLQuery1.SQL.Text:= 'select * from CUSTOMER';
 
   SQLQuery1.SQL.Text:= 'select * from CUSTOMER';
   IBConnection1.Connected:= True;
+
   DBConnection.Connected:= True;
 
   SQLTransaction1.Active:= True;
 
   SQLTransaction1.Active:= True;
 
   SQLQuery1.Open;
 
   SQLQuery1.Open;
Line 121: Line 217:
 
   SQLQuery1.Close;
 
   SQLQuery1.Close;
 
   SQLTransaction1.Active:= False;
 
   SQLTransaction1.Active:= False;
   IBConnection1.Connected:= False;
+
   DBConnection.Connected:= False;
 
end;
 
end;
 
initialization
 
  {$I unit1.lrs}
 
  
 
end.                                                 
 
end.                                                 
</delphi>
+
</syntaxhighlight>
  
Nun wird man aber in den seltensten Fällen den kompletten Inhalt einer Tabelle benötigen. Nehmen wir an, es sollen nur die Kunden aus den USA angezeigt werden. Dafür müßte die SQL Anweisung wie folgt lauten:
 
select * from CUSTOMER where COUNTRY = 'USA'
 
Diese Anweisung werden wir aus zwei Gründen nicht für unser Beispielprogramm verwenden: Zum einen gibt es ein Problem bei der Verwendung des einfachen Anführungszeichens. Der Compiler würde das Anführungszeichen vor USA als schließendes Zeichen betrachten (das erste Zeichen steht ja vor select from...) und damit die SQL Anweisung ungültig machen. Der zweite und gewichtigere Grund ist die Tatsache, daß bei der Entwicklung des Programms noch gar nicht bekannt ist, welche Einschränkung der Anzeige später vorgenommen werden soll. Der Benutzer soll in seiner Flexibilität nicht eingeschränkt werden. Dazu ersetzen wir zunächst 'USA' durch einen Platzhalter:
 
select * from CUSTOMER where COUNTRY = :COUNTRY
 
Die Platzhalter sind durch den führenden Doppelpunkt gekennzeichnet. Um dem Benutzer die Eingabe des Filterwertes zu ermöglichen, platzieren sie eine ''TEdit'' Komponente (Seite 'Standard' in der Komponentenpalette) auf ihrem Formular. Löschen sie den Wert der 'Text' Eigenschaft. Über die 'Params' Eigenschaft von TSQLQuery können wir nun mit dem in TEdit eingegebenem Text unseren Platzhalter ersetzen:
 
SQLQuery1.Params.ParamByName('COUNTRY').AsString := Edit1.Text;
 
Der Parameter kann sowohl über seine Position als auch seinen Namen spezifiziert werden. Letzteres dürfte vor allem die Lesbarkeit des Quelltextes verbessern. Insgesamt sollte die Prozedur jetzt so aussehen:
 
<delphi>
 
procedure TForm1.Button1Click(Sender: TObject);
 
begin
 
  SQLQuery1.Close;
 
  SQLQuery1.SQL.Clear;
 
  SQLQuery1.SQL.Text:= 'select * from CUSTOMER where COUNTRY = :COUNTRY';
 
  SQLQuery1.Params.ParamByName('COUNTRY').AsString := Edit1.Text;
 
  IBConnection1.Connected:= True;
 
  SQLTransaction1.Active:= True;
 
  SQLQuery1.Open;
 
end;                                           
 
</delphi>
 
Sie können jetzt ruhig mit den Einstellungen ein wenig herumspielen. Wenn sie einen Filterwert eingeben, der in der Datenbank nicht vorhanden ist, dann wird eine leere Tabelle angezeigt.
 
Es können jedoch auch ernsthafte Probleme auftreten. Da bei einer Client-Server-Anwendung üblicherweise Client und Server räumlich getrennt sind, ist meist nicht auf den ersten Blick ersichtlich, warum es zu einem Problem gekommen ist. Ist der Server heruntergefahren worden oder hat nur jemand einen Stecker gezogen? Zugriffe auf eine Datenbank sollten daher '''immer''' in eine try ... except und/oder try ... finally Schleife eingebunden werden. Nur so ist sichergestellt, daß Datenbankfehler abgefangen werden können und der Anwender nicht im Regen stehengelassen wird. Für unsere Beispielanwendung könnte eine rudimentäre Behandlungsroutine wie folgt aussehen:
 
<delphi>
 
begin
 
  try
 
    SQLQuery1.Close;
 
    ...
 
    SQLQuery1.Open;
 
  except
 
    on EDatabaseError do
 
    begin
 
      MessageDlg('Fehler','Es ist ein Datenbankfehler aufgetreten.',mtError,[mbOK],0);
 
      Edit1.Text:='';
 
    end;
 
  end;
 
end;               
 
</delphi>
 
Hier wird jedoch nur eine einfache Meldung ausgegeben.
 
  
 
== See also ==
 
== See also ==
 
+
* [[SQLdb Tutorial0]]: Instructions for setting up sample tables/sample data for the tutorial series.
* [[SQLdb Package]]: informationen about the SQLdb package
+
* [[SQLdb Tutorial2]]: Second part of the DB tutorial series, showing editing, inserting etc.
* [[SQLdb Programming Reference]]: an overview about the interaction of the SQLdb database components
+
* [[SQLdb Tutorial3]]: Third part of the DB tutorial series, showing how to program for multiple databases and use a login form
* [[SqlDBHowto/nl]]: informationen about the usage of the SQLdb package (dutch language)
+
* [[SQLdb Tutorial4]]: Fourth part of the DB tutorial series, showing how to use data modules
 +
* [[Lazarus Database Overview]]: Information about the databases that Lazarus supports. Links to database-specific notes.
 +
* [[SQLdb Package]]: information about the SQLdb package
 +
* [[SQLdb Programming Reference]]: an overview of the interaction of the SQLdb database components
 +
* [[SqlDBHowto]]: information about using the SQLdb package
 
* [[Working With TSQLQuery]]: information about TSQLQuery
 
* [[Working With TSQLQuery]]: information about TSQLQuery

Revision as of 00:55, 27 February 2020

Deutsch (de) English (en) español (es) français (fr) 日本語 (ja) 中文(中国大陆)‎ (zh_CN)

Databases portal

References:

Tutorials/practical articles:

Databases

Advantage - MySQL - MSSQL - Postgres - Interbase - Firebird - Oracle - ODBC - Paradox - SQLite - dBASE - MS Access - Zeos

Introduction

This tutorial shows you how to program databases using practical example code based on the SQLdb Package. It is primarily targeted at newbies. If somebody is looking for basics about databases and SQL, he should read relevant books/documentation. For this tutorial I use Firebird with the example database employee.fdb. Other databases can also be used; some adjustments will need to be made which are mentioned in the text.

While this tutorial may seem long, it mostly is just a lot of text that explains why you should type what you type. As you can see at the end, the amount of actual code you will need for a working application is not that great. More experienced developers will hopefully be able to glance through the instructions and quickly understand what's going on. Also, you can stop at the end of the Basic example chapter and have a working program.

This tutorial is based on a German tutorial by Swen, but it is extended, especially after the Basic example. Swen wants the German version to remain as-is. If this is a problem, we can rename this version and base a new German translation on that.

From Swen: thanks to Joost and Michael. Without their help this tutorial probably never would have come about.

Requirements

This tutorial is written for use with recent Lazarus versions (Laz 1.0); it should also work on older versions Lazarus 0.9.30.

Please see SQLdb_Tutorial0, which will walk you through making sure you have the right sample database set up.

Basic example

Project and components

First you should create a new Lazarus project.

To get access to our database we need one TIBConnection, one TSQLTransaction and one TSQLQuery component from the 'SQLdb tab' in the component palette:

sqldbcomponents.png

TIBConnection is an Interbase/Firebird specific connection component. If you are using a different database, substitute the proper component from the 'SQLdb tab, e.g. a TSQLite3Connection' for an SQLite database, TPQConnection for a PostgreSQL database. Discussion of setting up any database access libraries is out of scope for this tutorial; see e.g. Databases for that.

Click on the TIBConnection (or equivalent connection component) on your form, and in the Object Inspector, change the name to DBConnection. This will simplify the rest of the tutorial when using different databases. It's also generally a good idea to name your components for something useful in your program (e.g. MainframeDBConnection) so you know what it stands for.

The other two components, TSQLTransaction and TSQLQuery, can be used for all databases that are supported by SQLdb.

To display the data, we use a TDBGrid component, which can be found on the 'Data Controls' tab. To connect this component to the database components we need a TDataSource component from the 'Data Access tab'.

Now we have all database components needed for the first example. You can enlarge the TDBGrid to have enough space to display all data.

Link the components

Next we need to connect our components. A very simple way is to use the object inspector, but you can also do this in your source code.

Change the Transaction property of DBConnection to 'SQLTransaction1'. This causes the Database property of SQLTransaction1 to automatically change to 'DBConnection'.

Then, change the Database property of SQLQuery1 to 'DBConnection'. Lazarus automatically adds the value for the 'Transaction' property.

Next, change the Dataset property of Datasource1 to 'SQLQuery1'.

Finally we change the Datasource property of DBGrid1 to 'Datasource1'.

We now end up with a connection that links its default transaction to a transaction component. The transaction component links its database property to the connection object. These two components are enough to connect and execute instructions, but not enough to show queries. For this, an SQLQuery component is used, which points to the database (and links to its default transaction). With the SQLQuery, we'll later on retrieve data and post it back to the database.

Finally, the datasource component, which is linked to the query component, is a sort of place holder. It keeps track of where in the query dataset we are and the GUI components are linked to that so they all show the same record.

If this is gibberish to you, don't despair: with just some more work, we'll be able to show our first data.

Connecting to the database

How can we now show the data from our database on the screen?

First we need to tell DBConnection where the employee.fdb database is located. Locations of that db differ depending on operating system, it could be something like:

  • .../examples/empbuild/ subdirectory of your Firebird installation on Linux
  • C:\Program Files\Firebird\Firebird_2_5\examples\empbuild\EMPLOYEE.FDB on a Windows machine
  • Using Firebird embedded, the file should be in your project directory

Again you have the choice: you can use the object inspector to assign the path or do it directly in your source code.

We choose to use the object inspector: set the DBConnection 'HostName' property to the Firebird server name or IP adddress. Use localhost if a Firebird server is running on your development machine; use a blank value if you use the embedded Firebird client. Change the DatabaseName property of DBConnection to the path to the employee.fdb file on the database server. If you use embedded Firebird, the path part should be empty and you should just specify the filename.

Before the database server grants access to the data, it will check authorisation via username and password. A serious database application will ask the user for both values when the application is started, and send these to the server when connecting. A possible way of doing this is shown in SQLdb Tutorial3.

However, for now, to simplify matters, we use the object inspector again to hard code these. Change the 'UserName' property to 'SYSDBA' and 'Password' to 'masterkey' (of course, adjust if your database installation has a different username/password).

Now check if all settings so far are correct: set the 'Connected' property to 'True'. If the database path isn't correct or if username or password are wrong, you will get an error message. If the connection was successful, you should cut it now (set 'Connected' to 'False').

PostgreSQL

The situation with PostgreSQL is very similar to that on Firebird. The database name does not have a path - you just specify a name part (e.g. 'employee'). PostgreSQL has no embedded mode, so you need to fill out the HostName property for the connection test to work.

SQLite

For SQLite, you can leave the 'HostName', 'UserName', and 'Password' properties empty. Set the 'DatabaseName' to the name of your SQLite file, e.g. employee.sqlite. Note: sqlite will create the database specified if it doesn't exist, so be careful here.

You should now have something like the following screenshot - todo: this screenshot is actually further along, we only have a button now:

Form and components set up

Choosing what data to show

Although the connection was successful, no data was displayed. The reason is simple. We haven't told the database server which data to return: the employee.fdb database contains several tables, and we haven't told Firebird the table we want to see. If you don't know the structure of a database, you can use tools like FlameRobin, to display the contents. Lazarus also provides such a tool - the DataDesktop. You can find it in the /tools/lazdatadesktop/ subdirectory of Lazarus. Save our project and then open the project lazdatadesktop.lpi and compile it.

The DataDesktop in action

Back to our example.

We want to display all data from the table 'CUSTOMER'. The SQL instruction for that is:

select * from CUSTOMER

We need to assign this command to the 'SQL' property of SQLQuery1. In the source code of our project this would look like:

SQLQuery1.SQL.Text := 'select * from CUSTOMER';

The SQL instruction must be enclosed by single quotes. You also have the ability to assign the content of another component (e.g. Edit1.Text). This is not always a good idea; see Secure programming (a more advanced text) for details on SQL injection.

Let's add a TButton from the 'Standard' tab on the form. When the user clicks on the button, data retrieval should start. Change its Caption property from "Button1" to Show data".

We will need some code for this. Double click on Button1. Lazarus then creates the skeleton of the necessary procedure. In our source code we should find the following lines:

procedure TForm1.Button1Click(Sender: TObject);
begin

end;

Between begin and end we must enter the instructions needed to display the data.... obviously that will be something to do with SQLQuery1..

The 'SQL' property of SQLQuery1 can only be changed, if SQLQuery1 is not active. That's why we close the component first:

SQLQuery1.Close;

Then we assign our SQL instruction to the 'SQL' property, overwriting any previous SQL commands:

SQLQuery1.SQL.Text := 'select * from CUSTOMER';

Now we need to establish the connection to the database, activate the transaction and open the query:

DBConnection.Connected := True;
SQLTransaction1.Active := True;
SQLQuery1.Open;

You can omit the first two instructions, because they are done automatically by the third instruction. If you compile the project at this point, you could already see the data from the 'CUSTOMER' table.

However, a serious application must make sure that all open database connections are properly closed when not needed anymore. Otherwise the secondary effects would not be foreseeable. So, we use the OnClose event of our form (create it with a double click in the object inspector):

procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin

end;

To close the connection we use the reverse order compared to our opening code:

SQLQuery1.Close;
SQLTransaction1.Active := False;
DBConnection.Connected := False;

If you set DBConnection.Connected to False, the Transaction and the Query is automatically closed and you can omit closing them manually.

Summary

Up to now we have learned how to connect to a database using the SQLdb package and how to display the contents of a table on the screen. If you want to add more functionality such as editing, please continue with SQLdb Tutorial2

If you followed the previous steps, then your code should look like:

unit Unit1; 

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, IBConnection, sqldb, db, FileUtil, Forms, Controls,
  Graphics, Dialogs, DBGrids, StdCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    Datasource1: TDatasource;
    DBGrid1: TDBGrid;
    DBConnection: TIBConnection;
    SQLQuery1: TSQLQuery;
    SQLTransaction1: TSQLTransaction;
    procedure Button1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
  private
    { private declarations }
  public
    { public declarations }
  end; 

var
  Form1: TForm1; 

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
begin
  SQLQuery1.Close;
  SQLQuery1.SQL.Text:= 'select * from CUSTOMER';
  DBConnection.Connected:= True;
  SQLTransaction1.Active:= True;
  SQLQuery1.Open;
end;

procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
  SQLQuery1.Close;
  SQLTransaction1.Active:= False;
  DBConnection.Connected:= False;
end;

end.


See also