diff --git a/.gitattributes b/.gitattributes
index 296a55b3da..a562335442 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -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
diff --git a/examples/database/sqlite_encryption_pragma/README.txt b/examples/database/sqlite_encryption_pragma/README.txt
new file mode 100644
index 0000000000..cb2b153675
--- /dev/null
+++ b/examples/database/sqlite_encryption_pragma/README.txt
@@ -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
\ No newline at end of file
diff --git a/examples/database/sqlite_encryption_pragma/project1.lpi b/examples/database/sqlite_encryption_pragma/project1.lpi
new file mode 100644
index 0000000000..1c330535f7
--- /dev/null
+++ b/examples/database/sqlite_encryption_pragma/project1.lpi
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/database/sqlite_encryption_pragma/project1.lpr b/examples/database/sqlite_encryption_pragma/project1.lpr
new file mode 100644
index 0000000000..ced6d82558
--- /dev/null
+++ b/examples/database/sqlite_encryption_pragma/project1.lpr
@@ -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.
+
diff --git a/examples/database/sqlite_encryption_pragma/project1.res b/examples/database/sqlite_encryption_pragma/project1.res
new file mode 100644
index 0000000000..e66ecf85fe
Binary files /dev/null and b/examples/database/sqlite_encryption_pragma/project1.res differ
diff --git a/examples/database/sqlite_encryption_pragma/unit1.lfm b/examples/database/sqlite_encryption_pragma/unit1.lfm
new file mode 100644
index 0000000000..ab3e698e0d
--- /dev/null
+++ b/examples/database/sqlite_encryption_pragma/unit1.lfm
@@ -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
diff --git a/examples/database/sqlite_encryption_pragma/unit1.pas b/examples/database/sqlite_encryption_pragma/unit1.pas
new file mode 100644
index 0000000000..93e44d092b
--- /dev/null
+++ b/examples/database/sqlite_encryption_pragma/unit1.pas
@@ -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 //
+// //
+////////////////////////////////////////////////////////////////////////////////
+
+
+// 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.
+