Difference between revisions of "SQLite/ru"

From Lazarus wiki
Jump to navigationJump to search
m (link TDataSet)
 
(19 intermediate revisions by one other user not shown)
Line 37: Line 37:
 
* [http://system.data.sqlite.org/ System.Data.SQLite]: с открытым исходным кодом, доступны двоичные файлы Windows (32, 64, CE), загрузите, например, один из предварительно скомпилированных двоичных файлов и переименуйте SQLite.Interop.dll в sqlite3.dll (если вы используете статически связанные файлы, вероятно, вам нужно переименовать System.Data.SQLite.DLL в sqlite3.dll)
 
* [http://system.data.sqlite.org/ System.Data.SQLite]: с открытым исходным кодом, доступны двоичные файлы Windows (32, 64, CE), загрузите, например, один из предварительно скомпилированных двоичных файлов и переименуйте SQLite.Interop.dll в sqlite3.dll (если вы используете статически связанные файлы, вероятно, вам нужно переименовать System.Data.SQLite.DLL в sqlite3.dll)
 
* [http://wxcode.sourceforge.net/docs/wxsqlite3/ wxSQLite3]: открытый исходный код, доступны некоторые бинарные файлы для Linux (напр: https://launchpad.net/ubuntu/oneiric/+package/libwxsqlite3-2.8-0)
 
* [http://wxcode.sourceforge.net/docs/wxsqlite3/ wxSQLite3]: открытый исходный код, доступны некоторые бинарные файлы для Linux (напр: https://launchpad.net/ubuntu/oneiric/+package/libwxsqlite3-2.8-0)
* [https://github.com/resilar/sqleet sqleet]: открытый исходный код, нет зависимостей от других библиотек, легко собирается при помощи GCC в исполняемые файлы, кроссплаформенный. ДОступны механизмы шифрования как в интерактивном режиме, так и посредством sqleet API.
+
* [https://github.com/resilar/sqleet sqleet]: открытый исходный код, нет зависимостей от других библиотек, легко собирается при помощи GCC в исполняемые файлы и файлы библиотек, кроссплаформенный. Доступны механизмы шифрования как в интерактивном режиме, так и посредством sqleet API.
  
 
==== sqlite3backup ====
 
==== sqlite3backup ====
  
sqlite3backup is a unit provided with FPC (not in Lazarus but can be used programmatically) that provides backup/restore functionality for SQLite3. It uses SQLDB's sqlite3conn.
+
sqlite3backup - это модуль, поставляемый с FPC (не в Lazarus, но может использоваться программно), который обеспечивает функции резервного копирования/восстановления для SQLite3. Он использует SQLDB sqlite3conn.
  
 
=== Zeos ===
 
=== Zeos ===
Line 49: Line 49:
 
=== SQLitePass ===
 
=== SQLitePass ===
  
[http://source.online.free.fr/ SQLitePass] components. Last code update in 2010. Last forum activity in 2011.
+
Компоненты [http://source.online.free.fr/ SQLitePass]. Последнее обновление кода в 2010. Последняя активность на форуме в 2011.
  
 
=== TSQLite3Dataset и TSQLiteDataset ===
 
=== TSQLite3Dataset и TSQLiteDataset ===
  
There are also separate TSQLiteDataset (unit sqliteds) and TSQLite3Dataset (unit sqlite3ds) packages; see below for a description on how to use them. Visit the [http://sqlite4fpc.yolasite.com/ sqlite4fpc homepage] to find the API reference and more tutorials.
+
Существуют также отдельные пакеты TSQLiteDataset (модуль sqlite) и TSQLite3Dataset (модуль sqlite3ds); см. ниже описание того, как их использовать. Посетите [http://sqlite4fpc.yolasite.com/ домашнюю страницу sqlite4fpc], чтобы найти справочник по API и другие руководства.
  
TSqliteDataset and TSqlite3Dataset are [[TDataset]] descendants that access, respectively, 2.8.x and 3.x.x sqlite databases. For new projects, you would presumably use TSQlite3Dataset as SQLite 3.x is the current version.
+
TSqliteDataset и TSqlite3Dataset являются потомками [[TDataSet]], которые обращаются к базам данных sqlite 2.8.x и 3.x.x соответственно. Для новых проектов вы, вероятно, будете использовать TSQlite3Dataset, поскольку текущая версия SQLite 3.x.
  
Below is a list of the principal advantages and disadvantages compared to other FPC/Lazarus SQLite drivers/access methods:
+
Ниже приведен список основных преимуществ и недостатков по сравнению с другими драйверами/методами доступа FPC/Lazarus SQLite:
  
Advantages:
+
Преимущества:
* Flexible: programmers can choose to use or not to use the SQL language, allowing them to work with simple table layouts or any complex layout that SQL/sqlite allows
+
* Гибкость: программисты могут выбирать, использовать или не использовать язык SQL, что позволяет им работать с простыми макетами таблиц или любым сложным макетом, который позволяет SQL/sqlite.
Disadvantages:
+
Недостатки:
* Changing to other databases is more difficult than if you use the SQLDB or Zeos components
+
* Переход на другие базы данных сложнее, чем при использовании компонентов SQLDB или Zeos
  
{{Note|Given the above, many users will use SQLDB or Zeos due to the advantages unless they need lower-level access to the SQLite library}}
+
{{Note|Учитывая вышеизложенное, многие пользователи будут использовать SQLDB или Zeos из-за преимуществ, если им не нужен низкоуровневый доступ к библиотеке SQLite.}}
  
== Using the SQLdb components with SQLite ==
+
== Использование компонентов SQLdb со SQLite ==
  
These instructions are focused on SQLDB (the TSQLite3Connection) specifics for SQLite. For a general overview, have a look at [[SqlDBHowto|SqlDBHowto]] which has some useful information about the SQLdb components.  
+
Эти инструкции сосредоточены на особенностях SQLDB (TSQLite3Connection) для SQLite. Для общего обзора ознакомьтесь с [[SqlDBHowto|SqlDB: Howto]], где есть полезная информация о компонентах SQLdb.
  
See [[SQLdb_Tutorial1]] for a tutorial on creating a GUI database-enabled program that is written for SQLite/SQLDB (as well as for Firebird/SQLDB, PostgreSQL/SQLDB, basically any RDBMS SQLDB supports).
+
См. [[SQLdb_Tutorial1| Учебник1 по SQLdb]] для обучения создания программы с поддержкой базы данных с графическим интерфейсом пользователя, которая написана для SQLite/SQLDB (а также для Firebird/SQLDB, PostgreSQL/SQLDB, в основном любой СУБД, поддерживаемой SQLDB).
  
We will use a combination of three components from the Lazarus SQLdb tab: TSQLite3Connection, TSQLTransaction and TSQLQuery. The TSQLQuery acts as our TDataset; in the simplest case it just represents one of our tables. For the sake of simplicity: make sure you already have an existing SQLite database file and don't need to create a new one now.  
+
Мы будем использовать комбинацию из трех компонентов из вкладки Lazarus SQLdb: TSQLite3Connection, TSQLTransaction и TSQLQuery. TSQLQuery действует как наш TDataset; в простейшем случае это просто одна из наших таблиц. Для простоты: убедитесь, что у вас уже есть существующий файл базы данных SQLite, и вам не нужно создавать новый сейчас.
TSQLite3Connection can be found in the ''sqlite3conn'' unit, if you want to declare it yourself or are working in FreePascal.
+
TSQLite3Connection можно найти в модуле sqlite3conn, если вы хотите объявить его самостоятельно или работаете в FreePascal.
  
The three components are connected with each other as usual: In the TSQLQuery set the properties Database and Transaction, in the TSQLTransaction set the property Database. There is not much to do in the Transaction and Connection components, most of the interesting things will be done in the TSQLQuery. Configure the components as follows:
+
Эти три компонента связаны друг с другом как обычно: в TSQLQuery установите свойства Database и Transaction, в TSQLTransaction установите свойство Database. В компонентах Transaction и Connection особо нечего делать, большинство интересного будет сделано в TSQLQuery. Настройте компоненты следующим образом:
  
TSQLite3Connection:
+
<b>TSQLite3Connection</b>:
  
* DatabaseName: Set this property to the file name (absolute path!) of your SQLite file. Unfortunately, you cannot simply use a relative path that works unchanged at designtime and at runtime ***is this still true? Can't you just copy the db file in a post-build shell script or symlink it?***. You should make sure that at application start the correct path to the file is always set programmatically, no matter what it contained at designtime.
+
* DatabaseName: установите для этого свойства имя файла (абсолютный путь!) вашего файла SQLite. К сожалению, вы не можете просто использовать относительный путь, который работает без изменений во время разработки и во время выполнения (<i>это все еще верно? Разве вы не можете просто скопировать файл db в сценарий оболочки после сборки или создать символическую ссылку на него? </i>). Вы должны убедиться, что при запуске приложения правильный путь к файлу всегда устанавливается программно, независимо от того, что он содержал во время разработки.
  
Note: To set the full library path (if you place your sqlite dll/so/dylib in a place where the OS won't find it, like the application directory on Linux/OSX), you can set the ''SQLiteLibraryName'' property (BEFORE any connection is established e.g. in the OnCreate event of the main form), like this:
+
{{Note| Чтобы установить полный путь к библиотеке (если вы поместите свою sqlite dll/so/dylib в место, где ОС ее не найдет, например каталог приложения в Linux/OSX), вы можете установить «SQLiteLibraryName» свойство (ДО того, как будет установлено какое-либо соединение, например, в событии OnCreate главной формы)}}, например:
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
Line 87: Line 87:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
TSQLQuery:
+
<b>TSQLQuery</b>:
  
* SQL: Set it to some simple select query on one of your tables. For example, if you have a table 'foo' and want this dataset to represent this table then just use the following: <syntaxhighlight lang="SQL">SELECT * FROM foo</syntaxhighlight>
+
* SQL: задайте для него простой запрос выбора для одной из ваших таблиц. Например, если у вас есть таблица 'foo' и вы хотите, чтобы этот набор данных представлял эту таблицу, просто используйте следующие: <syntaxhighlight lang="SQL">SELECT * FROM foo</syntaxhighlight>
  
* Active: Set this to True from within the IDE to test whether it is all set up correctly. This will also automatically activate the transaction and the connection objects. If you receive an error then either the DatabaseName of the connection is not correct or the SQL query is wrong. Later, when we are done adding the fields (see below) set them all to inactive again, we don't want the IDE to lock the SQLite database (single user!) when testing the application.
+
* Active: установите для него значение True в среде IDE, чтобы проверить, все ли настроено правильно. Это также автоматически активирует транзакцию и объекты подключения. Если вы получаете сообщение об ошибке, то либо DatabaseName соединения неверно, либо запрос SQL неверен. Позже, когда мы закончим добавление полей (см. ниже), снова установим их все в неактивные состояния, мы не хотим, чтобы среда IDE блокировала базу данных SQLite (для одного пользователя!) при тестировании приложения.
  
* ''Probably not necessary for proper operation - will need to be checked (June 2012)'' Now we can add Fields to our TSQLQuery. While the components are still set to active do a right click and "edit fields...". Click the "+" button and add fields. It will list all fields your SQL query returned. Add every field you will need, you can also add lookup fields here; in this case just make sure you have already defined all needed fields in the other datasets before you start adding lookup fields that refer to them. If your table has many columns and you don't need them all you can just leave them out, you can also make your SQL a bit more specific.  
+
* ''Наверное, не нужно для правильной работы - нужно будет проверить (June 2012)'' Теперь мы можем добавить поля в наш TSQLQuery. Пока компоненты все еще активны, щелкните правой кнопкой мыши и «отредактируйте поля ...». Нажмите кнопку «+» и добавьте поля. В нем будут перечислены все поля, возвращенные вашим SQL-запросом. Добавьте все поля, которые вам понадобятся, вы также можете добавить сюда поля поиска; в этом случае просто убедитесь, что вы уже определили все необходимые поля в других наборах данных, прежде чем начинать добавлять поля поиска, которые ссылаются на них. Если в вашей таблице много столбцов, и они вам не нужны, вы можете просто не указывать их, а также сделать свой SQL более конкретным.
  
* In your code you need to call SQLQuery.ApplyUpdates and SQLTransaction.Commit, TSQLQuery.AfterPost and AfterInsert events are a good place for this when using it with data aware controls but of course you can also postpone these calls to a later time. If you don't call them, the database will not be updated.
+
* В вашем коде вам нужно вызвать SQLQuery.ApplyUpdates и SQLTransaction.Commit, события TSQLQuery.AfterPost и AfterInsert - хорошее место для этого при использовании его с элементами управления с учетом данных, но, конечно, вы также можете отложить эти вызовы на более позднее время. Если вы не вызовете их, база данных не будет обновлена.
  
* "Database is locked": The IDE might still be locking the database (SQLite is a single user database), you probably forgot to set the components to inactive and disconnected again after you were done defining all the fields of your TSQLQuery objects. Use the Form's OnCreate event to set the path and activate the objects at runtime only. Most of the things you set in the TSQLQuery from within the IDE don't require (and some don't even allow) them to be active at design time, the only exception is defining the fields where it wants to read the table design, so inactive at design time should be the normal state.
+
* "Database is locked" (База данных заблокирована): IDE может по-прежнему блокировать базу данных (SQLite - это база данных для одного пользователя), вы, вероятно, забыли установить компоненты в неактивное состояние и снова отключить их после того, как вы закончили определение всех полей ваших объектов TSQLQuery. Используйте событие OnCreate формы, чтобы задать путь и активировать объекты только во время выполнения. Большинство вещей, которые вы устанавливаете в TSQLQuery из среды IDE, не требуют (а некоторые даже не позволяют), чтобы они были активными во время разработки, единственным исключением является определение полей, в которых он хочет прочитать дизайн таблицы, поэтому неактивность во время разработки должно быть нормальным состоянием.
  
* Your tables should all have a primary key and you must make sure that the corresponding field has pfInKey and nothing else in its PoviderFlags (these flags control how and where the field is used when automatically constructing the update and delete queries).
+
* Все ваши таблицы должны иметь первичный ключ, и вы должны убедиться, что соответствующее поле имеет pfInKey и ничего больше в его PoviderFlags (эти флаги управляют тем, как и где используется поле при автоматическом построении запросов на обновление и удаление).
  
* If you are using lookup fields
+
* Если вы используете lookup-поля
** make sure the ProviderFlags for the lookup field is completely empty so it won't attempt to use its name in an update query. The lookup field itself is not a data field, it only acts on the value of another field, the corresponding key field, and only this key field will later be used in the update queries. You can set the key field to hidden because usually you don't want to see it in your DBGrid but it needs to be defined.
+
** убедитесь, что ProviderFlags для lookup-поля полностью пуст, чтобы он не пытался использовать свое имя в запросе на обновление. Само поле поиска не является полем данных, оно действует только на значение другого поля, соответствующего ключевого поля, и только это ключевое поле будет позже использоваться в запросах на обновление. Вы можете установить ключевое поле как скрытое, потому что обычно вы не хотите видеть его в своей DBGrid, но его необходимо определить.
** LookupCache must be set to True. At the time of this writing for some reason the lookup field will not display anything otherwise (but still work) and strangely the exact opposite is the case when working with the TSQLite3Dataset or other TXXXDataset components, here it must be set to False. I'm not yet sure whether this is intended behavior or a bug.
+
** LookupCache должен иметь значение True. На момент написания этой статьи по какой-то причине в -lookupполе ничего не отображается (но все равно работает), и, как ни странно, происходит полная противоположность при работе с TSQLite3Dataset или другими компонентами TXXXDataset, здесь должно быть установлено значение False. Я еще не уверен, является ли это предполагаемым поведением или ошибкой.
  
* Usually with simple tables you won't need to set any of the InsertSQL, UpdateSQL and DeleteSQL properties, just leave them empty. If you have the ProviderFlags of all your fields set correctly it should be able to create the needed SQL on the fly. For more details on InsertSQL, UpdateSQL and DeleteSQL, see [[Working_With_TSQLQuery#TSQLQuery.InsertSQL.2C_TSQLQuery.UpdateSQL_and_TSQLQuery.DeleteSQL:_Basic_Use_of_Parameters]].
+
* Обычно для простых таблиц вам не нужно устанавливать какие-либо свойства InsertSQL, UpdateSQL и DeleteSQL, просто оставьте их пустыми. Если у вас правильно установлены ProviderFlags всех ваших полей, он сможет создать необходимый SQL на лету. Подробнее об InsertSQL, UpdateSQL и DeleteSQL см. [[Working_With_TSQLQuery#InsertSQL.2C_UpdateSQL_and_DeleteSQL_-_Basic_use_of_parameters|Работа с TSQLQuery]].
  
After the above is all set up correctly, you should now be able to use the TSQLQuery like any other TDataset, either by manipulating its data programmatically or by placing a TDatasouce on the Form, connecting it to the TSQLQuery and then using data contols like TDBGrid etc.
+
После того, как все вышеперечисленное будет настроено правильно, вы сможете использовать TSQLQuery, как и любой другой TDataset, либо программно манипулируя его данными, либо помещая TDatasouce в форму, подключая его к TSQLQuery, а затем используя контуры данных, такие как TDBGrid и т.п.
  
 
===Creating a Database===
 
===Creating a Database===
  
The [http://www.freepascal.org/docs-html/fcl/sqldb/tsqlconnection.createdb.html 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:
+
Метод [http://www.freepascal.org/docs-html/fcl/sqldb/tsqlconnection.createdb.html TSQLite3Connection.CreateDB], унаследованный от родительского класса, на самом деле ничего не делает; чтобы создать базу данных, если файл еще не существует, вам просто нужно записать данные таблицы, как в следующем примере:
  
(Code extracted from sqlite_encryption_pragma example that ships with Lazarus 1.3 onwards)
+
(Код, извлеченный из примера sqlite_encryption_pragma, который поставляется с Lazarus 1.3 и новее)
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
Line 120: Line 120:
 
begin
 
begin
  
   SQLite3Connection1.Close; // Ensure the connection is closed when we start
+
   SQLite3Connection1.Close; // Убедитесь, что соединение закрыто при запуске
  
 
   try
 
   try
    // Since we're making this database for the first time,
+
  //Поскольку мы делаем эту базу данных впервые,
    // check whether the file already exists
+
  // проверяем, существует ли уже файл   
    newFile := not FileExists(SQLite3Connection1.DatabaseName);
+
  newFile := not FileExists(SQLite3Connection1.DatabaseName);
  
 
     if newFile then
 
     if newFile then
 
     begin
 
     begin
       // Create the database and the tables
+
       // Создаем базу данных и таблицы
 
       try
 
       try
 
         SQLite3Connection1.Open;
 
         SQLite3Connection1.Open;
 
         SQLTransaction1.Active := true;
 
         SQLTransaction1.Active := true;
  
         // Here we're setting up a table named "DATA" in the new database
+
         // Здесь мы настраиваем таблицу с именем "DATA" в новой базе данных.
 
         SQLite3Connection1.ExecuteDirect('CREATE TABLE "DATA"('+
 
         SQLite3Connection1.ExecuteDirect('CREATE TABLE "DATA"('+
 
                     ' "id" Integer NOT NULL PRIMARY KEY AUTOINCREMENT,'+
 
                     ' "id" Integer NOT NULL PRIMARY KEY AUTOINCREMENT,'+
Line 141: Line 141:
 
                     ' "Info" Char(128) NOT NULL);');
 
                     ' "Info" Char(128) NOT NULL);');
  
         // Creating an index based upon id in the DATA Table
+
         // Создание индекса на основе идентификатора в таблице "DATA"
 
         SQLite3Connection1.ExecuteDirect('CREATE UNIQUE INDEX "Data_id_idx" ON "DATA"( "id" );');
 
         SQLite3Connection1.ExecuteDirect('CREATE UNIQUE INDEX "Data_id_idx" ON "DATA"( "id" );');
  
 
         SQLTransaction1.Commit;
 
         SQLTransaction1.Commit;
  
         ShowMessage('Succesfully created database.');
+
         ShowMessage('База данных успешно создана.');
 
       except
 
       except
         ShowMessage('Unable to Create new Database');
+
         ShowMessage('Невозможно создать новую базу данных');
 
       end;
 
       end;
 
     end;
 
     end;
 
   except
 
   except
     ShowMessage('Unable to check if database file exists');
+
     ShowMessage('Невозможно проверить, существует ли файл базы данных');
 
   end;
 
   end;
 
  end;
 
  end;
 
</syntaxhighlight>
 
</syntaxhighlight>
  
===Creating user defined collations ===
+
===Создание определяемых пользователем порядка сортировки ===
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
// utf8 case-sensitive compare callback function
+
// utf8-callback функция сравнения с учетом регистра
 
function UTF8xCompare(user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl;
 
function UTF8xCompare(user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl;
 
var S1, S2: AnsiString;
 
var S1, S2: AnsiString;
Line 169: Line 169:
 
end;
 
end;
  
// utf8 case-insensitive compare callback function
+
// utf8-callback функция сравнения без учета регистра
 
function UTF8xCompare_CI(user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl;
 
function UTF8xCompare_CI(user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl;
 
var S1, S2: AnsiString;
 
var S1, S2: AnsiString;
Line 178: Line 178:
 
end;
 
end;
  
// register collation using SQLite3 API (requires sqlite3dyn unit):
+
// регистрируем порядок сортировки с помощью SQLite3 API (требуется модуль sqlite3dyn):
 
sqlite3_create_collation(SQLite3.Handle, 'UTF8_CI', SQLITE_UTF8, nil, @UTF8xCompare_CI);
 
sqlite3_create_collation(SQLite3.Handle, 'UTF8_CI', SQLITE_UTF8, nil, @UTF8xCompare_CI);
// or using method of TSQLite3Connection:
+
// или используем метод TSQLite3Connection:
 
CreateCollation('UTF8_CI',1,nil,@UTF8xCompare_CI);   
 
CreateCollation('UTF8_CI',1,nil,@UTF8xCompare_CI);   
  
// now we can use case-insensitive comparison in SQL like:
+
// теперь мы можем использовать порядок сортировки без учета регистра в SQL, например:
 
// SELECT * FORM table1 WHERE column1 COLLATE UTF8_CI = 'á'
 
// SELECT * FORM table1 WHERE column1 COLLATE UTF8_CI = 'á'
  
// but this does not work for LIKE operator
+
// но это не работает для оператора LIKE
// in order to support also LIKE operator we must overload default LIKE function using sqlite3_create_function()
+
// чтобы поддерживать также оператор LIKE, мы должны перегрузить функцию LIKE по умолчанию, используя sqlite3_create_function ()
 
// http://www.sqlite.org/lang_corefunc.html#like
 
// http://www.sqlite.org/lang_corefunc.html#like
 
</syntaxhighlight>
 
</syntaxhighlight>
  
===Creating user defined functions ===
+
===Создание пользовательских функций (UDF) ===
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
// example overloading default LOWER() function with user supplied function
+
// пример перегрузки функции LOWER() по умолчанию на функцию, предоставляемую пользователем
// to run this demo, you must add units 'sqlite3dyn' and 'ctypes' to your uses-clause
+
// чтобы запустить эту демку, вы должны добавить модули sqlite3dyn и ctypes в ваше предложение uses
// and add a const 'SQLITE_DETERMINISTIC' with value $800
+
// и добавить константу 'SQLITE_DETERMINISTIC' со значением $800
  
 
procedure UTF8xLower(ctx: psqlite3_context; N: cint; V: ppsqlite3_value); cdecl;
 
procedure UTF8xLower(ctx: psqlite3_context; N: cint; V: ppsqlite3_value); cdecl;
Line 206: Line 206:
 
end;
 
end;
  
// register function LOWER() using SQLite3 API (requires sqlite3dyn unit):
+
// регистрируем функцию LOWER() с помощью SQLite3 API (требуется модуль sqlite3dyn):
 
sqlite3_create_function(SQLite3.Handle, 'lower', 1, SQLITE_UTF8 or SQLITE_DETERMINISTIC, nil, @UTF8xLower, nil, nil);
 
sqlite3_create_function(SQLite3.Handle, 'lower', 1, SQLITE_UTF8 or SQLITE_DETERMINISTIC, nil, @UTF8xLower, nil, nil);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== SQLite3 and Dates ===
+
=== SQLite3 и даты ===
  
* SQLite 3 doesn't store dates as a special DateTime value. It can stores them as strings, doubles or integers - see
+
* SQLite 3 не хранит даты как специальное значение DateTime. Он может хранить их в виде строк, чисел двойной точности или целых чисел - см. [http://www.sqlite.org/datatype3.html#datetime Date and Time Datatype].  
http://www.sqlite.org/datatype3.html#datetime.  
+
* В строках разделителем даты является «-» в соответствии со стандартом SQL/ISO 8601. Таким образом, если вы выполняете INSERT с использованием встроенной функции DATE, она сохранит его как что-то вроде «ГГГГ-ММ-ДД».
* 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'.
+
* Чтение значения DateTime может вызвать проблемы для DataSet, если они хранятся в виде строк: квалификатор .AsDateTime может останавливаться на "строковой дате" SQLite, но это можно преодолеть, используя что-то вроде <tt>strftime(''%d/%m/%Y'',recdate) AS sqlite3recdate</tt> в вашем операторе SQL SELECT, который заставляет SQLite3 возвращать запись даты в указанном формате (строка формата %d/%m/%d соответствует вашему региональному формату даты, который будет пониматься как .AsDateTime) '''==> Пожалуйста, откройте отчет об ошибке с примером приложения, демонстрирующим проблему, если это так'''
* 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 <tt>strftime(''%d/%m/%Y'',recdate) AS sqlite3recdate</tt> 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'''
+
* При сравнении дат, хранящихся в виде строк (используя, например, функцию BETWEEN), помните, что сравнение всегда будет <b>строковым</b> сравнением и, следовательно, будет зависеть от того, как вы сохранили значение даты.
* When comparing dates stored as strings (using for example the BETWEEN function) remember that the comparison will always be a <b>string</b> comparison, and will therefore depend on how you have stored the date value.
 
  
==== Default values in local time instead of UTC ====
+
==== Значения по умолчанию для местного времени вместо UTC ====
  
CURRENT_TIME, CURRENT_DATE and CURRENT_TIMESTAMP return current UTC date and/or time. For local date and/or times we can use:
+
CURRENT_TIME, CURRENT_DATE и CURRENT_TIMESTAMP возвращают текущую дату и/или время в формате UTC. Для местной даты и/или времени мы можем использовать:
  
 
   DEFAULT (datetime('now','localtime')) for datetime values formated YYYY-MM-DD HH:MM:SS
 
   DEFAULT (datetime('now','localtime')) for datetime values formated YYYY-MM-DD HH:MM:SS
Line 226: Line 225:
 
   DEFAULT (time('now','localtime')) for time value formated HH:MM:SS
 
   DEFAULT (time('now','localtime')) for time value formated HH:MM:SS
  
===SQLDB And SQLite troubleshooting===
+
===Устранение неполадок SQLDB и SQLite===
  
* Keep in mind that for designtime support to work (fields etc) Lazarus must find sqlite3.dll too.
+
* Имейте в виду, что для поддержки работы времени разработки (поля и т.д.) Lazarus также должен найти sqlite3.dll ([[user:zoltanleo|прим.перев]]: положите этот файл в корень IDE рядом с экзешником. Обратите внимание, что разрядность библиотеки должна соответствовать разрядности Лазаруса).
* 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.
+
* То же самое и с именем файла базы данных. Всегда используйте абсолютный путь, если вы используете компоненты для извлечения, например, имена полей во время разработки. В противном случае IDE создаст в своем каталоге пустой файл. В случае возникновения проблем проверьте, не содержит ли каталог lazarus/ нулевую байтовую копию файла базы данных.
* 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:
+
* Если у вас есть отношения master/detail, вам необходимо обновлять главный набор данных после каждой вставки, чтобы получить значение для поля внешнего ключа подчиненного набора данных. Это можно сделать в событии AfterPost основного набора данных, вызвав одну из следующих перегруженных процедур:
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
Line 240: Line 239:
 
   
 
   
 
procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery; pKeyField: string);
 
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
+
// Используется, если Dataset не гарантирует сортировку набора данных по первичному ключу автоинкремента
 
var
 
var
 
   vLastID: Integer;
 
   vLastID: Integer;
Line 247: Line 246:
 
begin
 
begin
 
   vUpdateStatus := pDataset.UpdateStatus;
 
   vUpdateStatus := pDataset.UpdateStatus;
   //Get last inserted ID in the database
+
   //Получаем последний вставленный ID в базе данных
 
   pDataset.ApplyUpdates;
 
   pDataset.ApplyUpdates;
 
   vLastID:=(pDataSet.DataBase as TSQLite3Connection).GetInsertID;
 
   vLastID:=(pDataSet.DataBase as TSQLite3Connection).GetInsertID;
   //Now come back to respective row
+
   //Теперь возвращаемся к соответствующей строке
 
   if vUpdateStatus = usInserted then begin
 
   if vUpdateStatus = usInserted then begin
 
     pDataset.Refresh;
 
     pDataset.Refresh;
     //Refresh and go back to respective row
+
     //Обновляемся и возвращаемся к соответствующей строке
 
     pDataset.Locate(pKeyField,vLastID,[]);
 
     pDataset.Locate(pKeyField,vLastID,[]);
 
   end;
 
   end;
Line 259: Line 258:
 
   
 
   
 
procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery);
 
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
+
//Используется только в том случае, если DataSet гарантированно отсортирован по первичному ключу с автоинкрементом.
 
var
 
var
 
   vLastID: Integer;
 
   vLastID: Integer;
Line 270: Line 269:
 
   if vUpdateStatus = usInserted then begin
 
   if vUpdateStatus = usInserted then begin
 
     pDataset.Refresh;
 
     pDataset.Refresh;
     //Dangerous!
+
     //Опасно!
 
     pDataSet.Last;
 
     pDataSet.Last;
 
   end;
 
   end;
Line 277: Line 276:
 
procedure TDataModule1.SQLQuery1AfterPost(DataSet: TDataSet);
 
procedure TDataModule1.SQLQuery1AfterPost(DataSet: TDataSet);
 
begin
 
begin
   RefreshADatasetAfterInsert(Dataset as TSQLQuery); //If your dataset is sorted by primary key
+
   RefreshADatasetAfterInsert(Dataset as TSQLQuery); //Если ваш набор данных отсортирован по первичному ключу
 
end;   
 
end;   
  
 
procedure TDataModule1.SQLQuery2AfterPost(DataSet: TDataSet);
 
procedure TDataModule1.SQLQuery2AfterPost(DataSet: TDataSet);
 
begin
 
begin
   RefreshADatasetAfterInsert(Dataset as TSQLQuery, 'ID'); //if you are not sure that the dataset is always sorted by primary key
+
   RefreshADatasetAfterInsert(Dataset as TSQLQuery, 'ID'); //если вы не уверены, что набор данных всегда сортируется по первичному ключу
 
end;
 
end;
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Vacuum and other operations that must be done outside a transaction ===
+
=== Vacuum и другие операции, которые необходимо выполнять вне транзакции ===
  
SQLDB seems to always require a connection, but some operations like Pragma and Vacuum must
+
Кажется, что SQLDB всегда требует подключения, но некоторые операции, такие как Pragma и Vacuum, должны Быть сделано вне транзакции. Хитрость заключается в том, чтобы завершить транзакцию, выполнить то, что вы должны, и начать транзакцию еще раз (чтобы не запутать sqldb):
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:)
 
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
   // commit any pending operations or use a "fresh" sqlconnection
+
   // коммит любых ожидающих операций или использование «свежего» соединения sql
   Conn.ExecuteDirect('End Transaction');  // End the transaction started by SQLdb
+
   Conn.ExecuteDirect('End Transaction');  // Завершение транзакции, начатой SQLdb
 
   Conn.ExecuteDirect('Vacuum');
 
   Conn.ExecuteDirect('Vacuum');
   Conn.ExecuteDirect('Begin Transaction'); //Start a transaction for SQLdb to use
+
   Conn.ExecuteDirect('Begin Transaction'); //Запуск транзакции для использования SQLdb
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== Using TSQLite3Dataset ==
+
== Использование TSQLite3Dataset ==
  
This section details how to use the TSQLite2Dataset and TSQLite3Dataset components to access SQlite databases.
+
В этом разделе подробно описано, как использовать компоненты TSQLite2Dataset и TSQLite3Dataset для доступа к базам данных SQlite (от Luiz Américo luizmed(at)oi(dot)com(dot))br
by Luiz Américo
 
luizmed(at)oi(dot)com(dot)br
 
  
  
====Requirements====
+
====Требования====
  
* For sqlite2 databases (legacy):
+
* Для баз данных sqlite2 (legacy):
** FPC 2.0.0 or higher
+
** FPC 2.0.0 или выше
** Lazarus 0.9.10 or higher
+
** Lazarus 0.9.10 или выше
** SQLite runtime library 2.8.15 or above*
+
** SQLite runtime библиотеки 2.8.15 или выше*
  
* Sqlite2 is not maintained anymore and the binary file cannot be found in the sqlite site
+
* Sqlite2 больше не поддерживается, и двоичный файл не может быть найден на сайте sqlite
  
* For sqlite3 databases:
+
* Для баз данных sqlite3:
** FPC 2.0.2 or higher
+
** FPC 2.0.2 или выше
** Lazarus 0.9.11 (svn revision 8443) or higher
+
** Lazarus 0.9.11 (svn revision 8443) или выше
** sqlite runtime library 3.2.1 or higer (get it from [http://www.sqlite.org www.sqlite.org])
+
** sqlite runtime библиотеки 3.2.1 или выше (можно получить с [http://www.sqlite.org www.sqlite.org])
  
'''Before initiating a lazarus project, ensure that:'''
+
'''Перед запуском проекта lazarus убедитесь, что:'''
* the sqlite library is either 
+
* библиотека sqlite либо
** in the system PATH or
+
** прописана в системной переменной PATH или
** in the executable output directory and Lazarus (or current project) directories - this option might work on Windows only
+
** находится в каталоге вывода исполняемых файлов и в каталогах Lazarus (или текущего проекта) - этот параметр может работать только в Windows
* under Linux, put cmem as the first unit in uses clause of the main program
+
* в Linux поместите <code>cmem</code> в качестве первого модуля в разделе <code>uses</code> основной программы
** In Debian, Ubuntu and other Debian-like distros, in order to build Lazarus IDE you must install the packages libsqlite-dev/libsqlite3-dev, not only sqlite/sqlite3 (Also applies to OpenSuSe)
+
** В Debian, Ubuntu и других подобных Debian дистрибутивах для создания Lazarus IDE необходимо установить пакеты libsqlite-dev/libsqlite3-dev, а не только sqlite/sqlite3 (также относится к OpenSuSe)
  
====How To Use (Basic Usage)====
+
====Как использовать (базовое использование)====
  
Install the package found at /components/sqlite directory (see instructions [[Install_Packages|here]])
+
Установить пакет, который находится в каталоге /components/sqlite (см. инструкции [[Install_Packages/ru|здесь]]) ([[user:zoltanleo|прим.перев.]]: на момент перевода статьи это можно сделать через стандартный установщик пакетов Лазаруса из меню Package(Пакеты) --> Install/Uninstall Package (Установка/Удаление пакетов) --> справа в окне Available for installation (Доступные для установки) выбираем sqlite3laz 0.4 --> ниже жмем кнопку Install Selection (Установить выбранное) --> жмем в самом низу кнопку Save and rebuild IDE (Сохранить и пересобрать IDE)).
  
At design time, set the following properties:
+
Во время разработки установите следующие свойства:
  
* FileName: path of the sqlite file [required]  
+
* FileName: путь к файлу sqlite [обязательно]
* TableName: name of the table used in the sql statement [required]  
+
* TableName: имя таблицы, используемой в операторе sql [обязательно]
* SQL: a SQL select statement [optional]  
+
* SQL: оператор выбора SQL [по желанию]
* SaveOnClose: The default value is false, which means that changes are not saved. One can change it to true. [optional]
+
* SaveOnClose: значение по умолчанию - false, что означает, что изменения не сохраняются. Его можно изменить на true. [по желанию]
* Active: Needs to be set at design time or at program startup. [required]
+
* Active: необходимо установить во время разработки или при запуске программы. [обязательно]
  
'''Creating a Table (Dataset)'''
+
'''Создание Table (Dataset)'''
  
Double-click the component icon or use the 'Create Table' item of the popup menu that appears when clicking the right mouse button.
+
Дважды щелкните значок компонента или используйте пункт 'Create Table'(Создать таблицу) во всплывающем меню, которое появляется при нажатии правой кнопки мыши.
A simple self-explaining table editor will be shown.
+
Будет показан простой редактор таблиц с пояснениями.
  
Here are all field types supported by TSqliteDataset and TSqlite3Dataset:  
+
Вот все типы полей, поддерживаемые TSqliteDataset и TSqlite3Dataset:
 
    
 
    
 
* Integer
 
* Integer
Line 359: Line 354:
 
* Currency
 
* Currency
 
    
 
    
'''Retrieving the data'''
+
'''Получение данных'''
  
After creating the table or with a previously created Table, open the dataset with the Open method.
+
После создания таблицы или с помощью ранее созданной таблицы откройте набор данных с помощью метода Open.
If the SQL property was not set then all records from all fields will be retrieved, the same if you set the SQL to:
+
Если свойство SQL не было установлено, будут извлечены все записи из всех полей, то же самое можно получить, если вы зададите SQL следующим образом:
  
 
<syntaxhighlight lang=pascal>SQL := 'Select * from TABLENAME';</syntaxhighlight>
 
<syntaxhighlight lang=pascal>SQL := 'Select * from TABLENAME';</syntaxhighlight>
  
'''Applying changes to the underlying datafile'''
+
'''Применение изменений к базовому файлу данных'''
  
To use the ApplyUpdates function, the dataset must contain at least one field that fulfills the requirements for a Primary Key (values must be UNIQUE and not NULL)
+
Чтобы использовать функцию ApplyUpdates, набор данных должен содержать по крайней мере одно поле, которое удовлетворяет требованиям для первичного ключа (значения должны быть UNIQUE, а не NULL)
  
It's possible to do that in two ways:
+
Сделать это можно двумя способами:
  
* Set PrimaryKey property to the name of a Primary Key field
+
* Установить свойство PrimaryKey на имя поля первичного ключа
* Add an AutoInc field (This is easier since the TSqliteDataSet automatically handles it as a Primary Key)
+
* Добавить поле AutoInc (это проще, поскольку TSqliteDataSet автоматически обрабатывает его как первичный ключ)
  
If one of the two conditions is set, just call
+
Если установлено одно из двух условий, просто вызовите
 
    
 
    
 
<syntaxhighlight lang=pascal>ApplyUpdates;</syntaxhighlight>
 
<syntaxhighlight lang=pascal>ApplyUpdates;</syntaxhighlight>
  
{{Note|If both conditions are set, the field corresponding to PrimaryKey is used to apply the updates.}}
+
{{Note|Если заданы оба условия, поле, соответствующее PrimaryKey, используется для применения обновлений.}}
  
{{Note|Setting PrimaryKey to a field that is not a Primary Key will lead to loss of data if ApplyUpdates is called, so ensure that the chosen field contains not Null and Unique values before using it.}}
+
{{Note|Установка PrimaryKey в поле, которое не является первичным ключом, приведет к потере данных при вызове ApplyUpdates, поэтому перед его использованием убедитесь, что выбранное поле не содержит значений Null и Unique.}}
  
=====Master/detail example=====
+
=====Пример Master/detail=====
  
Various examples of master/detail relations (e.g. the relation between customer and orders):
+
Различные примеры отношений master/detail (например, отношения между клиентом и заказами):
  
* the generic SQLDB way of doing this using the <code>DataSource</code> property: [[MasterDetail]]
+
* общий способ SQLDB для этого с использованием свойства <code>DataSource</code>: [[MasterDetail]]
* TSQLite3 specific example using locate: [[TSqlite3 Master Detail Example]].
+
* Конкретный пример TSQLite3 с использованием метода <code>locate</code>: [[TSqlite3_Master_Detail_Example|пример TSqlite3 Master Detail]].
  
====Remarks====
+
====Примечания====
  
* Although it has been tested with 10,000 records and worked fine, TSqliteDataset keeps all the data in memory, so remember to retrieve only the necessary data (especially with Memo Fields).
+
* Несмотря на то, что TSqliteDataset был протестирован с 10 000 записей и работал нормально, все данные хранятся ([[user:zoltanleo|прим.перев.]]: кешируются) в памяти, поэтому не забывайте извлекать только необходимые данные (особенно с полями Memo).
* The same datafile (Filename property) can host several tables/datasets
+
* Один и тот же файл данных (свойство Filename) может содержать несколько таблиц/наборов данных.
* Several datasets (different combinations of fields) can be created using the same table simultaneously
+
* Несколько наборов данных (разные комбинации полей) могут быть созданы с использованием одной и той же таблицы одновременно
* It's possible to filter the data using WHERE statements in the sql, closing and reopening the dataset (or calling RefetchData method). But in this case, the order and number of fields must remain the same
+
* Можно фильтровать данные с помощью операторов WHERE в sql, закрывая и повторно открывая набор данных (или вызывая метод RefetchData). Но в этом случае порядок и количество полей должны оставаться прежними.
* It's also possible to use complex SQL statements using aliases, joins, views in multiple tables (remember that they must reside in the same datafile), but in this case ApplyUpdates won't work. If someone wants to use complex queries and to apply the updates to the datafile, mail me and i will give some hints how to do that
+
* Также можно использовать сложные операторы SQL, используя псевдонимы, объединения, представления в нескольких таблицах (помните, что они должны находиться в одном файле данных), но в этом случае ApplyUpdates не будет работать. Если кто-то хочет использовать сложные запросы и применить обновления к файлу данных, напишите мне, и я дам несколько советов, как это сделать.
* Setting filename to a sqlite datafile not created by TSqliteDataset and opening it is allowed but some fields won't have the correct field type detected. These will be treated as string fields.
+
* Установка имени файла в файл данных sqlite, не созданный TSqliteDataset, и его открытие разрешено, но в некоторых полях не будет обнаружен правильный тип поля. Они будут рассматриваться как строковые поля.
  
Generic examples can be found at fpc/fcl-db/src/sqlite SVN directory
+
Общие примеры можно найти в SVN каталоге fpc/fcl-db/src/sqlite.
  
 
==See also==
 
==See also==

Latest revision as of 16:18, 16 November 2021

English (en) español (es) français (fr) 日本語 (ja) polski (pl) русский (ru) 中文(中国大陆)‎ (zh_CN)

Databases portal

References:

Tutorials/practical articles:

Databases

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

Поддержка SQLite и FPC/Lazarus

SQLite - это встроенная (не серверная) однопользовательская база данных, которую можно использовать в приложениях FPC и Lazarus. Для доступа к SQLite из программ FPC/Lazarus можно использовать различные драйверы. Все драйверы нуждаются в библиотеке SQLite/dll в исполняемом каталоге (который может быть каталогом вашего проекта или, например, (projectdir)/lib/architecture/ в зависимости от настроек вашего проекта Lazarus) (и распространяется вместе с вашим исполняемым файлом) для работы.

Это также может быть необходимо включить в ваш каталог Lazarus IDE. См. ветку форума и особенно внимательно прочитайте про TSQLite3Dataset и TSQLiteDataset ниже

В большинстве дистрибутивов Linux по умолчанию установлен sqlite3 (например, libsqlite3.so.0), но для дистрибутивов Ubuntu, по крайней мере, также требуется соответствующий пакет Dev. Оба должны быть установлены через системный менеджер пакетов и помечены как зависимость, а не распространяться вместе с вашим приложением.

Win64: см. предупреждение здесь о неиспользовании определенных версий FPC/Lazarus Win64.

Прямой доступ к SQLite

Вы можете использовать простой способ подключения SQLite к Lazarus. Компоненты называются LiteDAC. Компоненты доступа к данным SQLite (LiteDAC) - это библиотека компонентов, которая обеспечивает встроенное подключение к SQLite из Lazarus (и Free Pascal) в Windows, macOS, iOS, Android, Linux и FreeBSD как для 32-разрядных, так и для 64-разрядных платформ. LiteDAC предназначен для программистов, которые могут разрабатывать действительно кроссплатформенные настольные и мобильные приложения баз данных SQLite без необходимости развертывания каких-либо дополнительных библиотек.

Вы можете скачать пробную версию этого коммерческого продукта по адресу _https://www.devart.com/litedac/download.html (LiteDAC 4.4 for Lazarus (FreePascal))

Встроенный SQLDB

FPC/Lazarus предлагает встроенные компоненты SQLDB, которые включают поддержку баз данных SQLite (TSQLite3Connection) с вкладки SQLdb в Палитре компонентов, которые позволяют, например, создавать графические интерфейсы пользователя с такими компонентами базы данных, как TDBGrid. Преимущество использования SQLDB заключается в том, что довольно легко перейти на другую базу данных, такую ​​как Firebird или PostgreSQL, без особых изменений в программе. Подробнее см. ниже.

Поддержка Spatialite

Spatialite - это ГИС-расширения SQLite, которые можно использовать из SQLDB. См. Spatialite.

Поддержка шифрования SQLite

В последних версиях FPC (реализованных в марте 2012 г.) SQLDB включал поддержку некоторых расширенных версий SQLite3, которые шифруют файл базы данных SQLite с использованием алгоритма AES. Используйте свойство пароля, чтобы установить ключ шифрования.

Примеры:

  • SQLCipher: Открытый исходный код, например Бинарные файлы Windows не бесплатно (их нужно скомпилировать самостоятельно)
  • System.Data.SQLite: с открытым исходным кодом, доступны двоичные файлы Windows (32, 64, CE), загрузите, например, один из предварительно скомпилированных двоичных файлов и переименуйте SQLite.Interop.dll в sqlite3.dll (если вы используете статически связанные файлы, вероятно, вам нужно переименовать System.Data.SQLite.DLL в sqlite3.dll)
  • wxSQLite3: открытый исходный код, доступны некоторые бинарные файлы для Linux (напр: https://launchpad.net/ubuntu/oneiric/+package/libwxsqlite3-2.8-0)
  • sqleet: открытый исходный код, нет зависимостей от других библиотек, легко собирается при помощи GCC в исполняемые файлы и файлы библиотек, кроссплаформенный. Доступны механизмы шифрования как в интерактивном режиме, так и посредством sqleet API.

sqlite3backup

sqlite3backup - это модуль, поставляемый с FPC (не в Lazarus, но может использоваться программно), который обеспечивает функции резервного копирования/восстановления для SQLite3. Он использует SQLDB sqlite3conn.

Zeos

Zeos

SQLitePass

Компоненты SQLitePass. Последнее обновление кода в 2010. Последняя активность на форуме в 2011.

TSQLite3Dataset и TSQLiteDataset

Существуют также отдельные пакеты TSQLiteDataset (модуль sqlite) и TSQLite3Dataset (модуль sqlite3ds); см. ниже описание того, как их использовать. Посетите домашнюю страницу sqlite4fpc, чтобы найти справочник по API и другие руководства.

TSqliteDataset и TSqlite3Dataset являются потомками TDataSet, которые обращаются к базам данных sqlite 2.8.x и 3.x.x соответственно. Для новых проектов вы, вероятно, будете использовать TSQlite3Dataset, поскольку текущая версия SQLite 3.x.

Ниже приведен список основных преимуществ и недостатков по сравнению с другими драйверами/методами доступа FPC/Lazarus SQLite:

Преимущества:

  • Гибкость: программисты могут выбирать, использовать или не использовать язык SQL, что позволяет им работать с простыми макетами таблиц или любым сложным макетом, который позволяет SQL/sqlite.

Недостатки:

  • Переход на другие базы данных сложнее, чем при использовании компонентов SQLDB или Zeos
Light bulb  Примечание: Учитывая вышеизложенное, многие пользователи будут использовать SQLDB или Zeos из-за преимуществ, если им не нужен низкоуровневый доступ к библиотеке SQLite.

Использование компонентов SQLdb со SQLite

Эти инструкции сосредоточены на особенностях SQLDB (TSQLite3Connection) для SQLite. Для общего обзора ознакомьтесь с SqlDB: Howto, где есть полезная информация о компонентах SQLdb.

См. Учебник1 по SQLdb для обучения создания программы с поддержкой базы данных с графическим интерфейсом пользователя, которая написана для SQLite/SQLDB (а также для Firebird/SQLDB, PostgreSQL/SQLDB, в основном любой СУБД, поддерживаемой SQLDB).

Мы будем использовать комбинацию из трех компонентов из вкладки Lazarus SQLdb: TSQLite3Connection, TSQLTransaction и TSQLQuery. TSQLQuery действует как наш TDataset; в простейшем случае это просто одна из наших таблиц. Для простоты: убедитесь, что у вас уже есть существующий файл базы данных SQLite, и вам не нужно создавать новый сейчас. TSQLite3Connection можно найти в модуле sqlite3conn, если вы хотите объявить его самостоятельно или работаете в FreePascal.

Эти три компонента связаны друг с другом как обычно: в TSQLQuery установите свойства Database и Transaction, в TSQLTransaction установите свойство Database. В компонентах Transaction и Connection особо нечего делать, большинство интересного будет сделано в TSQLQuery. Настройте компоненты следующим образом:

TSQLite3Connection:

  • DatabaseName: установите для этого свойства имя файла (абсолютный путь!) вашего файла SQLite. К сожалению, вы не можете просто использовать относительный путь, который работает без изменений во время разработки и во время выполнения (это все еще верно? Разве вы не можете просто скопировать файл db в сценарий оболочки после сборки или создать символическую ссылку на него? ). Вы должны убедиться, что при запуске приложения правильный путь к файлу всегда устанавливается программно, независимо от того, что он содержал во время разработки.
Light bulb  Примечание: Чтобы установить полный путь к библиотеке (если вы поместите свою sqlite dll/so/dylib в место, где ОС ее не найдет, например каталог приложения в Linux/OSX), вы можете установить «SQLiteLibraryName» свойство (ДО того, как будет установлено какое-либо соединение, например, в событии OnCreate главной формы)

, например:

SQLiteLibraryName:='./sqlite3.so';

TSQLQuery:

  • SQL: задайте для него простой запрос выбора для одной из ваших таблиц. Например, если у вас есть таблица 'foo' и вы хотите, чтобы этот набор данных представлял эту таблицу, просто используйте следующие:
    SELECT * FROM foo
    
  • Active: установите для него значение True в среде IDE, чтобы проверить, все ли настроено правильно. Это также автоматически активирует транзакцию и объекты подключения. Если вы получаете сообщение об ошибке, то либо DatabaseName соединения неверно, либо запрос SQL неверен. Позже, когда мы закончим добавление полей (см. ниже), снова установим их все в неактивные состояния, мы не хотим, чтобы среда IDE блокировала базу данных SQLite (для одного пользователя!) при тестировании приложения.
  • Наверное, не нужно для правильной работы - нужно будет проверить (June 2012) Теперь мы можем добавить поля в наш TSQLQuery. Пока компоненты все еще активны, щелкните правой кнопкой мыши и «отредактируйте поля ...». Нажмите кнопку «+» и добавьте поля. В нем будут перечислены все поля, возвращенные вашим SQL-запросом. Добавьте все поля, которые вам понадобятся, вы также можете добавить сюда поля поиска; в этом случае просто убедитесь, что вы уже определили все необходимые поля в других наборах данных, прежде чем начинать добавлять поля поиска, которые ссылаются на них. Если в вашей таблице много столбцов, и они вам не нужны, вы можете просто не указывать их, а также сделать свой SQL более конкретным.
  • В вашем коде вам нужно вызвать SQLQuery.ApplyUpdates и SQLTransaction.Commit, события TSQLQuery.AfterPost и AfterInsert - хорошее место для этого при использовании его с элементами управления с учетом данных, но, конечно, вы также можете отложить эти вызовы на более позднее время. Если вы не вызовете их, база данных не будет обновлена.
  • "Database is locked" (База данных заблокирована): IDE может по-прежнему блокировать базу данных (SQLite - это база данных для одного пользователя), вы, вероятно, забыли установить компоненты в неактивное состояние и снова отключить их после того, как вы закончили определение всех полей ваших объектов TSQLQuery. Используйте событие OnCreate формы, чтобы задать путь и активировать объекты только во время выполнения. Большинство вещей, которые вы устанавливаете в TSQLQuery из среды IDE, не требуют (а некоторые даже не позволяют), чтобы они были активными во время разработки, единственным исключением является определение полей, в которых он хочет прочитать дизайн таблицы, поэтому неактивность во время разработки должно быть нормальным состоянием.
  • Все ваши таблицы должны иметь первичный ключ, и вы должны убедиться, что соответствующее поле имеет pfInKey и ничего больше в его PoviderFlags (эти флаги управляют тем, как и где используется поле при автоматическом построении запросов на обновление и удаление).
  • Если вы используете lookup-поля
    • убедитесь, что ProviderFlags для lookup-поля полностью пуст, чтобы он не пытался использовать свое имя в запросе на обновление. Само поле поиска не является полем данных, оно действует только на значение другого поля, соответствующего ключевого поля, и только это ключевое поле будет позже использоваться в запросах на обновление. Вы можете установить ключевое поле как скрытое, потому что обычно вы не хотите видеть его в своей DBGrid, но его необходимо определить.
    • LookupCache должен иметь значение True. На момент написания этой статьи по какой-то причине в -lookupполе ничего не отображается (но все равно работает), и, как ни странно, происходит полная противоположность при работе с TSQLite3Dataset или другими компонентами TXXXDataset, здесь должно быть установлено значение False. Я еще не уверен, является ли это предполагаемым поведением или ошибкой.
  • Обычно для простых таблиц вам не нужно устанавливать какие-либо свойства InsertSQL, UpdateSQL и DeleteSQL, просто оставьте их пустыми. Если у вас правильно установлены ProviderFlags всех ваших полей, он сможет создать необходимый SQL на лету. Подробнее об InsertSQL, UpdateSQL и DeleteSQL см. Работа с TSQLQuery.

После того, как все вышеперечисленное будет настроено правильно, вы сможете использовать TSQLQuery, как и любой другой TDataset, либо программно манипулируя его данными, либо помещая TDatasouce в форму, подключая его к TSQLQuery, а затем используя контуры данных, такие как TDBGrid и т.п.

Creating a Database

Метод TSQLite3Connection.CreateDB, унаследованный от родительского класса, на самом деле ничего не делает; чтобы создать базу данных, если файл еще не существует, вам просто нужно записать данные таблицы, как в следующем примере:

(Код, извлеченный из примера sqlite_encryption_pragma, который поставляется с Lazarus 1.3 и новее)

var
  newFile : Boolean;
begin

  SQLite3Connection1.Close; // Убедитесь, что соединение закрыто при запуске

  try
  //Поскольку мы делаем эту базу данных впервые,
  // проверяем, существует ли уже файл    
  newFile := not FileExists(SQLite3Connection1.DatabaseName);

    if newFile then
    begin
      // Создаем базу данных и таблицы
      try
        SQLite3Connection1.Open;
        SQLTransaction1.Active := true;

        // Здесь мы настраиваем таблицу с именем "DATA" в новой базе данных.
        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);');

        // Создание индекса на основе идентификатора в таблице "DATA"
        SQLite3Connection1.ExecuteDirect('CREATE UNIQUE INDEX "Data_id_idx" ON "DATA"( "id" );');

        SQLTransaction1.Commit;

        ShowMessage('База данных успешно создана.');
      except
        ShowMessage('Невозможно создать новую базу данных');
      end;
    end;
  except
    ShowMessage('Невозможно проверить, существует ли файл базы данных');
  end;
 end;

Создание определяемых пользователем порядка сортировки

// utf8-callback функция сравнения с учетом регистра
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-callback функция сравнения без учета регистра
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;

// регистрируем порядок сортировки с помощью SQLite3 API (требуется модуль sqlite3dyn):
sqlite3_create_collation(SQLite3.Handle, 'UTF8_CI', SQLITE_UTF8, nil, @UTF8xCompare_CI);
// или используем метод TSQLite3Connection:
CreateCollation('UTF8_CI',1,nil,@UTF8xCompare_CI);  

// теперь мы можем использовать порядок сортировки без учета регистра в SQL, например:
// SELECT * FORM table1 WHERE column1 COLLATE UTF8_CI = 'á'

// но это не работает для оператора LIKE
// чтобы поддерживать также оператор LIKE, мы должны перегрузить функцию LIKE по умолчанию, используя sqlite3_create_function ()
// http://www.sqlite.org/lang_corefunc.html#like

Создание пользовательских функций (UDF)

// пример перегрузки функции LOWER() по умолчанию на функцию, предоставляемую пользователем
// чтобы запустить эту демку, вы должны добавить модули sqlite3dyn и ctypes в ваше предложение uses
// и добавить константу 'SQLITE_DETERMINISTIC' со значением $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;

// регистрируем функцию LOWER() с помощью SQLite3 API (требуется модуль sqlite3dyn):
sqlite3_create_function(SQLite3.Handle, 'lower', 1, SQLITE_UTF8 or SQLITE_DETERMINISTIC, nil, @UTF8xLower, nil, nil);

SQLite3 и даты

  • SQLite 3 не хранит даты как специальное значение DateTime. Он может хранить их в виде строк, чисел двойной точности или целых чисел - см. Date and Time Datatype.
  • В строках разделителем даты является «-» в соответствии со стандартом SQL/ISO 8601. Таким образом, если вы выполняете INSERT с использованием встроенной функции DATE, она сохранит его как что-то вроде «ГГГГ-ММ-ДД».
  • Чтение значения DateTime может вызвать проблемы для DataSet, если они хранятся в виде строк: квалификатор .AsDateTime может останавливаться на "строковой дате" SQLite, но это можно преодолеть, используя что-то вроде strftime(%d/%m/%Y,recdate) AS sqlite3recdate в вашем операторе SQL SELECT, который заставляет SQLite3 возвращать запись даты в указанном формате (строка формата %d/%m/%d соответствует вашему региональному формату даты, который будет пониматься как .AsDateTime) ==> Пожалуйста, откройте отчет об ошибке с примером приложения, демонстрирующим проблему, если это так
  • При сравнении дат, хранящихся в виде строк (используя, например, функцию BETWEEN), помните, что сравнение всегда будет строковым сравнением и, следовательно, будет зависеть от того, как вы сохранили значение даты.

Значения по умолчанию для местного времени вместо UTC

CURRENT_TIME, CURRENT_DATE и CURRENT_TIMESTAMP возвращают текущую дату и/или время в формате UTC. Для местной даты и/или времени мы можем использовать:

 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 и SQLite

  • Имейте в виду, что для поддержки работы времени разработки (поля и т.д.) Lazarus также должен найти sqlite3.dll (прим.перев: положите этот файл в корень IDE рядом с экзешником. Обратите внимание, что разрядность библиотеки должна соответствовать разрядности Лазаруса).
  • То же самое и с именем файла базы данных. Всегда используйте абсолютный путь, если вы используете компоненты для извлечения, например, имена полей во время разработки. В противном случае IDE создаст в своем каталоге пустой файл. В случае возникновения проблем проверьте, не содержит ли каталог lazarus/ нулевую байтовую копию файла базы данных.
  • Если у вас есть отношения master/detail, вам необходимо обновлять главный набор данных после каждой вставки, чтобы получить значение для поля внешнего ключа подчиненного набора данных. Это можно сделать в событии AfterPost основного набора данных, вызвав одну из следующих перегруженных процедур:
interface
    procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery);overload;
    procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery; pKeyField: string);overload;  
 
implementation
 
procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery; pKeyField: string);
// Эта процедура обновляет набор данных и помещает курсор на последнюю запись
// Используется, если Dataset не гарантирует сортировку набора данных по первичному ключу автоинкремента
var
  vLastID: Integer;
  vUpdateStatus : TUpdateStatus;
begin
  vUpdateStatus := pDataset.UpdateStatus;
  //Получаем последний вставленный ID в базе данных 
  pDataset.ApplyUpdates;
  vLastID:=(pDataSet.DataBase as TSQLite3Connection).GetInsertID;
  //Теперь возвращаемся к соответствующей строке
  if vUpdateStatus = usInserted then begin
    pDataset.Refresh;
    //Обновляемся и возвращаемся к соответствующей строке
    pDataset.Locate(pKeyField,vLastID,[]);
  end;
end;
 
procedure RefreshADatasetAfterInsert(pDataSet: TSQLQuery);
//Эта процедура обновляет набор данных и помещает курсор на последнюю запись
//Используется только в том случае, если DataSet гарантированно отсортирован по первичному ключу с автоинкрементом.
var
  vLastID: Integer;
  vUpdateStatus : TUpdateStatus;
begin
  vUpdateStatus := pDataset.UpdateStatus;
  pDataset.ApplyUpdates;
  vLastID:=(pDataSet.DataBase as TSQLite3Connection).GetInsertID;
  if vUpdateStatus = usInserted then begin
    pDataset.Refresh;
    //Опасно!
    pDataSet.Last;
  end;
end;

procedure TDataModule1.SQLQuery1AfterPost(DataSet: TDataSet);
begin
  RefreshADatasetAfterInsert(Dataset as TSQLQuery); //Если ваш набор данных отсортирован по первичному ключу
end;  

procedure TDataModule1.SQLQuery2AfterPost(DataSet: TDataSet);
begin
  RefreshADatasetAfterInsert(Dataset as TSQLQuery, 'ID'); //если вы не уверены, что набор данных всегда сортируется по первичному ключу
end;

Vacuum и другие операции, которые необходимо выполнять вне транзакции

Кажется, что SQLDB всегда требует подключения, но некоторые операции, такие как Pragma и Vacuum, должны Быть сделано вне транзакции. Хитрость заключается в том, чтобы завершить транзакцию, выполнить то, что вы должны, и начать транзакцию еще раз (чтобы не запутать sqldb):

  // коммит любых ожидающих операций или использование «свежего» соединения sql
  Conn.ExecuteDirect('End Transaction');  // Завершение транзакции, начатой SQLdb
  Conn.ExecuteDirect('Vacuum');
  Conn.ExecuteDirect('Begin Transaction'); //Запуск транзакции для использования SQLdb

Использование TSQLite3Dataset

В этом разделе подробно описано, как использовать компоненты TSQLite2Dataset и TSQLite3Dataset для доступа к базам данных SQlite (от Luiz Américo luizmed(at)oi(dot)com(dot))br


Требования

  • Для баз данных sqlite2 (legacy):
    • FPC 2.0.0 или выше
    • Lazarus 0.9.10 или выше
    • SQLite runtime библиотеки 2.8.15 или выше*
  • Sqlite2 больше не поддерживается, и двоичный файл не может быть найден на сайте sqlite
  • Для баз данных sqlite3:
    • FPC 2.0.2 или выше
    • Lazarus 0.9.11 (svn revision 8443) или выше
    • sqlite runtime библиотеки 3.2.1 или выше (можно получить с www.sqlite.org)

Перед запуском проекта lazarus убедитесь, что:

  • библиотека sqlite либо
    • прописана в системной переменной PATH или
    • находится в каталоге вывода исполняемых файлов и в каталогах Lazarus (или текущего проекта) - этот параметр может работать только в Windows
  • в Linux поместите cmem в качестве первого модуля в разделе uses основной программы
    • В Debian, Ubuntu и других подобных Debian дистрибутивах для создания Lazarus IDE необходимо установить пакеты libsqlite-dev/libsqlite3-dev, а не только sqlite/sqlite3 (также относится к OpenSuSe)

Как использовать (базовое использование)

Установить пакет, который находится в каталоге /components/sqlite (см. инструкции здесь) (прим.перев.: на момент перевода статьи это можно сделать через стандартный установщик пакетов Лазаруса из меню Package(Пакеты) --> Install/Uninstall Package (Установка/Удаление пакетов) --> справа в окне Available for installation (Доступные для установки) выбираем sqlite3laz 0.4 --> ниже жмем кнопку Install Selection (Установить выбранное) --> жмем в самом низу кнопку Save and rebuild IDE (Сохранить и пересобрать IDE)).

Во время разработки установите следующие свойства:

  • FileName: путь к файлу sqlite [обязательно]
  • TableName: имя таблицы, используемой в операторе sql [обязательно]
  • SQL: оператор выбора SQL [по желанию]
  • SaveOnClose: значение по умолчанию - false, что означает, что изменения не сохраняются. Его можно изменить на true. [по желанию]
  • Active: необходимо установить во время разработки или при запуске программы. [обязательно]

Создание Table (Dataset)

Дважды щелкните значок компонента или используйте пункт 'Create Table'(Создать таблицу) во всплывающем меню, которое появляется при нажатии правой кнопки мыши. Будет показан простой редактор таблиц с пояснениями.

Вот все типы полей, поддерживаемые TSqliteDataset и TSqlite3Dataset:

  • Integer
  • AutoInc
  • String
  • Memo
  • Bool
  • Float
  • Word
  • DateTime
  • Date
  • Time
  • LargeInt
  • Currency

Получение данных

После создания таблицы или с помощью ранее созданной таблицы откройте набор данных с помощью метода Open. Если свойство SQL не было установлено, будут извлечены все записи из всех полей, то же самое можно получить, если вы зададите SQL следующим образом:

SQL := 'Select * from TABLENAME';

Применение изменений к базовому файлу данных

Чтобы использовать функцию ApplyUpdates, набор данных должен содержать по крайней мере одно поле, которое удовлетворяет требованиям для первичного ключа (значения должны быть UNIQUE, а не NULL)

Сделать это можно двумя способами:

  • Установить свойство PrimaryKey на имя поля первичного ключа
  • Добавить поле AutoInc (это проще, поскольку TSqliteDataSet автоматически обрабатывает его как первичный ключ)

Если установлено одно из двух условий, просто вызовите

ApplyUpdates;
Light bulb  Примечание: Если заданы оба условия, поле, соответствующее PrimaryKey, используется для применения обновлений.
Light bulb  Примечание: Установка PrimaryKey в поле, которое не является первичным ключом, приведет к потере данных при вызове ApplyUpdates, поэтому перед его использованием убедитесь, что выбранное поле не содержит значений Null и Unique.
Пример Master/detail

Различные примеры отношений master/detail (например, отношения между клиентом и заказами):

  • общий способ SQLDB для этого с использованием свойства DataSource: MasterDetail
  • Конкретный пример TSQLite3 с использованием метода locate: пример TSqlite3 Master Detail.

Примечания

  • Несмотря на то, что TSqliteDataset был протестирован с 10 000 записей и работал нормально, все данные хранятся (прим.перев.: кешируются) в памяти, поэтому не забывайте извлекать только необходимые данные (особенно с полями Memo).
  • Один и тот же файл данных (свойство Filename) может содержать несколько таблиц/наборов данных.
  • Несколько наборов данных (разные комбинации полей) могут быть созданы с использованием одной и той же таблицы одновременно
  • Можно фильтровать данные с помощью операторов WHERE в sql, закрывая и повторно открывая набор данных (или вызывая метод RefetchData). Но в этом случае порядок и количество полей должны оставаться прежними.
  • Также можно использовать сложные операторы SQL, используя псевдонимы, объединения, представления в нескольких таблицах (помните, что они должны находиться в одном файле данных), но в этом случае ApplyUpdates не будет работать. Если кто-то хочет использовать сложные запросы и применить обновления к файлу данных, напишите мне, и я дам несколько советов, как это сделать.
  • Установка имени файла в файл данных sqlite, не созданный TSqliteDataset, и его открытие разрешено, но в некоторых полях не будет обнаружен правильный тип поля. Они будут рассматриваться как строковые поля.

Общие примеры можно найти в SVN каталоге fpc/fcl-db/src/sqlite.

See also