Pull to refresh

SQLite — замечательная встраиваемая БД (часть 2)

Reading time 4 min
Views 172K
Часть 1
Часть 3

В этой части будут затронуты непростые вопросы использования SQLite через работу с его программным интерфейсом (API).



Что такое SQLite API? Это набор функций sqlite3_XXX на языке C.

Заголовки этих функций находятся в sqlite3.h, а описание API в виде одного большого HTML находится тут.

Мы начнем использовать API, а позднее плавно перейдем к вопросам оборачивания его в уютный фреймворк.

Попробуем создать небольшой проект на C++ (я делал в MS Visual Studio), который что-то делает с SQLite базой.

Использовать SQLite в своем проекте можно двумя способами.

«Вкомпилировать» код (если это C или C++). Или загружать и использовать sqlite3.dll (позволяет легко обновлять SQLite и не привязан к языку).

В любом случае, надо создать новый проект (консольного) приложения (я использовал MS Visual Studio) и добавить в него вот такой main.cpp:

 
#include <stdio.h>
#include "sqlite3.h"
 
const char* SQL = "CREATE TABLE IF NOT EXISTS foo(a,b,c); INSERT INTO FOO VALUES(1,2,3); INSERT INTO FOO SELECT * FROM FOO;";
 
int main(int argc, char **argv){
 
sqlite3 *db = 0; // хэндл объекта соединение к БД
char *err = 0;
 
// открываем соединение
if( sqlite3_open("my_cosy_database.dblite", &db) )
fprintf(stderr, "Ошибка открытия/создания БД: %s\n", sqlite3_errmsg(db));
// выполняем SQL
else if (sqlite3_exec(db, SQL, 0, 0, &err))
{
fprintf(stderr, "Ошибка SQL: %sn", err);
sqlite3_free(err);
}
// закрываем соединение
sqlite3_close(db);
return 0;
}
 


Далее, если мы желаем собрать проект вместе с кодом SQLite, то надо:

— скачать исходный код в виде amalgamation;
— извлечь из него sqlite3.h и sqlite3.c и добавить их в проект.

Если же мы хотим использовать sqlite3.dll, необходимо:

— скачать SQLite DLL и распаковать;
— выполнить «LIB.EXE /DEF:sqlite3.def» в папке куда распаковали для получения sqlite3.lib (убедитесь, что пути к lib.exe прописаны через вызов vcvars32.bat);
— включить в проект sqlite3.lib;
— скачать amalgamation и извлечь из него sqlite3.h;
— включить в проект sqlite3.h;

Компилируем, выполняем (во втором случае, DLL должна быть доступна для исполняемого файла).

При первом запуске будет создан файл «my_cosy_database.dblite» с БД, в нем — одна таблица и две записи в ней.
При последующих запусках — программа будет присоединяться к уже существующей БД и удваивать число записей в таблице.

Давайте разбираться с кодом проекта.

Использование SQLite предполагает, что мы хотим выполнять команды на языке SQL в какой-то БД (Ваш К.О.!).

Можно представить работу с SQLite базой как работу с файлами в ОС Windows. Мы открываем файл и получаем _хэндл_ файла, к которому «привязан» некий системный объект (файл). Передавая этот хэндл в различные функции мы просим систему что-то сделать с файлом. Затем — закрываем файл. Также и в SQLite. Мы открываем файл с БД и получаем хэндл объекта «соединение к БД». Затем мы исполняем некие SQL команды через вызовы функций, получающих этот хэндл, и, в конце, закрываем соединение.

Ничего оригинального, особенного или хитрого, как видим, тут нет.

Расширение файла с БД SQLite не стандартизовано. Некоторые делают его ".sqlite3", но можно поставить любое.

Функция

int sqlite3_open(
  const char *filename,   /* Database filename (UTF-8) */
  sqlite3 **ppDb          /* OUT: SQLite db handle */
);
 

создает или открывает БД в указанном файле (UTF-8!) и заносит хендл соединения в db. Она возвращает 0 (успех) или код ошибки. Закрывающий вызов sqlite3_close нужен в любом случае (даже при ошибке sqlite3_open).

Функция

int sqlite3_exec(
  sqlite3*,                                  /* An open database */
  const char *sql,                           /* SQL to be evaluated (UTF-8) */
  int (*callback)(void*,int,char**,char**),  /* Callback function */
  void *,                                    /* 1st argument to callback */
  char **errmsg                              /* Error msg written here */
);
 


выполняет команду SQL (состояющую из одного или нескольких операторов SQL в UTF-8, разделенных ";") в контексте указанного (открытого) соединения к БД.

Функция обратного вызова (callback) и custom аргумент к ней нужны, если делается SELECT (для извлечения данных). Об этом позже, пока не используем.

В параметре errmsg можно получить текст ошибки и позднее очистить его через sqlite3_free. Если передать здесь NULL, то текста ошибки не получим.

Как и sqlite3_open возвращается 0 или код ошибки.

Команда «CREATE TABLE» содержит уточнение «IF NOT EXISTS». Это означает, что таблица создается, если ее — нет. Если есть, то ничего не происходит (и нет ошибки).

Собственно, вот и все. Несмотря на то, что в реальных проектах не используются ни sqlite3_open (есть более мощный вызов sqlite3_open_v2), ни sqlite3_exec (обычно используется связка вызовов, компилирующих SQL, привязывающих параметры и пр.) это вполне рабочий проект.

Он несет и еще одну важную миссию. Как уже было сказано при каждом запуске он удваивает кол-во строк в таблице foo. После 20 запусков в таблице будет ~2 млн записей.

Т.е. 21-й запуск вставляет ~2 млн записей.

На моей машине (Windows 7 x64, i5 2.8 Ghz, HDD, не SSD ) это заняло ~ 15 секунд. Пускай это убогий и синтетический тест, но он все-таки дает определенное представление о производительности SQLite.

Продолжение следует.
Tags:
Hubs:
+32
Comments 34
Comments Comments 34

Articles