https://sourceforge.net/projects/zeoslib/files/Zeos%20Database%20Objects/zeosdbo-7.1.4-stable/
------------
https://wiki.freepascal.org/SQLite/ja#Creating_user_defined_collations
Creating a Database
Delphi way:
http://docwiki.embarcadero.com/RADStudio/Rio/en/Using_SQLite_with_FireDAC
------------
https://wiki.freepascal.org/SQLite/ja#Creating_user_defined_collations
Creating a Database
The TSQLite3Connection.CreateDB method inherited from the parent class actually does nothing; to create a database if no file exists yet, you simply have to write table data as in the following example:
(Code extracted from sqlite_encryption_pragma example that ships with Lazarus 1.3 onwards)
var
newFile : Boolean;
begin
SQLite3Connection1.Close; // Ensure the connection is closed when we start
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
// Create the database and the tables
try
SQLite3Connection1.Open;
SQLTransaction1.Active := true;
// 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;
Creating user defined collations
// utf8 case-sensitive compare callback function
function UTF8xCompare(user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl;
var S1, S2: AnsiString;
begin
SetString(S1, data1, len1);
SetString(S2, data2, len2);
Result := UnicodeCompareStr(UTF8Decode(S1), UTF8Decode(S2));
end;
// utf8 case-insensitive compare callback function
function UTF8xCompare_CI(user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl;
var S1, S2: AnsiString;
begin
SetString(S1, data1, len1);
SetString(S2, data2, len2);
Result := UnicodeCompareText(UTF8Decode(S1), UTF8Decode(S2));
end;
// register collation using SQLite3 API (requires sqlite3dyn unit):
sqlite3_create_collation(SQLite3.Handle, 'UTF8_CI', SQLITE_UTF8, nil, @UTF8xCompare_CI);
// or using method of TSQLite3Connection:
CreateCollation('UTF8_CI',1,nil,@UTF8xCompare_CI);
// now we can use case-insensitive comparison in SQL like:
// SELECT * FORM table1 WHERE column1 COLLATE UTF8_CI = 'á'
// but this does not work for LIKE operator
// in order to support also LIKE operator we must overload default LIKE function using sqlite3_create_function()
// http://www.sqlite.org/lang_corefunc.html#like
Creating user defined functions
// example overloading default LOWER() function with user supplied function
// to run this demo, you must add units 'sqlite3dyn' and 'ctypes' to your uses-clause
// and add a const 'SQLITE_DETERMINISTIC' with value $800
procedure UTF8xLower(ctx: psqlite3_context; N: cint; V: ppsqlite3_value); cdecl;
var S: AnsiString;
begin
SetString(S, sqlite3_value_text(V[0]), sqlite3_value_bytes(V[0]));
S := UTF8Encode(AnsiLowerCase(UTF8Decode(S)));
sqlite3_result_text(ctx, PAnsiChar(S), Length(S), sqlite3_destructor_type(SQLITE_TRANSIENT));
end;
// register function LOWER() using SQLite3 API (requires sqlite3dyn unit):
sqlite3_create_function(SQLite3.Handle, 'lower', 1, SQLITE_UTF8 or SQLITE_DETERMINISTIC, nil, @UTF8xLower, nil, nil);
SQLite3 and Dates
- SQLite 3 doesn't store dates as a special DateTime value. It can stores them as strings, doubles or integers - see http://www.sqlite.org/datatype3.html#datetime.
- In strings, the date separator is '-' as per SQL standard/ISO 8601. Thus, if you do an INSERT using the built-in DATE function, it will store it as something like 'YYYY-MM-DD'.
- Reading a DateTime value can cause problems for DataSets if they are stored as strings: the .AsDateTime qualifier can stall on an SQLite 'string date' but this can be overcome by using something like strftime(%d/%m/%Y,recdate) AS sqlite3recdate in your SQL SELECT statement, which forces SQLite3 to return the date record in a specified format. (the format string %d/%m/%d corresponds to your locale date format which .AsDateTime will understand) ==> Please open a bug report with an example application demonstrating the problemif this is the case
- When comparing dates stored as strings (using for example the BETWEEN function) remember that the comparison will always be a string comparison, and will therefore depend on how you have stored the date value.
Default values in local time instead of UTC
CURRENT_TIME, CURRENT_DATE and CURRENT_TIMESTAMP return current UTC date and/or time. For local date and/or times we can use:
DEFAULT (datetime('now','localtime')) for datetime values formated YYYY-MM-DD HH:MM:SS DEFAULT (date('now','localtime')) for date value formated YYYY-MM-DD DEFAULT (time('now','localtime')) for time value formated HH:MM:SS
SQLDB And SQLite troubleshooting
- Keep in mind that for designtime support to work (fields etc) Lazarus must find sqlite3.dll too.
- The same goes for the database filename. Always use absolute path if you use components to extract e.g. fieldnames at designtime. Otherwise the IDE will create an empty file in its directory. In case of trouble, check if the lazarus/ directory doesn't hold a zero byte copy of the database file.
- If you have master/detail relationship, you need to refresh master dataset after each insert, in order to get value for slave dataset foreign key field. You can do that in AfterPost event of the master dataset, by calling one of the following overloaded procedures:
interface
procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery);overload;
procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery; pKeyField: string);overload;
implementation
procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery; pKeyField: string);
//This procedure refreshes a dataset and positions cursor to last record
//To be used if Dataset is not guaranteed to be sorted by an autoincrement primary key
var
vLastID: Integer;
vUpdateStatus : TUpdateStatus;
begin
vUpdateStatus := pDataset.UpdateStatus;
//Get last inserted ID in the database
pDataset.ApplyUpdates;
vLastID:=(pDataSet.DataBase as TSQLite3Connection).GetInsertID;
//Now come back to respective row
if vUpdateStatus = usInserted then begin
pDataset.Refresh;
//Refresh and go back to respective row
pDataset.Locate(pKeyField,vLastID,[]);
end;
end;
procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery);
//This procedure refreshes a dataset and positions cursor to last record
//To be used only if DataSet is guaranteed to be sorted by an autoincrement primary key
var
vLastID: Integer;
vUpdateStatus : TUpdateStatus;
begin
vUpdateStatus := pDataset.UpdateStatus;
pDataset.ApplyUpdates;
vLastID:=(pDataSet.DataBase as TSQLite3Connection).GetInsertID;
if vUpdateStatus = usInserted then begin
pDataset.Refresh;
//Dangerous!
pDataSet.Last;
end;
end;
procedure TDataModule1.SQLQuery1AfterPost(DataSet: TDataSet);
begin
RefreshADatasetAfterInsert(Dataset as TSQLQuery); //If your dataset is sorted by primary key
end;
procedure TDataModule1.SQLQuery2AfterPost(DataSet: TDataSet);
begin
RefreshADatasetAfterInsert(Dataset as TSQLQuery, 'ID'); //if you are not sure that the dataset is always sorted by primary key
end;
Vacuum and other operations that must be done outside a transaction
SQLDB seems to always require a connection, but some operations like Pragma and Vacuum must be done outside a transaction. The trick is to end transaction, execute what you must and start transaction again (so that sqldb doesn't get confused:)
// commit any pending operations or use a "fresh" sqlconnection
Conn.ExecuteDirect('End Transaction'); // End the transaction started by SQLdb
Conn.ExecuteDirect('Vacuum');
Conn.ExecuteDirect('Begin Transaction'); //Start a transaction for SQLdb to use
Delphi way:
http://docwiki.embarcadero.com/RADStudio/Rio/en/Using_SQLite_with_FireDAC
No comments:
Post a Comment
Коментар: