Examples: added SQLite3 Demo with Encryption and Pragma by Jack Linke, bug #26479

git-svn-id: trunk@46000 -
This commit is contained in:
maxim 2014-07-31 21:12:33 +00:00
parent 8e1ff48dfa
commit e6c7b22177
7 changed files with 1088 additions and 0 deletions

6
.gitattributes vendored
View File

@ -4551,6 +4551,12 @@ 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/database/sqlite_encryption_pragma/README.txt svneol=native#text/plain
examples/database/sqlite_encryption_pragma/project1.lpi svneol=native#text/plain
examples/database/sqlite_encryption_pragma/project1.lpr svneol=native#text/pascal
examples/database/sqlite_encryption_pragma/project1.res -text
examples/database/sqlite_encryption_pragma/unit1.lfm svneol=native#text/plain
examples/database/sqlite_encryption_pragma/unit1.pas svneol=native#text/pascal
examples/database/sqlite_mushrooms/ImageTest.db3 -text
examples/database/sqlite_mushrooms/Mushroom_Report.lrf svneol=native#text/plain
examples/database/sqlite_mushrooms/Readme.txt svneol=native#text/plain

View File

@ -0,0 +1,200 @@
////////////////////////////////////////////////////
// //
// Simple SQLite3 Demo with Encryption and Pragma //
// //
////////////////////////////////////////////////////
// //
// CONTENTS //
// //
// 1. OVERVIEW OF THIS DEMONSTRATION //
// 2. REQUIREMENTS FOR SQLITE ENCRYPTION //
// 3. SQLITE PRAGMA STATEMENTS //
// 4. ADDITIONAL SQLITE RESOURCES //
// //
////////////////////////////////////////////////////
1. OVERVIEW OF THIS DEMONSTRATION
This application very simply demonstrates the following capabilities:
- Creation of an SQLite3 Database
- Encrypting the database using a key
- Changing (or setting if not initially set) the encryption key for the
database after it has been created
- Creation of a database table
- Creating an Index
- Adding a row of data to the table
- Performing a very basic query
- Setting and reading various database metadata (Pragma)
The application makes a new database file "new.db" within the local
directory.
I highly recommend using a third party SQLite Database Management Tool to
verify the table and index creation and encryption of your database.
You'll want to use one that supports SQLite 3.6.8 or later. I use SQLite2009
Pro Enterprise Manager. This and other tools can be found at:
http://www.sqlite.org/cvstrac/wiki?p=ManagementTools
2. REQUIREMENTS FOR SQLITE ENCRYPTION
Since version 3.6.8 SQLite has supported the option of database encryption
(though it must be supported specifically by the version of the sqlite3.dll
you use for your application). The entire database, except for bytes 16
through 23, will be encrypted. See the additional resources at the end of
this document for more details about the SQLite Database Header, and these
specific bytes.
Using the following link, you can find a few options for versions of SQLite
that provide support for encryption. Since I'm working mainly on Windows, I
opted for the Open Source System.Data.SQLite
http://wiki.freepascal.org/sqlite#Support_for_SQLite_encryption
I used the "Precompiled Binaries for 32-bit Windows (.NET Framework 3.5 SP1)"
and renamed SQLite.Interop.dll to sqlite3.dll, but you should be able to use
any version of applicable SQLite DLL you want as long as you have the
required dependencies (.NET Framework and VC++ Redistributables.
http://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki
When selecting the DLL to use, if you have the latest version of the .NET
framework installed on your computer (4.5.1) and the Visual Studio 2013
Redistributable Package, then you should be able to use this:
http://system.data.sqlite.org/downloads/1.0.93.0/sqlite-netFx451-binary-x64-2013-1.0.93.0.zip
Just extract the SQLite.Interop.dll and rename it to sqlite3.dll and place
it in the local directory. Again, you'll want to download a version that
matches the version of .NET and Visual C++ Runtime on your computer (you
may have many/all the versions of .NET and VC++ Redists installed).
You can download various versions of the .NET framework at:
http://msdn.microsoft.com/en-us/vstudio/aa496123.aspx
You can download various versions of the Visual C++ Redistributables at:
http://support.microsoft.com/kb/2019667
Make sure the sqlite3.dll is in the same directory as your application,
or you *will* have errors, and your application will not work!
3. SQLITE PRAGMA STATEMENTS
SQLite Pragma are metadata variables and constants that are stored in the
header of an SQLite Database. Most of these values are read-only or are not
recommended to be changed, but a few of them can be set for various purposes
in your application.
This demonstration application performs a few different Pragma operations:
- sets and reads the application_id Pragma
- sets and reads the user_version Pragma
- sets and re-sets the encryption key
Per the SQLite Documentation (edited for clarity):
The pragma user_version is used to set or get the value of the user-version.
The user-version is a big-endian 32-bit signed integer stored in the database
header at offset 60.
The user-version is not used internally by SQLite. It may be used by
applications for any purpose.
http://www.sqlite.org/pragma.html#pragma_schema_version
In the demo application, I've set the user_version to a constant value.
You can use any 32-bit Signed Integer value you want:
// must be a 32-bit Signed Integer (LongInt -2147483648 .. 2147483647)
user_version = 23400001;
When we create the database, we set this value to the database:
SQLite3Connection1.ExecuteDirect('PRAGMA user_version = ' + IntToStr(user_version) + ';');
To read the user_version from the database, we can do the following:
SQLQuery1.SQL.Text := 'PRAGMA user_version;';
SQLQuery1.Open;
ShowMessage(SQLQuery1.fields[0].asString);
Per the SQLite Documentation:
The application_id PRAGMA is used to query or set the 32-bit unsigned big-endian
"Application ID" integer located at offset 68 into the database header.
Applications that use SQLite as their application file-format should set the
Application ID integer to a unique integer so that utilities such as file(1) can
determine the specific file type rather than just reporting "SQLite3 Database".
A list of assigned application IDs can be seen by consulting the magic.txt file
in the SQLite source repository.
http://www.sqlite.org/pragma.html#pragma_application_id
In the demo application, I've set the application_id to a constant value.
You can use any 32-bit Unsigned Integer value you want. In one of my applications
I use this value to track differences in the database table structure between
different versions of my application, incrementing the application_id each time I
change the table structure with a new application version:
// must be a 32-bit Unsigned Integer (Longword 0 .. 4294967295)
application_id = 1189021115;
When we create the database, we set this value to the database:
SQLite3Connection1.ExecuteDirect('PRAGMA application_id = ' + IntToStr(application_id) + ';');
To read the application_id from the database, we can do the following:
SQLQuery1.SQL.Text := 'PRAGMA application_id;';
SQLQuery1.Open;
ShowMessage(SQLQuery1.fields[0].asString);
The key pragma is a little different. Using Lazarus' SQLiteConnection Component,
we set the key with the 'password' parameter.
SQLite3Connection1.Password := txtOld.Text;
We could also use a Pragma statement to set the key initially using the following
when we create the database:
SQLite3Connection1.ExecuteDirect('PRAGMA key = ' + QuotedStr(txtNew.Text) + ';');
The benefit of using the password parameter of the SQLiteConnection component
is that it sets the key and if we want to use open and close the database
multiple times while using the application, we don't have to keep specifying a key.
If you do not want to encrypt the database initially, simply do not provide an
encryption key/password, or leave these values blank:
SQLite3Connection1.Password := '';
In order to change the encryption or to remove all encryption (unencrypting the
database) after the database has been created, we use the 'rekey' Pragma as follows:
SQLite3Connection1.ExecuteDirect('PRAGMA rekey = ' + QuotedStr(txtNew.Text) + ';');
The double-quotes used here allow the user to leave txtNew empty, which sets the
resulting SQL Statement to:
PRAGMA rekey = '';
Which removes all encryption (unencrypts the database).
4. ADDITIONAL SQLITE RESOURCES
To read more about the SQLite Encryption Extension (SEE), use the following URL
(Section: How To Compile And Use SEE)
http://www.sqlite.org/see/doc/trunk/www/index.wiki
For specifics on the key and rekey Pragmas, read the section Using the "key"
PRAGMA at the following URL:
http://www.sqlite.org/see/doc/trunk/www/readme.wiki
Details about the SQLite File Format (and particularly about the Database Header)
can be found at:
http://www.sqlite.org/fileformat2.html#database_header
Information about the various standard database PRAGMA (metadata) statements can
be found at:
http://www.sqlite.org/pragma.html
The methods of passing the key to the database used in this demonstration are very
simplistic. Ideally, we would take a stronger cryptographic approach.
Some helpful info on this topic can be found at:
https://www.owasp.org/index.php/Cheat_Sheets

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="9"/>
<PathDelim Value="\"/>
<General>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
<Title Value="project1"/>
<ResourceType Value="res"/>
<UseXPManifest Value="True"/>
</General>
<i18n>
<EnableI18N LFM="False"/>
</i18n>
<VersionInfo>
<StringTable ProductVersion=""/>
</VersionInfo>
<BuildModes Count="1">
<Item1 Name="Default" Default="True"/>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
<DestinationDirectory Value="$(ProjPath)\published\"/>
</PublishOptions>
<RunParams>
<local>
<FormatVersion Value="1"/>
</local>
</RunParams>
<RequiredPackages Count="3">
<Item1>
<PackageName Value="SQLDBLaz"/>
</Item1>
<Item2>
<PackageName Value="FCL"/>
</Item2>
<Item3>
<PackageName Value="LCL"/>
</Item3>
</RequiredPackages>
<Units Count="2">
<Unit0>
<Filename Value="project1.lpr"/>
<IsPartOfProject Value="True"/>
<UnitName Value="project1"/>
</Unit0>
<Unit1>
<Filename Value="unit1.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="Form1"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
<UnitName Value="Unit1"/>
</Unit1>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="project1"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Linking>
<Debugging>
<GenerateDebugInfo Value="False"/>
</Debugging>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
<Other>
<CompilerMessages>
<MsgFileName Value=""/>
</CompilerMessages>
<CompilerPath Value="$(CompPath)"/>
</Other>
</CompilerOptions>
</CONFIG>

View File

@ -0,0 +1,21 @@
program project1;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms, Unit1
{ you can add units after this };
{$R *.res}
begin
RequireDerivedFormResource := True;
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.

View File

@ -0,0 +1,321 @@
object Form1: TForm1
Left = 389
Height = 740
Top = 156
Width = 416
Caption = 'SQLite DB Demo'
ClientHeight = 740
ClientWidth = 416
OnCreate = FormCreate
LCLVersion = '1.2.4.0'
object btnMakeNewDB: TButton
Left = 144
Height = 25
Top = 88
Width = 120
Caption = 'Make New DB'
OnClick = btnMakeNewDBClick
TabOrder = 0
end
object txtNew: TEdit
Left = 176
Height = 23
Top = 160
Width = 120
TabOrder = 1
end
object btnReKeyDB: TButton
Left = 144
Height = 25
Top = 200
Width = 120
Caption = 'ReKey DB'
OnClick = btnReKeyDBClick
TabOrder = 2
end
object Label2: TLabel
Left = 112
Height = 15
Top = 164
Width = 53
Caption = 'New Pass:'
ParentColor = False
end
object txtPass: TEdit
Left = 176
Height = 23
Top = 16
Width = 120
TabOrder = 3
end
object Label3: TLabel
Left = 88
Height = 15
Top = 20
Width = 77
Caption = 'Database Pass:'
ParentColor = False
end
object Shape1: TShape
AnchorSideLeft.Control = Owner
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
Left = 0
Height = 1
Top = 128
Width = 416
Anchors = [akTop, akLeft, akRight]
end
object Shape2: TShape
AnchorSideLeft.Control = Owner
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
Left = 0
Height = 1
Top = 240
Width = 416
Anchors = [akTop, akLeft, akRight]
end
object btnViewAppID: TButton
Left = 280
Height = 25
Top = 704
Width = 120
Caption = 'View Application_ID'
OnClick = btnViewAppIDClick
TabOrder = 4
end
object btnViewUserVersion: TButton
Left = 280
Height = 25
Top = 658
Width = 120
Caption = 'View User_Version'
OnClick = btnViewUserVersionClick
TabOrder = 5
end
object btnSetAppID: TButton
Left = 152
Height = 25
Top = 704
Width = 120
Caption = 'Set Application_ID'
OnClick = btnSetAppIDClick
TabOrder = 6
end
object btnSetUserVersion: TButton
Left = 152
Height = 25
Top = 658
Width = 120
Caption = 'Set User_Version'
OnClick = btnSetUserVersionClick
TabOrder = 7
end
object txtUser_Version: TEdit
Left = 24
Height = 23
Hint = 'Must be a 32-bit Signed Integer (LongInt -2147483648 .. 2147483647)'
Top = 658
Width = 120
ParentShowHint = False
ShowHint = True
TabOrder = 8
Text = '0'
end
object txtApplication_ID: TEdit
Left = 24
Height = 23
Hint = 'Must be a 32-bit Unsigned Integer (Longword 0 .. 4294967295)'
Top = 704
Width = 120
ParentShowHint = False
ShowHint = True
TabOrder = 9
Text = '0'
end
object Label4: TLabel
Left = 24
Height = 15
Top = 642
Width = 70
Caption = 'User_Version:'
ParentColor = False
end
object Label5: TLabel
Left = 24
Height = 15
Top = 688
Width = 79
Caption = 'Application_Id:'
ParentColor = False
end
object Label6: TLabel
Left = 16
Height = 50
Top = 584
Width = 384
AutoSize = False
Caption = 'Database Pragma Settings:'#13#10'user_version originally set to 23400001'#13#10'application_id originally set to 1189021115'
ParentColor = False
WordWrap = True
end
object Label7: TLabel
Left = 15
Height = 15
Top = 64
Width = 88
Caption = 'Create Database:'
ParentColor = False
end
object Label8: TLabel
Left = 16
Height = 15
Top = 136
Width = 137
Caption = 'Change the Database Key:'
ParentColor = False
end
object Shape3: TShape
AnchorSideLeft.Control = Owner
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
Left = 0
Height = 1
Top = 568
Width = 416
Anchors = [akTop, akLeft, akRight]
end
object Label9: TLabel
Left = 16
Height = 15
Top = 248
Width = 117
Caption = 'Add Info To Database:'
ParentColor = False
end
object txtUser_Name: TEdit
Left = 176
Height = 23
Top = 272
Width = 120
TabOrder = 10
end
object txtInfo: TEdit
Left = 176
Height = 23
Top = 296
Width = 120
TabOrder = 11
end
object btnAddToDB: TButton
Left = 144
Height = 25
Top = 336
Width = 120
Caption = 'Add To DB'
OnClick = btnAddToDBClick
TabOrder = 12
end
object Label10: TLabel
Left = 120
Height = 15
Top = 276
Width = 35
Caption = 'Name:'
ParentColor = False
end
object Label11: TLabel
Left = 120
Height = 15
Top = 300
Width = 24
Caption = 'Info:'
ParentColor = False
end
object Shape4: TShape
AnchorSideLeft.Control = Owner
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
Left = 0
Height = 1
Top = 376
Width = 416
Anchors = [akTop, akLeft, akRight]
end
object Label12: TLabel
Left = 15
Height = 15
Top = 384
Width = 83
Caption = 'Query Database'
ParentColor = False
end
object btnUpdateGrid: TButton
Left = 64
Height = 25
Top = 528
Width = 120
Caption = 'Update Grid'
OnClick = btnUpdateGridClick
TabOrder = 13
end
object DBGrid1: TDBGrid
Left = 8
Height = 104
Top = 408
Width = 400
Color = clWindow
Columns = <>
ReadOnly = True
TabOrder = 14
end
object Shape5: TShape
AnchorSideLeft.Control = Owner
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
Left = 0
Height = 1
Top = 56
Width = 416
Anchors = [akTop, akLeft, akRight]
end
object btnCountRows: TButton
Left = 224
Height = 25
Top = 528
Width = 120
Caption = 'Count Rows'
OnClick = btnCountRowsClick
TabOrder = 15
end
object DataSource1: TDataSource
DataSet = SQLQuery1
left = 376
top = 8
end
object SQLQuery1: TSQLQuery
FieldDefs = <>
Database = SQLite3Connection1
Transaction = SQLTransaction1
Params = <>
left = 376
top = 72
end
object SQLTransaction1: TSQLTransaction
Active = False
Database = SQLite3Connection1
left = 376
top = 144
end
object SQLite3Connection1: TSQLite3Connection
Connected = False
LoginPrompt = False
KeepConnection = False
Transaction = SQLTransaction1
LogEvents = []
Options = []
left = 376
top = 200
end
end

View File

@ -0,0 +1,455 @@
unit Unit1;
////////////////////////////////////////////////////////////////////////////////
// //
// This is free and unencumbered software released into the public domain. //
// //
// Anyone is free to copy, modify, publish, use, compile, sell, or //
// distribute this software, either in source code form or as a compiled //
// binary, for any purpose, commercial or non-commercial, and by any //
// means. //
// //
// In jurisdictions that recognize copyright laws, the author or authors //
// of this software dedicate any and all copyright interest in the //
// software to the public domain. We make this dedication for the benefit //
// of the public at large and to the detriment of our heirs and //
// successors. We intend this dedication to be an overt act of //
// relinquishment in perpetuity of all present and future rights to this //
// software under copyright law. //
// //
// 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 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. //
// //
// For more information, please refer to <http://unlicense.org/> //
// //
////////////////////////////////////////////////////////////////////////////////
// For this test application, I wanted to very simply try the following
// capabilities which I'll be using in a large application:
// - Creation of a SQLite3 Database
// - Creation of a database table
// - Setting various database metadata (PRAGMA)
// - Optionally encrypt the database using a key
// - Change (or set if not initially set) the encryption key for the database
// The application makes a new database file "new.db" within the local directory
// See readme.txt for installation instructions and details
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, db, sqldb, sqlite3conn, FileUtil, Forms, Controls,
Graphics, Dialogs, StdCtrls, ExtCtrls, DBGrids;
type
{ TForm1 }
TForm1 = class(TForm)
btnMakeNewDB: TButton;
btnReKeyDB: TButton;
btnViewAppID: TButton;
btnSetAppID: TButton;
btnViewUserVersion: TButton;
btnSetUserVersion: TButton;
btnAddToDB: TButton;
btnUpdateGrid: TButton;
btnCountRows: TButton;
DataSource1: TDataSource;
DBGrid1: TDBGrid;
Label12: TLabel;
Shape4: TShape;
Shape5: TShape;
txtUser_Name: TEdit;
txtInfo: TEdit;
Label10: TLabel;
Label11: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
Label8: TLabel;
Label9: TLabel;
Shape1: TShape;
Shape2: TShape;
Shape3: TShape;
txtNew: TEdit;
txtApplication_ID: TEdit;
Label2: TLabel;
SQLite3Connection1: TSQLite3Connection;
SQLQuery1: TSQLQuery;
SQLTransaction1: TSQLTransaction;
txtUser_Version: TEdit;
txtPass: TEdit;
procedure btnAddToDBClick(Sender: TObject);
procedure btnMakeNewDBClick(Sender: TObject);
procedure btnReKeyDBClick(Sender: TObject);
procedure btnSetAppIDClick(Sender: TObject);
procedure btnSetUserVersionClick(Sender: TObject);
procedure btnViewAppIDClick(Sender: TObject);
procedure btnViewUserVersionClick(Sender: TObject);
procedure btnUpdateGridClick(Sender: TObject);
procedure btnCountRowsClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
const
// More information on the use of these values is below.
// They need not be set as constants in your application. They can be any valid value
application_id = 1189021115; // must be a 32-bit Unsigned Integer (Longword 0 .. 4294967295)
user_version = 23400001; // must be a 32-bit Signed Integer (LongInt -2147483648 .. 2147483647)
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.btnMakeNewDBClick(Sender: TObject);
var
newFile : Boolean;
begin
SQLite3Connection1.Close; // Ensure the connection is closed when we start
// Set the password initially.
// Could probably be done with a PRAGMA statement, but this is so much simpler
// and once set, doesn't need to be reset every time we open the database.
// txtPass can be left blank if you want an unencrypted database.
SQLite3Connection1.Password := txtPass.Text;
try
// Since we're making this database for the first time,
// check whether the file already exists
newFile := not FileExists(SQLite3Connection1.DatabaseName);
if newFile then
begin
// Make the database and the tables
try
SQLite3Connection1.Open;
SQLTransaction1.Active := true;
// Per the SQLite Documentation (edited for clarity):
// The pragma user_version is used to set or get the value of the user-version.
// The user-version is a big-endian 32-bit signed integer stored in the database header at offset 60.
// The user-version is not used internally by SQLite. It may be used by applications for any purpose.
// http://www.sqlite.org/pragma.html#pragma_schema_version
SQLite3Connection1.ExecuteDirect('PRAGMA user_version = ' + IntToStr(user_version) + ';');
// Per the SQLite Documentation:
// The application_id PRAGMA is used to query or set the 32-bit unsigned big-endian
// "Application ID" integer located at offset 68 into the database header.
// Applications that use SQLite as their application file-format should set the
// Application ID integer to a unique integer so that utilities such as file(1) can
// determine the specific file type rather than just reporting "SQLite3 Database".
// A list of assigned application IDs can be seen by consulting the magic.txt file
// in the SQLite source repository.
// http://www.sqlite.org/pragma.html#pragma_application_id
SQLite3Connection1.ExecuteDirect('PRAGMA application_id = ' + IntToStr(application_id) + ';');
// Here we're setting up a table named "DATA" in the new database
SQLite3Connection1.ExecuteDirect('CREATE TABLE "DATA"('+
' "id" Integer NOT NULL PRIMARY KEY AUTOINCREMENT,'+
' "Current_Time" DateTime NOT NULL,'+
' "User_Name" Char(128) NOT NULL,'+
' "Info" Char(128) NOT NULL);');
// Creating an index based upon id in the DATA Table
SQLite3Connection1.ExecuteDirect('CREATE UNIQUE INDEX "Data_id_idx" ON "DATA"( "id" );');
SQLTransaction1.Commit;
ShowMessage('Succesfully created database.');
except
ShowMessage('Unable to Create new Database');
end;
end;
except
ShowMessage('Unable to check if database file exists');
end;
end;
procedure TForm1.btnAddToDBClick(Sender: TObject);
begin
SQLite3Connection1.Password := txtPass.Text; // The current password
if (txtUser_Name.Text = '') OR (txtInfo.Text = '') then
begin
ShowMessage('Please enter both a Name and Info');
end
else
begin
// Attempt to add txtUser_Name and txtInfo to the database
try
SQLite3Connection1.Open;
SQLTransaction1.Active := True;
// Insert the values into the database
// We're using ParamByName which prevents SQL Injection
// http://wiki.freepascal.org/Working_With_TSQLQuery#Parameters_in_TSQLQuery.SQL
SQLQuery1.SQL.Text := 'Insert into DATA (Current_Time,User_Name,Info) values (:Current_Time,:User_Name,:Info)';
SQLQuery1.Params.ParamByName('Current_Time').AsDateTime := Now;
SQLQuery1.Params.ParamByName('User_Name').AsString := txtUser_Name.Text;
SQLQuery1.Params.ParamByName('Info').AsString := txtInfo.Text;
SQLQuery1.ExecSQL;
SQLTransaction1.Commit;
// Clear Edit boxes
txtUser_Name.Text := '';
txtInfo.Text := '';
// Now let's update the grid to show the new values to the user:
btnUpdateGridClick(nil);
except
ShowMessage('Unable to add User_Name: ' + txtUser_Name.Text + ' and Info: ' + txtInfo.Text + ' to the database. Ensure database exists and password is correct.');
end;
end;
end;
procedure TForm1.btnReKeyDBClick(Sender: TObject);
begin
SQLite3Connection1.Close; // Ensure the connection is closed when we start
SQLite3Connection1.Password := txtPass.Text; // The current password
// Update the database key
try
SQLite3Connection1.Open;
SQLTransaction1.Active := True;
// Here we change the key.
// We use double-quotes here so that a blank key (IE: "") can be provided if
// you want to remove encryption from the database.
// This is a very simplistic demonstration. Ideally, we would take a stronger cryptographic approach
// Some helpful info on this topic can be found at:
// https://www.owasp.org/index.php/Cheat_Sheets
// Per SQLite Documentation:
// Note that the hexkey, rekey and hexrekey pragmas only work with SQLite version 3.6.8 and later.
// http://www.sqlite.org/see/doc/trunk/www/readme.wiki
// Section: Using the "key" PRAGMA
SQLite3Connection1.ExecuteDirect('PRAGMA rekey = ' + QuotedStr(txtNew.Text) + ';');
SQLTransaction1.Commit;
SQLite3Connection1.Close;
// Transfer the password to txtPass and erase txtNew
txtPass.Text := txtNew.Text;
txtNew.Text := '';
// ... and make sure we remember the new password in our sqlconnection ready
// for reconnecting
SQLite3Connection1.Password := txtPass.Text;
ShowMessage('Password rekey succesful.');
except
ShowMessage('Unable to set the new key using: PRAGMA rekey = ' + txtNew.Text + ';');
end;
end;
procedure TForm1.btnSetAppIDClick(Sender: TObject);
begin
SQLite3Connection1.Close; // Ensure the connection is closed when we start
SQLite3Connection1.Password := txtPass.Text; // The current password
// Try to set the application_id Pragma
try
SQLite3Connection1.Open;
SQLTransaction1.Active := True;
SQLQuery1.SQL.Text := 'PRAGMA application_id = ' + txtApplication_ID.Text + ';';
SQLQuery1.ExecSQL;
SQLTransaction1.Commit;
SQLite3Connection1.Close;
ShowMessage('SetAppID succesful');
except
ShowMessage('Unable to set new application_id: ' + txtApplication_ID.Text + ';');
end;
end;
procedure TForm1.btnSetUserVersionClick(Sender: TObject);
begin
SQLite3Connection1.Close; // Ensure the connection is closed when we start
SQLite3Connection1.Password := txtPass.Text; // The current password
// Try to set the user_version Pragma
try
SQLite3Connection1.Open;
SQLTransaction1.Active := True;
SQLQuery1.SQL.Text := 'PRAGMA user_version = ' + txtUser_Version.Text + ';';
SQLQuery1.ExecSQL;
SQLTransaction1.Commit;
SQLite3Connection1.Close;
ShowMessage('SetUserVersion succesful.');
except
ShowMessage('Unable to set user_version: ' + txtUser_Version.Text + ';');
end;
end;
procedure TForm1.btnViewAppIDClick(Sender: TObject);
begin
SQLite3Connection1.Close; // Ensure the connection is closed when we start
SQLite3Connection1.Password := txtPass.Text; // The current password
// Try to query database for application_id Pragma
try
SQLite3Connection1.Open;
SQLQuery1.SQL.Text := 'PRAGMA application_id;';
SQLQuery1.Open;
// Display the resulting value
ShowMessage('application_id is: '+SQLQuery1.fields[0].asString);
except
ShowMessage('Unable to display application_id');
end;
end;
procedure TForm1.btnViewUserVersionClick(Sender: TObject);
begin
SQLite3Connection1.Close; // Ensure the connection is closed when we start
SQLite3Connection1.Password := txtPass.Text; // The current password
// Try to query database for user_version Pragma
try
SQLite3Connection1.Open;
SQLQuery1.SQL.Text := 'PRAGMA user_version;';
SQLQuery1.Open;
// Display the resulting value
ShowMessage('user_version is: '+SQLQuery1.fields[0].asString);
except
ShowMessage('Unable to display user_version');
end;
end;
procedure TForm1.btnUpdateGridClick(Sender: TObject);
begin
SQLite3Connection1.Password := txtPass.Text; // The current password
// Try to perform query
try
SQLite3Connection1.Connected := True;
// Set SQL text to select everything from the DATA table
SQLQuery1.SQL.Clear;
SQLQuery1.SQL.Text := 'Select * from DATA';
SQLQuery1.Open;
// Allow the DBGrid to view the results of our query
DataSource1.DataSet := SQLQuery1;
DBGrid1.DataSource := DataSource1;
DBGrid1.AutoFillColumns := true;
except
ShowMessage('Unable to query the database');
end;
end;
procedure TForm1.btnCountRowsClick(Sender: TObject);
begin
SQLite3Connection1.Close; // Ensure the connection is closed when we start
SQLite3Connection1.Password := txtPass.Text; // The current password
// Try to perform query
try
SQLite3Connection1.Connected := True;
// Set SQL text to count all rows from the DATA table
SQLQuery1.SQL.Clear;
SQLQuery1.SQL.Text := 'Select Count(*) from DATA';
SQLQuery1.Open;
// Allow the DBGrid to view the results of our query
DataSource1.DataSet := SQLQuery1;
DBGrid1.DataSource := DataSource1;
DBGrid1.AutoFillColumns := true;
except
ShowMessage('Unable to query the database');
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
// Ensure we're using the local sqlite3.dll
SQLiteLibraryName := 'sqlite3.dll';
// Set the path to the database
SQLite3Connection1.DatabaseName := 'new.db';
end;
end.