myDC.ru

Здравствуйте, гость ( Вход | Регистрация )

 
 
Ответить в данную темуНачать новую тему

> Мануал По Работе С Sqlite3

Теги
Нет тегов для показа
Setuper
сообщение 23.6.2008, 14:06
Сообщение #1


RusHub team lead
**************

Группа: Модераторы
Сообщений: 4 030
Регистрация: 20.6.2008
Из: г. Королёв (Моск. обл.)
Пользователь №: 46
Спасибо сказали: 1708 раз




Взаимодействие SQLite и Lua.


1. Подключение библиотеки PXSQLite3.dll

Существует несколько способов подключения, однако я рассмотрю один из этих способов.
Итак, для подключения библиотеки Прикрепленный файл  PXSQLite3.7z ( 174.07 килобайт ) Кол-во скачиваний: 102
(для PtokaX 0.4.*.*), прежде всего, помещаем эту библиотеку в рабочую папку PtokaX (в папку, где находится файл PtokaX.exe). После этого нам нужен файл Прикрепленный файл  sqlite3.lua ( 17.95 килобайт ) Кол-во скачиваний: 48
. Этот файл содержит основные таблицы и функции для вызова функций из библиотеки PXSQLite3.dll, а также в этом файле как раз таки идет подключение данной библиотеки:
Код
local init, error = package.loadlib("PXSQLite3", "luaopen_pxsqlite3")

Скопировав файл sqlite.lua приступим к написанию скрипта для работы с sqlite:

В папке scripts создаем файл test.lua и пишем код:
Код
require("путь_к_файлу_sqlite3.lua"..".sqlite3")

local db = sqlite3.open_memory() -- открываем "временную базу данных"

db:exec[[ -- выполнение sql запроса
    CREATE TABLE test (id INTEGER PRIMARY KEY, content); -- создание таблицы test с первичным ключом id типа integer и некой переменной content

    INSERT INTO test VALUES (NULL, 'Hello World'); -- вставка в таблицу test данных
    INSERT INTO test VALUES (NULL, 'Hello Lua');
    INSERT INTO test VALUES (NULL, 'Hello Sqlite3')
]]

for row in db:rows("SELECT * FROM test") do
    Core.SendToAll(row.id.." -> "..row.content)
end

db:close() -- закрытие базы данных.


2. Открытие и закрытие базы данных.

Код
db = sqlite3.open("filename") --открытие файла базы данных "filename" (обычно файл с расширением "*.db3" - database sqlite3)


Код
db = sqlite3.open_memory() --открытие временной базы данных в оперативной памяти


Код
db:close() --метод закрытия базы данных


3. Выполнение sql запросов

Код
db:exec( "Запрос в двойных кавычках" ) --однострочный запрос
db:exec[[ Запросы без кавычек ]] --многострочный запрос


4. Обработка запросов, связанных с SELECT.

Код
-- Возвращает row как индексированный, целочисленный массив
for row in db:irows("SELECT * FROM test") do
    Core.SendToAll(row[1].." - "..row[2])
end

-- Возвращает row как индексированный массив с индексами равными названиям столбцов таблицы
for row in db:rows("SELECT * FROM test") do
    Core.SendToAll(row.id.." - "..row.data)
end

-- Возвращает данные каждого столбца отдельно
for id, data in db:cols("SELECT * FROM test") do
    Core.SendToAll(id.." - "..data)
end


5. Обработка однострочных или одноколоночных запросов.

Код
row = db:first_irow("SELECT count(*) FROM test")
Core.SendToAll(row[1])

row = db:first_row("SELECT count(*) AS count FROM test")
Core.SendToAll(row.count)

count = db:first_cols("SELECT count(*) FROM test")
Core.SendToAll(count)


6. Выполнение предзапросов.
Если нам необходимо несколько раз использовать один и тот же запрос, мы можем получить этот запрос у базы данных единожды. Это оптимизирует работу с базой данных:

Код
local stmt = db:prepare("SELECT * FROM test")

for row in stmt:irows() do
    Core.SendToAll(row[1].." - "..row[2])
end

for row in stmt:rows() do
    Core.SendToAll(row.id.." - "..row.data)
end

for id, data in stmt:cols() do
    Core.SendToAll(id.." - "..data)
end


Хочу заметить, что на самом деле та же самая функция db:rows(query) выполняется через предзапрос db:prepare(query):rows().


Также, используя данную конструкцию предзапросов, можно осуществлять проверку на правильность запроса.

Пример:
Код
function CheckSql(sRequest)
  return db:prepare(sRequest) and true
end

Функция возвращает true в случае правильности запроса и nil в противном случае.

7. Использование анонимных параметров.
Функция stmt:bind(параметры) устанавливает анонимные параметры (? - обозначение анонимного параметра).

Код
local stmt = db:prepare[[
    INSERT INTO test VALUES (?, ?);
    INSERT INTO test VALUES (?, ?)
]]

function insert(id1, data1, id2, data2)
    stmt:bind(id1, data1, id2, data2)
    stmt:exec()
end

insert(1, "Hello World",   2, "Hello Lua")
insert(3, "Hello Sqlite3", 4, "Hello User")

stmt = db:prepare("SELECT data FROM test WHERE test.id = ?")

function get_data(id)
    stmt:bind(id)
    return stmt:first_cols()
end

Core.SendToAll(get_data(1))
Core.SendToAll(get_data(2))
Core.SendToAll(get_data(3))
Core.SendToAll(get_data(4))


8. Именованные параметры.

Код
db:exec("CREATE TABLE person_name (id, name)")
db:exec("CREATE TABLE person_email (id, email)")
db:exec("CREATE TABLE person_address (id, address)")

-- метка-заполнители '$' и ':' не в sql утверждениях выставляются или не выставляются по желанию программиста
local parameter_names = {":id", "$name", "address", "email"}

-- в sql утверждениях выставлять метка-заполнители необходимо обязательно!
local stmt = db:prepare(parameter_names, [[
    INSERT INTO person_name VALUES (:id, :name);
    INSERT INTO person_email VALUES (:id, :email);
    INSERT INTO person_address VALUES (:id, :address);
]])

function insert(id, name, address, email)
    stmt:bind(id, name, address, email)
    stmt:exec()
end

insert(1, "Michael", "Germany", "mroth@nessie.de")
insert(2, "John",    "USA",     "john@usa.org")
insert(3, "Hans",    "France",  "hans@france.com")


9. Автоматические именованные параметры.

Код
local stmt = db:prepare[[
    INSERT INTO person_name VALUES (:id, :name);
    INSERT INTO person_email VALUES (:id, :email);
    INSERT INTO person_address VALUES (:id, :address);
]]

function insert(id, name, address, email)
    stmt:bind(id, name, email, address)
    stmt:exec()
end


Параметры передаются последовательно. При повторном появлении параметра, он заменяется на такое же значение, что и предыдущий.

10. Параметры, передаваемые по средствам таблиц или метатаблиц.

Код
stmt = db:prepare[[
    INSERT INTO person_name VALUES (:id, :name);
    INSERT INTO person_email VALUES (:id, :email);
    INSERT INTO person_address VALUES (:id, :address);
]]

--первый способ
function insert(id, name, address, email)
    args = {}
    args.id = id
    args.name = name
    args.address = address
    args.email = args.email
    stmt:bind(args)
    stmt:exec()
end

--второй способ (упрощенный)
function insert2(id, name, address, email)
    stmt:bind{id=id, name=name, address=address, email=email}
    stmt:exec()
end


11. Запрос всех параметров.

Код
local stmt = db:prepare[[
    BEGIN TRANSACTION;
        INSERT INTO person_name VALUES (:id, :name);
        INSERT INTO person_email VALUES (:id, :email);
        INSERT INTO person_address VALUES (:id, :address);
    COMMIT
]]

local names = stmt:parameter_names()  -- занесение всех параметров в таблицу names

Core.SendToAll(table.getn(names))      -- "4"
Core.SendToAll(names[1])               -- "id"
Core.SendToAll(names[2])               -- "name"
Core.SendToAll(names[3])               -- "email"
Core.SendToAll(names[4])               -- "address"

Параметры упорядочиваются по мере их введения.

12. Функции, определяемые пользователем.

В SQLite3 вы можете определить свои собственные функции. Функцию написанную на Lua можно будет использовать в синтаксисе sql.
Код
function sql_add_ten(a)
    return a + 10
end

db:set_function("add_ten", 1, sql_add_ten) --lua функции sql_add_ten мы даем в sql имя: add_ten (1 - число аргументов)

for id, add_ten, data in db:cols("SELECT id, add_ten(id), data FROM test") do
    Core.SendToAll(id.." - "..add_ten.." - "..data)
end


13. Определение функции с произвольным числом аргументов.

Код
db:set_function("my_max", -1, math.max) -- (-1 - обозначение произвольного числа аргументов)

local max1 = db:first_cols("SELECT my_max(17, 7)")
local max2 = db:first_cols("SELECT my_max(1, 2, 3, 4, 5)")

Core.SendToAll(max1..", "..max2)       -- 17, 5


14. Задержка в выполнении sql кода.

Код
-- Открываем базу данных
db = sqlite3.open("filename")

-- параметр - время (в милисекундах), после которого функция, ожидающая ответ на запрос, сообщит что он не был выполнен
db:set_busy_timeout(2 * 1000)

-- Выполнение sql кода
db:exec(...)


15. Установка обработчика.
Можно установить обработчика, который бы выполнял некий код в то время когда база данных занята.
Обработчик возвращает значения, если SQL пытается продолжить начатую трансакцию и трансакция была прервана с ошибкой.
Возвращается 0, false или nil для прерыания трансакции и некое значение для повторного обращения к базе данных.

Код
-- Открываем базу данных
db = sqlite3.open("filename")

-- Делаем 10 попыток обратиться к "занятой" (или недоступной) базе данных
function my_busy_handler(attempts_made)
    if attempts_made < 10 then
        return true
    else
        return false
    end
end

-- Установка обработчика
db:set_busy_handler(my_busy_handler)

-- Выполнение sql кода
db:exec(...)


16. Трассирующий обработчик.
Трассирующий обработчик нужен для отслеживания выполнения sql кода.
Выполняется каждый раз, когда выполняется функция db:exec() или db:prepare(). Обработчик получает один аргумент со строкой, которая была откомпилированна.
Код
function mytrace(sql_string)
    Core.SendToAll("Sqlite3:"..sql_string)
end

db:set_trace_handler(mytrace)


Синтаксис SQLite

Полезные линки.

Официальный сайт SQLite
SQLite по-русски
Русская страница
SQLite Database Browser - визуальное средство администрирования SQLite
SQLite Administrator - средство администрирования и редактор SQL-запросов в SQLite
Go to the top of the page
+Quote Post
Setuper
сообщение 27.8.2008, 11:03
Сообщение #2


RusHub team lead
**************

Группа: Модераторы
Сообщений: 4 030
Регистрация: 20.6.2008
Из: г. Королёв (Моск. обл.)
Пользователь №: 46
Спасибо сказали: 1708 раз




Полезные функции sqlite:
Код
--функция проверяет правильность запроса
function CheckSql(sRequest)
  return db:prepare(sRequest) and true
end

--функция возвращает не пустую таблицу после запроса типа SELECT
function DoSelect(request)
    local t,stmt={},db:prepare(request)
    if stmt and stmt:rows() then
        for row in stmt:rows() do
            table.insert(t,row)
        end
        if next(t) then return t end
    end
end

--функция проверяет правильность и выполнимость запроса SELECT
function CheckSelect(request)
    local stmt=db:prepare(request)
    if stmt and stmt:first_row() then return true end
end

--функция возвращает однострочный запрос как таблицу
function DoFirstSelect(request)
    local stmt=db:prepare(request)
    if stmt and stmt:first_row() then
        return stmt:first_row()
    end
end

--функция выполняет любой запрос sqlite
function DoSql(request)
    local stmt=db:prepare(request)
    if stmt then
        stmt:exec()
        return true
    end
end
Go to the top of the page
+Quote Post
Nickolya
сообщение 10.10.2008, 21:40
Сообщение #3


Главный ра******й тут...
*********

Группа: Главные администраторы
Сообщений: 1 727
Регистрация: 18.5.2008
Из: RF, 2la
Пользователь №: 1
Спасибо сказали: 776 раз




Немного подняли шума на форуме птоки, уже становится понятнее почему что как, кому интересно - сюда.
Go to the top of the page
+Quote Post
Wariner
сообщение 10.10.2008, 22:27
Сообщение #4


Самый главный активист :-D
***********

Группа: Модераторы
Сообщений: 2 790
Регистрация: 29.6.2008
Из: г. Тула
Пользователь №: 97
Спасибо сказали: 440 раз




Колюх, а можешь рассказать в двух словах что тебе отвечали?( твои сообщения я практически понял ибо не такой сложный англ still_dreaming.gif )
Go to the top of the page
+Quote Post
Nickolya
сообщение 11.10.2008, 0:05
Сообщение #5


Главный ра******й тут...
*********

Группа: Главные администраторы
Сообщений: 1 727
Регистрация: 18.5.2008
Из: RF, 2la
Пользователь №: 1
Спасибо сказали: 776 раз




Вот в 2 словах, основные моменты переводил полностью, но лучше читайте исходную переписку, мало ли чего я не так перевел или недописал big_smile.gif

> Setuper: Я не могу создать больше 1 таблицы в этом скрипте!
> Я: да, такая же ***ня и у меня
> Я: вопрос еще актуален, может кто что сделать?
> какой-то zigzagkms: мне нужна либа для MySQL
> ATAG: всё работает на nix'е
> Я: да, там всё нормально, но на винде не пашет, такие-то и такие-то проблемы. И еще, почему птока не использует стандартныую библиотеку lua.dll, с ней бы мы могли использовать все расширения без изменений?
> Snooze: пользуйте таблицы, они работают быстрее
> PPK: нет стандартной lua.dll, луа растпространяется как исходный текст, все распространемые библиотеки не являются стандартными. Самая популярная - на луафордже, но она не может использоваться для птоки по многим причинам (меняются имена библиотек, не совместимы с 32-битным копилятором птоки, плохие настройки компилятора для 64-битной версии, что делает невозможным использование с 64-битной птокой...)
Еще причина почему изменено - в pxlua изменено управление памятью и исправлены некоторые баги (для примера, креш при делении на 0)
> Я: спасибо за объяснения, можешь объяснить как компилировать либы на 2 апи, с 1 вроде всё нормально, а именно момент с "name mangling".
> PPK (издевается, цк): апи птоки ничего не делает с библиотеками. _ было в начале функций т.к. они использовали "C calling convention", и это было изменено когда CrazyGuy сообщил что pxlua быстрее пашет с "fastcall calling convention" (using cpu registers for passing function parameters и на тестовом скрипте показала на 33% меньше времени цпу для завершения).
Вы можете использовать любой мой исходник чтобы посмотреть как компилировать библиотеки, 1 штуку вам надо поменять, и это "calling convention" в настройках компилятора.
Go to the top of the page
+Quote Post
Wariner
сообщение 13.10.2008, 16:04
Сообщение #6


Самый главный активист :-D
***********

