mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2026-01-05 00:13:39 +01:00
Examles: added SQLdb tutorial from Reinier Olislagers, bug #23389. It shows:
- how to program for multiple DBs - use of DB login form - how to programmatically load and save from/to databases git-svn-id: trunk@39395 -
This commit is contained in:
parent
7bea250603
commit
87f1227012
9
.gitattributes
vendored
9
.gitattributes
vendored
@ -4022,6 +4022,15 @@ examples/database/dblookup/project1.res -text
|
||||
examples/database/dblookup/readme.txt svneol=native#text/plain
|
||||
examples/database/dblookup/unit1.lfm svneol=native#text/plain
|
||||
examples/database/dblookup/unit1.pas svneol=native#text/plain
|
||||
examples/database/sqldbtutorial3/dbconfig.pas svneol=native#text/pascal
|
||||
examples/database/sqldbtutorial3/dbconfiggui.lfm svneol=native#text/plain
|
||||
examples/database/sqldbtutorial3/dbconfiggui.pas svneol=native#text/pascal
|
||||
examples/database/sqldbtutorial3/mainform.lfm svneol=native#text/plain
|
||||
examples/database/sqldbtutorial3/mainform.pas svneol=native#text/pascal
|
||||
examples/database/sqldbtutorial3/readme.txt svneol=native#text/plain
|
||||
examples/database/sqldbtutorial3/sqldbtutorial3.ini svneol=native#text/plain
|
||||
examples/database/sqldbtutorial3/sqldbtutorial3.lpi svneol=native#text/plain
|
||||
examples/database/sqldbtutorial3/sqldbtutorial3.lpr svneol=native#text/pascal
|
||||
examples/dbeditmask/Unit1.lfm svneol=native#text/plain
|
||||
examples/dbeditmask/Unit1.pas svneol=native#text/plain
|
||||
examples/dbeditmask/project1.lpi svneol=native#text/plain
|
||||
|
||||
190
examples/database/sqldbtutorial3/dbconfig.pas
Normal file
190
examples/database/sqldbtutorial3/dbconfig.pas
Normal file
@ -0,0 +1,190 @@
|
||||
unit dbconfig;
|
||||
|
||||
{ Small unit that retrieves connection settings for your database
|
||||
|
||||
Copyright (c) 2012 Reinier Olislagers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
}
|
||||
|
||||
//todo: add command line support (--dbtype=, --db=, --dbhost=, dbuser=, dbpass=, dbcharset=
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, IniFiles;
|
||||
|
||||
type
|
||||
{ TDBConnectionConfig }
|
||||
TDBConnectionConfig = class(TObject)
|
||||
private
|
||||
FDBCharset: string;
|
||||
FDBType: string;
|
||||
FDBHost: string;
|
||||
FDBPath: string;
|
||||
FDBUser: string;
|
||||
FDBPassword: string;
|
||||
FSettingsFileIsRead: boolean; //indicates if we read in settings file
|
||||
FSettingsFile: string;
|
||||
function GetDBCharset: string;
|
||||
function GetDBHost: string;
|
||||
function GetDBPassword: string;
|
||||
function GetDBPath: string;
|
||||
function GetDBType: string;
|
||||
function GetDBUser: string;
|
||||
function GetDefaultSettingsFile:string;
|
||||
procedure ReadINIFile;
|
||||
procedure SetDBType(AValue: string);
|
||||
procedure SetSettingsFile(AValue: string);
|
||||
public
|
||||
property DBCharset: string read GetDBCharset write FDBCharset; //Character set used for database (e.g. UTF8)
|
||||
property DBHost: string read GetDBHost write FDBHost; //Database host/server (name or IP address). Leave empty for embedded
|
||||
property DBPath: string read GetDBPath write FDBPath; //Path/database name
|
||||
property DBUser: string read GetDBUser write FDBUser; //User name needed for database (e.g. sa, SYSDBA)
|
||||
property DBPassword: string read GetDBPassword write FDBPassword; //Password needed for user name
|
||||
property DBType: string read GetDBType write SetDBType; //Type of database connection, e.g. Firebird, Oracle
|
||||
property SettingsFile: string read FSettingsFile write SetSettingsFile; //ini file to read settings from. If empty defaults to <programname>.ini
|
||||
constructor Create;
|
||||
constructor Create(DefaultType:string; DefaultHost:string=''; DefaultPath:string='data.fdb';
|
||||
DefaultUser:string='SYSDBA'; DefaultPassword:string='masterkey'; DefaultCharSet:string='UTF8');
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TDBConnectionConfig }
|
||||
|
||||
function TDBConnectionConfig.GetDBHost: string;
|
||||
begin
|
||||
if not(FSettingsFileIsRead) then ReadINIFile;
|
||||
result:=FDBHost;
|
||||
end;
|
||||
|
||||
function TDBConnectionConfig.GetDBCharset: string;
|
||||
begin
|
||||
if not(FSettingsFileIsRead) then ReadINIFile;
|
||||
result:=FDBCharset;
|
||||
end;
|
||||
|
||||
function TDBConnectionConfig.GetDBPassword: string;
|
||||
begin
|
||||
if not(FSettingsFileIsRead) then ReadINIFile;
|
||||
result:=FDBPassword;
|
||||
end;
|
||||
|
||||
function TDBConnectionConfig.GetDBPath: string;
|
||||
begin
|
||||
if not(FSettingsFileIsRead) then ReadINIFile;
|
||||
result:=FDBPath;
|
||||
end;
|
||||
|
||||
function TDBConnectionConfig.GetDBType: string;
|
||||
begin
|
||||
if not(FSettingsFileIsRead) then ReadINIFile;
|
||||
result:=FDBType;
|
||||
end;
|
||||
|
||||
function TDBConnectionConfig.GetDBUser: string;
|
||||
begin
|
||||
if not(FSettingsFileIsRead) then ReadINIFile;
|
||||
result:=FDBUser;
|
||||
end;
|
||||
|
||||
function TDBConnectionConfig.GetDefaultSettingsFile:string;
|
||||
begin
|
||||
result:=ChangeFileExt(ExtractFileName(ParamStr(0)), '.ini');
|
||||
end;
|
||||
|
||||
procedure TDBConnectionConfig.SetSettingsFile(AValue: string);
|
||||
begin
|
||||
// If empty value given, use the program name
|
||||
if AValue='' then AValue:=GetDefaultSettingsFile;
|
||||
if FSettingsFile=AValue then Exit;
|
||||
FSettingsFile:=AValue;
|
||||
// Read from file if present
|
||||
ReadINIFile;
|
||||
end;
|
||||
|
||||
|
||||
procedure TDBConnectionConfig.SetDBType(AValue: string);
|
||||
begin
|
||||
if FDBType=AValue then Exit;
|
||||
case UpperCase(AValue) of
|
||||
'FIREBIRD': FDBType:='Firebird';
|
||||
'POSTGRES', 'POSTGRESQL': FDBType:='PostgreSQL';
|
||||
'SQLITE','SQLITE3': FDBType:='SQLite';
|
||||
else FDBType:=AValue;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TDBConnectionConfig.ReadINIFile;
|
||||
var
|
||||
INI: TIniFile;
|
||||
begin
|
||||
if FileExists(FSettingsFile) then
|
||||
begin
|
||||
INI := TINIFile.Create(FSettingsFile);
|
||||
try
|
||||
FDBType := INI.ReadString('Database', 'DatabaseType', FDBType); //Default to Firebird
|
||||
FDBHost := INI.ReadString('Database', 'Host', FDBHost);
|
||||
FDBPath := INI.ReadString('Database', 'Database', FDBPath);
|
||||
FDBUser := INI.ReadString('Database', 'User', 'SYSDBA');
|
||||
FDBPassword := INI.ReadString('Database', 'Password', 'masterkey');
|
||||
FSettingsFileIsRead:=true;
|
||||
finally
|
||||
INI.Free;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TDBConnectionConfig.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
// Defaults
|
||||
FSettingsFile:=GetDefaultSettingsFile;
|
||||
FSettingsFileIsRead:=false;
|
||||
FDBType := 'Firebird';
|
||||
FDBHost := ''; //embedded: no hostname
|
||||
FDBPath := 'data.fdb';
|
||||
FDBUser := 'SYSDBA';
|
||||
FDBPassword := 'masterkey';
|
||||
end;
|
||||
|
||||
constructor TDBConnectionConfig.Create(DefaultType:string; DefaultHost:string=''; DefaultPath:string='data.fdb';
|
||||
DefaultUser:string='SYSDBA'; DefaultPassword:string='masterkey'; DefaultCharSet:string='UTF8');
|
||||
begin
|
||||
// First call regular constructor:
|
||||
Create;
|
||||
//... then override properties with what we specified:
|
||||
FDBCharset:=DefaultCharset;
|
||||
FDBHost:=DefaultHost;
|
||||
FDBPassword:=DefaultPassword;
|
||||
FDBPath:=DefaultPath;
|
||||
FDBType:=DefaultType;
|
||||
FDBUser:=DefaultUser;
|
||||
end;
|
||||
|
||||
destructor TDBConnectionConfig.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
125
examples/database/sqldbtutorial3/dbconfiggui.lfm
Normal file
125
examples/database/sqldbtutorial3/dbconfiggui.lfm
Normal file
@ -0,0 +1,125 @@
|
||||
object DBConfigForm: TDBConfigForm
|
||||
Left = 342
|
||||
Height = 400
|
||||
Top = 218
|
||||
Width = 499
|
||||
Caption = 'Database credentials'
|
||||
ClientHeight = 400
|
||||
ClientWidth = 499
|
||||
OnCreate = FormCreate
|
||||
OnDestroy = FormDestroy
|
||||
OnShow = FormShow
|
||||
LCLVersion = '1.0.2.0'
|
||||
object ConnectorType: TComboBox
|
||||
Left = 112
|
||||
Height = 23
|
||||
Top = 42
|
||||
Width = 364
|
||||
ItemHeight = 15
|
||||
OnEditingDone = ConnectorTypeEditingDone
|
||||
TabOrder = 0
|
||||
Text = 'ConnectorType'
|
||||
end
|
||||
object Host: TEdit
|
||||
Left = 112
|
||||
Height = 23
|
||||
Top = 87
|
||||
Width = 192
|
||||
OnEditingDone = HostEditingDone
|
||||
TabOrder = 1
|
||||
end
|
||||
object Database: TEdit
|
||||
Left = 112
|
||||
Height = 23
|
||||
Top = 128
|
||||
Width = 192
|
||||
OnEditingDone = DatabaseEditingDone
|
||||
TabOrder = 2
|
||||
end
|
||||
object Password: TEdit
|
||||
Left = 112
|
||||
Height = 23
|
||||
Top = 217
|
||||
Width = 192
|
||||
EchoMode = emPassword
|
||||
OnEditingDone = PasswordEditingDone
|
||||
PasswordChar = '*'
|
||||
TabOrder = 4
|
||||
end
|
||||
object User: TEdit
|
||||
Left = 112
|
||||
Height = 23
|
||||
Top = 176
|
||||
Width = 192
|
||||
OnEditingDone = UserEditingDone
|
||||
TabOrder = 3
|
||||
end
|
||||
object Label1: TLabel
|
||||
Left = 16
|
||||
Height = 16
|
||||
Top = 42
|
||||
Width = 75
|
||||
Caption = 'Database type'
|
||||
ParentColor = False
|
||||
end
|
||||
object Label2: TLabel
|
||||
Left = 16
|
||||
Height = 16
|
||||
Top = 87
|
||||
Width = 26
|
||||
Caption = 'Host'
|
||||
ParentColor = False
|
||||
end
|
||||
object Label3: TLabel
|
||||
Left = 16
|
||||
Height = 16
|
||||
Top = 128
|
||||
Width = 49
|
||||
Caption = 'Database'
|
||||
ParentColor = False
|
||||
end
|
||||
object Label4: TLabel
|
||||
Left = 16
|
||||
Height = 16
|
||||
Top = 176
|
||||
Width = 24
|
||||
Caption = 'User'
|
||||
ParentColor = False
|
||||
end
|
||||
object Label5: TLabel
|
||||
Left = 16
|
||||
Height = 16
|
||||
Top = 217
|
||||
Width = 51
|
||||
Caption = 'Password'
|
||||
ParentColor = False
|
||||
end
|
||||
object OKButton: TButton
|
||||
Left = 407
|
||||
Height = 25
|
||||
Top = 356
|
||||
Width = 75
|
||||
Caption = 'OK'
|
||||
ModalResult = 1
|
||||
TabOrder = 5
|
||||
end
|
||||
object CancelButton: TButton
|
||||
Left = 312
|
||||
Height = 25
|
||||
Top = 356
|
||||
Width = 75
|
||||
Cancel = True
|
||||
Caption = 'Cancel'
|
||||
ModalResult = 2
|
||||
TabOrder = 6
|
||||
end
|
||||
object TestButton: TButton
|
||||
Left = 229
|
||||
Height = 25
|
||||
Top = 264
|
||||
Width = 75
|
||||
Caption = 'Test'
|
||||
OnClick = TestButtonClick
|
||||
TabOrder = 7
|
||||
end
|
||||
end
|
||||
121
examples/database/sqldbtutorial3/dbconfiggui.pas
Normal file
121
examples/database/sqldbtutorial3/dbconfiggui.pas
Normal file
@ -0,0 +1,121 @@
|
||||
unit dbconfiggui;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, dbconfig;
|
||||
|
||||
type
|
||||
TConnectionTestFunction = function(ChosenConfig: TDBConnectionConfig): boolean of object;
|
||||
{ TDBConfigForm }
|
||||
|
||||
TDBConfigForm = class(TForm)
|
||||
OKButton: TButton;
|
||||
CancelButton: TButton;
|
||||
TestButton: TButton;
|
||||
ConnectorType: TComboBox;
|
||||
Host: TEdit;
|
||||
Database: TEdit;
|
||||
Label1: TLabel;
|
||||
Label2: TLabel;
|
||||
Label3: TLabel;
|
||||
Label4: TLabel;
|
||||
Label5: TLabel;
|
||||
Password: TEdit;
|
||||
User: TEdit;
|
||||
procedure ConnectorTypeEditingDone(Sender: TObject);
|
||||
procedure DatabaseEditingDone(Sender: TObject);
|
||||
procedure FormCreate(Sender: TObject);
|
||||
procedure FormDestroy(Sender: TObject);
|
||||
procedure FormShow(Sender: TObject);
|
||||
procedure HostEditingDone(Sender: TObject);
|
||||
procedure PasswordEditingDone(Sender: TObject);
|
||||
procedure TestButtonClick(Sender: TObject);
|
||||
procedure UserEditingDone(Sender: TObject);
|
||||
private
|
||||
FConnectionConfig: TDBConnectionConfig;
|
||||
FConnectionTestFunction: TConnectionTestFunction;
|
||||
FSetupComplete: boolean;
|
||||
{ private declarations }
|
||||
public
|
||||
property Config: TDBConnectionConfig read FConnectionConfig;
|
||||
property ConnectionTestCallback: TConnectionTestFunction write FConnectionTestFunction;
|
||||
{ public declarations }
|
||||
end;
|
||||
|
||||
var
|
||||
DBConfigForm: TDBConfigForm;
|
||||
|
||||
implementation
|
||||
|
||||
{$R *.lfm}
|
||||
|
||||
{ TDBConfigForm }
|
||||
|
||||
procedure TDBConfigForm.TestButtonClick(Sender: TObject);
|
||||
begin
|
||||
// Call callback with settings, let it figure out if connection succeeded and
|
||||
// get test result back
|
||||
if assigned(FConnectionTestFunction) and assigned(FConnectionConfig) then
|
||||
if FConnectionTestFunction(FConnectionConfig) then
|
||||
showmessage('Connection test succeeded.')
|
||||
else
|
||||
showmessage('Connection test failed.')
|
||||
else
|
||||
showmessage('Error: connection test code has not been implemented.');
|
||||
end;
|
||||
|
||||
procedure TDBConfigForm.UserEditingDone(Sender: TObject);
|
||||
begin
|
||||
FConnectionConfig.DBUser:=User.Text;
|
||||
end;
|
||||
|
||||
procedure TDBConfigForm.FormCreate(Sender: TObject);
|
||||
begin
|
||||
FConnectionConfig:=TDBConnectionConfig.Create;
|
||||
FSetupComplete:=false;
|
||||
end;
|
||||
|
||||
procedure TDBConfigForm.ConnectorTypeEditingDone(Sender: TObject);
|
||||
begin
|
||||
FConnectionConfig.DBType:=ConnectorType.Text;
|
||||
end;
|
||||
|
||||
procedure TDBConfigForm.DatabaseEditingDone(Sender: TObject);
|
||||
begin
|
||||
FConnectionConfig.DBPath:=Database.Text;
|
||||
end;
|
||||
|
||||
procedure TDBConfigForm.FormDestroy(Sender: TObject);
|
||||
begin
|
||||
FConnectionConfig.Free;
|
||||
end;
|
||||
|
||||
procedure TDBConfigForm.FormShow(Sender: TObject);
|
||||
begin
|
||||
if not FSetupComplete then
|
||||
begin
|
||||
// Only do this once in form's lifetime
|
||||
FSetupComplete:=true;
|
||||
ConnectorType.Text:=FConnectionConfig.DBType;
|
||||
Host.Text:=FConnectionConfig.DBHost;
|
||||
Database.Text:=FConnectionConfig.DBPath;
|
||||
User.Text:=FConnectionConfig.DBUser;
|
||||
Password.Text:=FConnectionConfig.DBPassword;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TDBConfigForm.HostEditingDone(Sender: TObject);
|
||||
begin
|
||||
FConnectionConfig.DBHost:=Host.Text;
|
||||
end;
|
||||
|
||||
procedure TDBConfigForm.PasswordEditingDone(Sender: TObject);
|
||||
begin
|
||||
FConnectionConfig.DBPassword:=Password.Text;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
23
examples/database/sqldbtutorial3/mainform.lfm
Normal file
23
examples/database/sqldbtutorial3/mainform.lfm
Normal file
@ -0,0 +1,23 @@
|
||||
object Form1: TForm1
|
||||
Left = 361
|
||||
Height = 387
|
||||
Top = 162
|
||||
Width = 455
|
||||
Caption = 'SQLDB Tutorial3'
|
||||
ClientHeight = 387
|
||||
ClientWidth = 455
|
||||
OnCreate = FormCreate
|
||||
OnDestroy = FormDestroy
|
||||
LCLVersion = '1.0.2.0'
|
||||
object SalaryGrid: TStringGrid
|
||||
Left = 8
|
||||
Height = 104
|
||||
Top = 48
|
||||
Width = 432
|
||||
ColCount = 4
|
||||
Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goEditing, goSmoothScroll]
|
||||
RowCount = 4
|
||||
TabOrder = 0
|
||||
OnValidateEntry = SalaryGridValidateEntry
|
||||
end
|
||||
end
|
||||
299
examples/database/sqldbtutorial3/mainform.pas
Normal file
299
examples/database/sqldbtutorial3/mainform.pas
Normal file
@ -0,0 +1,299 @@
|
||||
unit mainform;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Grids,
|
||||
dbconfiggui,dbconfig,
|
||||
{General db unit}sqldb,
|
||||
{For EDataBaseError}db,
|
||||
{Now we add all databases we want to support, otherwise their drivers won't be loaded}
|
||||
IBConnection,pqconnection,sqlite3conn;
|
||||
|
||||
type
|
||||
|
||||
{ TForm1 }
|
||||
|
||||
TForm1 = class(TForm)
|
||||
SalaryGrid: TStringGrid;
|
||||
procedure FormCreate(Sender: TObject);
|
||||
procedure FormDestroy(Sender: TObject);
|
||||
procedure SalaryGridValidateEntry(sender: TObject; aCol, aRow: Integer;
|
||||
const OldValue: string; var NewValue: String);
|
||||
private
|
||||
{ private declarations }
|
||||
FConn: TSQLConnector;
|
||||
FQuery: TSQLQuery;
|
||||
FTran: TSQLTransaction;
|
||||
function ConnectionTest(ChosenConfig: TDBConnectionConfig): boolean;
|
||||
procedure LoadSalaryGrid;
|
||||
public
|
||||
{ public declarations }
|
||||
end;
|
||||
|
||||
var
|
||||
Form1: TForm1;
|
||||
|
||||
implementation
|
||||
|
||||
{$R *.lfm}
|
||||
|
||||
{ TForm1 }
|
||||
|
||||
procedure TForm1.FormCreate(Sender: TObject);
|
||||
var
|
||||
LoginForm: TDBConfigForm;
|
||||
begin
|
||||
FConn:=TSQLConnector.Create(nil);
|
||||
FQuery:=TSQLQuery.Create(nil);
|
||||
FTran:=TSQLTransaction.Create(nil);
|
||||
FConn.Transaction:=FTran;
|
||||
FQuery.DataBase:=FConn;
|
||||
|
||||
LoginForm:=TDBConfigForm.Create(self);
|
||||
try
|
||||
// The test button on dbconfiggui will link to this procedure:
|
||||
LoginForm.ConnectionTestCallback:=@ConnectionTest;
|
||||
LoginForm.ConnectorType.Clear; //remove any default connectors
|
||||
// Now add the dbs that you support - use the name of the *ConnectionDef.TypeName property
|
||||
LoginForm.ConnectorType.AddItem('Firebird', nil);
|
||||
LoginForm.ConnectorType.AddItem('PostGreSQL', nil);
|
||||
LoginForm.ConnectorType.AddItem('SQLite3', nil); //No connectiondef object yet in FPC2.6.0
|
||||
case LoginForm.ShowModal of
|
||||
mrOK:
|
||||
begin
|
||||
//user wants to connect, so copy over db info
|
||||
FConn.ConnectorType:=LoginForm.Config.DBType;
|
||||
FConn.HostName:=LoginForm.Config.DBHost;
|
||||
FConn.DatabaseName:=LoginForm.Config.DBPath;
|
||||
FConn.UserName:=LoginForm.Config.DBUser;
|
||||
FConn.Password:=LoginForm.Config.DBPassword;
|
||||
FConn.Transaction:=FTran;
|
||||
end;
|
||||
mrCancel:
|
||||
begin
|
||||
ShowMessage('You canceled the database login. Application will terminate.');
|
||||
Close;
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
LoginForm.Free;
|
||||
end;
|
||||
|
||||
// Now load in our db details
|
||||
LoadSalaryGrid;
|
||||
end;
|
||||
|
||||
procedure TForm1.FormDestroy(Sender: TObject);
|
||||
begin
|
||||
FQuery.Free;
|
||||
FTran.Free;
|
||||
FConn.Free;
|
||||
end;
|
||||
|
||||
procedure TForm1.SalaryGridValidateEntry(sender: TObject; aCol, aRow: Integer;
|
||||
const OldValue: string; var NewValue: String);
|
||||
begin
|
||||
if (aCol=3) and ((aRow=1) or (aRow=2)) then
|
||||
begin
|
||||
// Allow updates to min and max salary if positive numerical data is entered
|
||||
if StrToFloatDef(NewValue,-1)>0 then
|
||||
begin
|
||||
// Storing the primary key in e.g. a hidden cell in the grid and using that in our
|
||||
// update query would be cleaner, but we can do it the hard way as well:
|
||||
FQuery.SQL.Text:='update employee set salary=:newsalary '+
|
||||
' where first_name=:firstname and last_name=:lastname and salary=:salary ';
|
||||
FQuery.Params.ParamByName('newsalary').AsFloat:=StrToFloatDef(NewValue,0);
|
||||
FQuery.Params.ParamByName('firstname').AsString:=SalaryGrid.Cells[1,aRow];
|
||||
FQuery.Params.ParamByName('lastname').AsString:=SalaryGrid.Cells[2,aRow];
|
||||
FQuery.Params.ParamByName('salary').AsFloat:=StrToFloatDef(OldValue,0);
|
||||
FTran.StartTransaction;
|
||||
FQuery.ExecSQL;
|
||||
FTran.Commit;
|
||||
LoadSalaryGrid; //reload standard deviation
|
||||
end
|
||||
else
|
||||
begin
|
||||
showmessage('Invalid salary entered.');
|
||||
NewValue:=OldValue;
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
// Discard edits to any other cells
|
||||
NewValue:=OldValue;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TForm1.ConnectionTest(ChosenConfig: TDBConnectionConfig): boolean;
|
||||
// Callback function that uses the info in dbconfiggui to test a connection
|
||||
// and return the result of the test to dbconfiggui
|
||||
var
|
||||
// Generic database connector...
|
||||
Conn: TSQLConnector;
|
||||
begin
|
||||
result:=false;
|
||||
Conn:=TSQLConnector.Create(nil);
|
||||
Screen.Cursor:=crHourglass;
|
||||
try
|
||||
// ...actual connector type is determined by this property.
|
||||
// Make sure the ChosenConfig.DBType string matches
|
||||
// the connectortype (e.g. see the string in the
|
||||
// T*ConnectionDef.TypeName for that connector .
|
||||
Conn.ConnectorType:=ChosenConfig.DBType;
|
||||
Conn.HostName:=ChosenConfig.DBHost;
|
||||
Conn.DatabaseName:=ChosenConfig.DBPath;
|
||||
Conn.UserName:=ChosenConfig.DBUser;
|
||||
Conn.Password:=ChosenConfig.DBPassword;
|
||||
try
|
||||
Conn.Open;
|
||||
result:=Conn.Connected;
|
||||
except
|
||||
// Result is already false
|
||||
end;
|
||||
Conn.Close;
|
||||
finally
|
||||
Screen.Cursor:=crDefault;
|
||||
Conn.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TForm1.LoadSalaryGrid;
|
||||
var
|
||||
Average: double;
|
||||
DifferencesSquared: double=0;
|
||||
Count: integer=0;
|
||||
begin
|
||||
// Clean out
|
||||
SalaryGrid.BeginUpdate;
|
||||
try
|
||||
SalaryGrid.ColCount:=4;
|
||||
SalaryGrid.RowCount:=4; //Header+3 detail rows
|
||||
SalaryGrid.Clean;
|
||||
SalaryGrid.Cells[1,0]:='First name';
|
||||
SalaryGrid.Cells[2,0]:='Surname';
|
||||
SalaryGrid.Cells[3,0]:='Salary';
|
||||
SalaryGrid.Cells[0,1]:='Min';
|
||||
SalaryGrid.Cells[0,2]:='Max';
|
||||
SalaryGrid.Cells[0,3]:='StdDev';
|
||||
// Load from DB
|
||||
try
|
||||
if not(FConn.Connected) then
|
||||
FConn.Open;
|
||||
{
|
||||
// This possible query works but is slow:
|
||||
// a nasty query if there are lots of rows in employee
|
||||
// because the subqueries in the where condition are run for each employee
|
||||
// in the table.
|
||||
// We use order by to make sure the lowest salary is presented first, then
|
||||
// the highest.
|
||||
SalaryQuery.SQL.Text:='select ' +
|
||||
' first_name, ' +
|
||||
' last_name, ' +
|
||||
' salary ' +
|
||||
' from employee ' +
|
||||
' where ' +
|
||||
' salary=(select min(salary) from employee) or ' +
|
||||
' salary=(select max(salary) from employee) ' +
|
||||
' order by salary ' ;
|
||||
}
|
||||
if FConn.Connected=false then
|
||||
begin
|
||||
ShowMessage('Error connecting to the database. Aborting data loading.');
|
||||
exit;
|
||||
end;
|
||||
|
||||
// Lowest salary
|
||||
// Note: we would like to only retrieve 1 row, but unfortunately the SQL
|
||||
// used differs for various dbs. As we'll deal with db dependent SQL later
|
||||
// in the tutorial, we leave this for now.
|
||||
// MS SQL: 'select top 1 '...
|
||||
FQuery.SQL.Text:='select ' +
|
||||
' e.first_name, ' +
|
||||
' e.last_name, ' +
|
||||
' e.salary ' +
|
||||
'from employee e ' +
|
||||
'order by e.salary asc ';
|
||||
// ISO SQL+Firebird SQL: add
|
||||
//'rows 1 '; here and below... won't work on e.g. PostgreSQL though
|
||||
FTran.StartTransaction;
|
||||
FQuery.Open;
|
||||
SalaryGrid.Cells[1,1]:=FQuery.Fields[0].AsString;
|
||||
SalaryGrid.Cells[2,1]:=FQuery.Fields[1].AsString;
|
||||
SalaryGrid.Cells[3,1]:=FQuery.Fields[2].AsString;
|
||||
FQuery.Close;
|
||||
// Always commit(retain) an opened transaction, even if only reading
|
||||
// this will allow updates by others to be seen when reading again
|
||||
FTran.Commit;
|
||||
|
||||
// Highest salary
|
||||
FQuery.SQL.Text:='select ' +
|
||||
' e.first_name, ' +
|
||||
' e.last_name, ' +
|
||||
' e.salary ' +
|
||||
'from employee e ' +
|
||||
'order by e.salary desc ';
|
||||
FTran.StartTransaction;
|
||||
FQuery.Open;
|
||||
SalaryGrid.Cells[1,2]:=FQuery.Fields[0].AsString;
|
||||
SalaryGrid.Cells[2,2]:=FQuery.Fields[1].AsString;
|
||||
SalaryGrid.Cells[3,2]:=FQuery.Fields[2].AsString;
|
||||
FQuery.Close;
|
||||
// Always commit(retain) an opened transaction, even if only reading
|
||||
FTran.Commit;
|
||||
|
||||
FTran.StartTransaction;
|
||||
if FConn.ConnectorType='PostGreSQL' then
|
||||
begin
|
||||
// For PostgreSQL, use a native SQL solution:
|
||||
FQuery.SQL.Text:='select stddev_pop(salary) from employee ';
|
||||
FTran.StartTransaction;
|
||||
FQuery.Open;
|
||||
if not(FQuery.EOF) then
|
||||
SalaryGrid.Cells[3,3]:=FQuery.Fields[0].AsString;
|
||||
FQuery.Close;
|
||||
// Always commit(retain) an opened transaction, even if only reading
|
||||
end
|
||||
else
|
||||
begin
|
||||
// For other databases, use the code approach:
|
||||
// 1. Get average of values
|
||||
FQuery.SQL.Text:='select avg(salary) from employee ';
|
||||
FQuery.Open;
|
||||
if (FQuery.EOF) then
|
||||
SalaryGrid.Cells[3,3]:='No data'
|
||||
else
|
||||
begin
|
||||
Average:=FQuery.Fields[0].AsFloat;
|
||||
FQuery.Close;
|
||||
// 2. For each value, calculate the square of (value-average), and add it up
|
||||
FQuery.SQL.Text:='select salary from employee where salary is not null ';
|
||||
FQuery.Open;
|
||||
while not(FQuery.EOF) do
|
||||
begin
|
||||
DifferencesSquared:=DifferencesSquared+Sqr(FQuery.Fields[0].AsFloat-Average);
|
||||
Count:=Count+1;
|
||||
FQuery.Next;
|
||||
end;
|
||||
// 3. Now calculate the average "squared difference" and take the square root
|
||||
SalaryGrid.Cells[3,3]:=FloatToStr(Sqrt(DifferencesSquared/Count));
|
||||
end;
|
||||
FQuery.Close;
|
||||
end;
|
||||
FTran.Commit;
|
||||
except
|
||||
on D: EDatabaseError do
|
||||
begin
|
||||
MessageDlg('Error', 'A database error has occurred. Technical error message: ' +
|
||||
D.Message, mtError, [mbOK], 0);
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
SalaryGrid.EndUpdate;
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
8
examples/database/sqldbtutorial3/readme.txt
Normal file
8
examples/database/sqldbtutorial3/readme.txt
Normal file
@ -0,0 +1,8 @@
|
||||
SQLdb Tutorial3
|
||||
===============
|
||||
|
||||
This directory has the accompanying code for
|
||||
http://wiki.lazarus.freepascal.org/SQLdb_Tutorial3
|
||||
|
||||
Please see that article for instructions and requirements.
|
||||
(You'll need database clients and a sample database; see the article)
|
||||
6
examples/database/sqldbtutorial3/sqldbtutorial3.ini
Normal file
6
examples/database/sqldbtutorial3/sqldbtutorial3.ini
Normal file
@ -0,0 +1,6 @@
|
||||
[Database]
|
||||
DatabaseType=Firebird
|
||||
Host=127.0.0.1
|
||||
Database=employee
|
||||
User=SYSDBA
|
||||
Password=masterkey
|
||||
124
examples/database/sqldbtutorial3/sqldbtutorial3.lpi
Normal file
124
examples/database/sqldbtutorial3/sqldbtutorial3.lpi
Normal file
@ -0,0 +1,124 @@
|
||||
<?xml version="1.0"?>
|
||||
<CONFIG>
|
||||
<ProjectOptions>
|
||||
<Version Value="9"/>
|
||||
<PathDelim Value="\"/>
|
||||
<General>
|
||||
<SessionStorage Value="InProjectDir"/>
|
||||
<MainUnit Value="0"/>
|
||||
<Title Value="sqldbtutorial3"/>
|
||||
<ResourceType Value="res"/>
|
||||
<UseXPManifest Value="True"/>
|
||||
</General>
|
||||
<i18n>
|
||||
<EnableI18N LFM="False"/>
|
||||
</i18n>
|
||||
<VersionInfo>
|
||||
<StringTable ProductVersion=""/>
|
||||
</VersionInfo>
|
||||
<BuildModes Count="2">
|
||||
<Item1 Name="Default" Default="True"/>
|
||||
<Item2 Name="Debug">
|
||||
<CompilerOptions>
|
||||
<Version Value="11"/>
|
||||
<PathDelim Value="\"/>
|
||||
<SearchPaths>
|
||||
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||
</SearchPaths>
|
||||
<Linking>
|
||||
<Options>
|
||||
<Win32>
|
||||
<GraphicApplication Value="True"/>
|
||||
</Win32>
|
||||
</Options>
|
||||
</Linking>
|
||||
<Other>
|
||||
<CompilerMessages>
|
||||
<UseMsgFile Value="True"/>
|
||||
</CompilerMessages>
|
||||
<CompilerPath Value="$(CompPath)"/>
|
||||
</Other>
|
||||
</CompilerOptions>
|
||||
</Item2>
|
||||
</BuildModes>
|
||||
<PublishOptions>
|
||||
<Version Value="2"/>
|
||||
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
|
||||
<ExcludeFileFilter Value="*.(bak|ppu|o|so);*~;backup"/>
|
||||
</PublishOptions>
|
||||
<RunParams>
|
||||
<local>
|
||||
<FormatVersion Value="1"/>
|
||||
</local>
|
||||
</RunParams>
|
||||
<RequiredPackages Count="1">
|
||||
<Item1>
|
||||
<PackageName Value="LCL"/>
|
||||
</Item1>
|
||||
</RequiredPackages>
|
||||
<Units Count="4">
|
||||
<Unit0>
|
||||
<Filename Value="sqldbtutorial3.lpr"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="sqldbtutorial3"/>
|
||||
</Unit0>
|
||||
<Unit1>
|
||||
<Filename Value="mainform.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<ComponentName Value="Form1"/>
|
||||
<HasResources Value="True"/>
|
||||
<ResourceBaseClass Value="Form"/>
|
||||
<UnitName Value="mainform"/>
|
||||
</Unit1>
|
||||
<Unit2>
|
||||
<Filename Value="dbconfig.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="dbconfig"/>
|
||||
</Unit2>
|
||||
<Unit3>
|
||||
<Filename Value="dbconfiggui.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<ComponentName Value="DBConfigForm"/>
|
||||
<HasResources Value="True"/>
|
||||
<ResourceBaseClass Value="Form"/>
|
||||
<UnitName Value="dbconfiggui"/>
|
||||
</Unit3>
|
||||
</Units>
|
||||
</ProjectOptions>
|
||||
<CompilerOptions>
|
||||
<Version Value="11"/>
|
||||
<PathDelim Value="\"/>
|
||||
<SearchPaths>
|
||||
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||
</SearchPaths>
|
||||
<Linking>
|
||||
<Debugging>
|
||||
<GenerateDebugInfo Value="False"/>
|
||||
</Debugging>
|
||||
<Options>
|
||||
<Win32>
|
||||
<GraphicApplication Value="True"/>
|
||||
</Win32>
|
||||
</Options>
|
||||
</Linking>
|
||||
<Other>
|
||||
<CompilerMessages>
|
||||
<UseMsgFile Value="True"/>
|
||||
</CompilerMessages>
|
||||
<CompilerPath Value="$(CompPath)"/>
|
||||
</Other>
|
||||
</CompilerOptions>
|
||||
<Debugging>
|
||||
<Exceptions Count="3">
|
||||
<Item1>
|
||||
<Name Value="EAbort"/>
|
||||
</Item1>
|
||||
<Item2>
|
||||
<Name Value="ECodetoolError"/>
|
||||
</Item2>
|
||||
<Item3>
|
||||
<Name Value="EFOpenError"/>
|
||||
</Item3>
|
||||
</Exceptions>
|
||||
</Debugging>
|
||||
</CONFIG>
|
||||
26
examples/database/sqldbtutorial3/sqldbtutorial3.lpr
Normal file
26
examples/database/sqldbtutorial3/sqldbtutorial3.lpr
Normal file
@ -0,0 +1,26 @@
|
||||
program sqldbtutorial3;
|
||||
{
|
||||
This is the accompanying project for
|
||||
http://wiki.lazarus.freepascal.org/SQLdb_Tutorial3
|
||||
|
||||
Please see that article for instructions and requirements.
|
||||
(You'll need database clients and a sample database; see the article)
|
||||
}
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
uses
|
||||
{$IFDEF UNIX}{$IFDEF UseCThreads}
|
||||
cthreads,
|
||||
{$ENDIF}{$ENDIF}
|
||||
Interfaces, // this includes the LCL widgetset
|
||||
Forms, mainform, dbconfiggui;
|
||||
|
||||
{$R *.res}
|
||||
|
||||
begin
|
||||
RequireDerivedFormResource := True;
|
||||
Application.Initialize;
|
||||
Application.CreateForm(TForm1, Form1);
|
||||
Application.Run;
|
||||
end.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user