Группа: Модераторы
Сообщений: 2 790
Регистрация: 29.6.2008
Из: г. Тула
Пользователь №: 97
Спасибо сказали: 440 раз




2Setuper: установил по твоему описанию Borland С++ Builder 6 но по посту выше следует поменять в опции calling convention параметр c C на fastcall, а там такого нет! Есть С, Pascal, Regicter(J) и Standard call. Это в этой версии нет такой опции или я что то не понял?
Go to the top of the page
+Quote Post
Setuper
сообщение 13.10.2008, 16:35
Сообщение #7


RusHub team lead
**************

Группа: Модераторы
Сообщений: 4 030
Регистрация: 20.6.2008
Из: г. Королёв (Моск. обл.)
Пользователь №: 46
Спасибо сказали: 1708 раз




2Wariner: Выше описана настройка компилятора для компиляции dll библиотеки для sqlite!

Опять же выше я полагаю описана настройка компилятора vs, потому как существуют исходники под vs)))))

Исходники с моими описаниями прилагаю (7zip файл), может найдутся знатоки программирования dll библиотек)))))
Прикрепленные файлы
Прикрепленный файл  SQLite.7z ( 1.63 мегабайт ) Кол-во скачиваний: 34
 
Go to the top of the page
+Quote Post
Wariner
сообщение 26.2.2009, 14:04
Сообщение #8


Самый главный активист :-D
***********

Группа: Модераторы
Сообщений: 2 790
Регистрация: 29.6.2008
Из: г. Тула
Пользователь №: 97
Спасибо сказали: 440 раз




хм а почему не работает код:
Код
    db = sqlite3.open(Core.GetPtokaXPath().."scripts/Protector/Logs/MainChat.db3")

т.е. не работает часть отвечающая за универсальность((((

+ как проверить наличие таблицы в бд? использовать проверку на правильность запроса?
Go to the top of the page
+Quote Post
Setuper
сообщение 26.2.2009, 14:30
Сообщение #9


RusHub team lead
**************

Группа: Модераторы
Сообщений: 4 030
Регистрация: 20.6.2008
Из: г. Королёв (Моск. обл.)
Пользователь №: 46
Спасибо сказали: 1708 раз




Всё работает! Проверку на существование таблицы делать не нужно, так как запрос CREATE TABLE будет выполняться только в случае отсутствия таблицы, не вызывая при этом ошибок.
Вот простейший пример по всем твоим вопросам:
Код
require"sqlite3"

local db = sqlite3.open(Core.GetPtokaXPath().."scripts/test.db3")

db:exec[[
  CREATE TABLE test (id INTEGER PRIMARY KEY, content);
  CREATE TABLE test1 (id INTEGER PRIMARY KEY, content);

  INSERT INTO test VALUES (NULL, 'Hello World');
  INSERT INTO test VALUES (NULL, 'Hello Lua');
  INSERT INTO test VALUES (NULL, 'Hello Sqlite3')
]]

function OnStartup()
  local t = DoSelect("SELECT * FROM test")
  for i,v in pairs(t) do
    for j,w in pairs(v) do
      Core.SendToAll(i.." - "..j.." - "..tostring(w))
    end
  end
end

function OnExit()
  db:close()
end

Функции для обработки запросов (в частности DoSelect) я выкладывал: http://mydc.ru/ipb.html?s=&showtopic=7...post&p=1995 Невнимательно просматриваешь тему!
Go to the top of the page
+Quote Post
Wariner
сообщение 26.2.2009, 14:51
Сообщение #10


Самый главный активист :-D
***********

Группа: Модераторы
Сообщений: 2 790
Регистрация: 29.6.2008
Из: г. Тула
Пользователь №: 97
Спасибо сказали: 440 раз




хм дело оказалось в путях. Толи из за того что присутствовали русские названия, толи слишком длинные и с пробелами.....


+ какие символы нельзя использовать в названии таблиц? не нашёл об этом инфы. Тестовым методом определил что нельзя только из цифр нельзя точки и тд
Go to the top of the page
+Quote Post
Setuper
сообщение 26.2.2009, 15:06
Сообщение #11


RusHub team lead
**************

Группа: Модераторы
Сообщений: 4 030
Регистрация: 20.6.2008
Из: г. Королёв (Моск. обл.)
Пользователь №: 46
Спасибо сказали: 1708 раз




Вообще говоря в sqlite можно писать так:
Код
CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, content);
однако данная конструкция не поддерживается в скомпилированной библиотеке (возможно из-за старой версии). Однако эта конструкция выполняется по умолчанию, хотя по синтаксису sqlite не должна выполняться по умолчанию, но тем лучше (не надо постоянно писать эти слова IF NOT EXISTS).

Правило формирования имени таблице такое же как и для любого ключевого слова в языке lua. Имя может состоять из комбинации букв, цифр и знака нижнего подчёркивания, при этом имя не должно начинять с цифры или с фразы sqlite_ - эта фраза зарезервирована под глобальные таблицы sqlite.

Возможно чуть позже я размещу тут на форуме подробный синтаксис команд sqlite, по причине того, что синтаксис на русском языке стал недоступен, из-за удаления его с одного из сайтов, ссылку на который я приводил выше.
Go to the top of the page
+Quote Post
Setuper
сообщение 6.3.2009, 23:14
Сообщение #12


RusHub team lead
**************

Группа: Модераторы
Сообщений: 4 030
Регистрация: 20.6.2008
Из: г. Королёв (Моск. обл.)
Пользователь №: 46
Спасибо сказали: 1708 раз




В соответствии с lua 5.1 поправлен метод bind в файле sqlite3.lua

Прикрепленный файл  sqlite3.lua ( 17.95 килобайт ) Кол-во скачиваний: 15
Go to the top of the page
+Quote Post
Wariner
сообщение 6.3.2009, 23:20
Сообщение #13


Самый главный активист :-D
***********

Группа: Модераторы
Сообщений: 2 790
Регистрация: 29.6.2008
Из: г. Тула
Пользователь №: 97
Спасибо сказали: 440 раз




а по русски shame.gif
что это дало?
Go to the top of the page
+Quote Post
Setuper
сообщение 6.3.2009, 23:40
Сообщение #14


RusHub team lead
**************

Группа: Модераторы
Сообщений: 4 030
Регистрация: 20.6.2008
Из: г. Королёв (Моск. обл.)
Пользователь №: 46
Спасибо сказали: 1708 раз




Это дало выполнимость пунктов с 7 по 10 в мануале (в начале этой темы). До этого эти пунткы на работали на языке lua 5.1.
Работа проверяется опытным путём (по приведённым примерам).

Это связано с изменением принципа извлечения переменного числа параметров http://www.lua.ru/doc/7.1.html
Go to the top of the page
+Quote Post

Ответить в данную темуНачать новую тему
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

Collapse

> Похожие темы

  Тема Ответов Автор Просмотров Последнее сообщение
No New Posts Topic has attachmentssqlite3
win32 | База данных
3 Setuper 11 416 2.6.2014, 15:19 Посл. сообщение: Alexey
No New Posts Topic has attachmentssqlite3
RusHub | Библиотека базы данных sqlite
1 Setuper 10 354 22.9.2012, 17:52 Посл. сообщение: Alexey
No New Posts Topic has attachmentsВопрос о работе PtokaX с разными диапазонами IP в локалке
10 Sasha_bc 14 878 13.2.2010, 22:24 Посл. сообщение: Sasha_bc
No New Posts От: Мануал По Работе С Sqlite3
От темы с ID: 70
9 Nickolya 13 882 10.10.2008, 20:48 Посл. сообщение: Setuper

 



RSS Сейчас: 27.11.2024, 3:54