|
Здравствуйте, гость ( Вход | Регистрация )
![]() ![]() |
|
![]() ![]()
Сообщение
#1
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
Взаимодействие SQLite и Lua.
1. Подключение библиотеки PXSQLite3.dll Существует несколько способов подключения, однако я рассмотрю один из этих способов. Итак, для подключения библиотеки ![]() (для PtokaX 0.4.*.*), прежде всего, помещаем эту библиотеку в рабочую папку PtokaX (в папку, где находится файл PtokaX.exe). После этого нам нужен файл ![]() . Этот файл содержит основные таблицы и функции для вызова функций из библиотеки 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) Полезные линки. |
|
|
![]()
Сообщение
#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 |
|
|
![]()
Сообщение
#3
|
|
![]() Главный ра******й тут... ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Главные администраторы Сообщений: 1 727 Регистрация: 18.5.2008 Из: RF, 2la Пользователь №: 1 Спасибо сказали: 776 раз ![]() |
Немного подняли шума на форуме птоки, уже становится понятнее почему что как, кому интересно -
|
|
|
![]()
Сообщение
#4
|
|
![]() Самый главный активист :-D ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 2 790 Регистрация: 29.6.2008 Из: г. Тула Пользователь №: 97 Спасибо сказали: 440 раз ![]() |
Колюх, а можешь рассказать в двух словах что тебе отвечали?( твои сообщения я практически понял ибо не такой сложный англ
![]() |
|
|
![]()
Сообщение
#5
|
|
![]() Главный ра******й тут... ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Главные администраторы Сообщений: 1 727 Регистрация: 18.5.2008 Из: RF, 2la Пользователь №: 1 Спасибо сказали: 776 раз ![]() |
Вот в 2 словах, основные моменты переводил полностью, но лучше читайте исходную переписку, мало ли чего я не так перевел или недописал
![]() > 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" в настройках компилятора. |
|
|
![]()
Сообщение
#6
|
|
![]() Самый главный активист :-D ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 2 790 Регистрация: 29.6.2008 Из: г. Тула Пользователь №: 97 Спасибо сказали: 440 раз ![]() |
2Setuper: установил по твоему описанию Borland С++ Builder 6 но по посту выше следует поменять в опции calling convention параметр c C на fastcall, а там такого нет! Есть С, Pascal, Regicter(J) и Standard call. Это в этой версии нет такой опции или я что то не понял?
|
|
|
![]() ![]()
Сообщение
#7
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
2Wariner: Выше описана настройка компилятора для компиляции dll библиотеки для sqlite!
Опять же выше я полагаю описана настройка компилятора vs, потому как существуют исходники под vs))))) Исходники с моими описаниями прилагаю (7zip файл), может найдутся знатоки программирования dll библиотек)))))
Прикрепленные файлы
|
|
|
![]()
Сообщение
#8
|
|
![]() Самый главный активист :-D ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 2 790 Регистрация: 29.6.2008 Из: г. Тула Пользователь №: 97 Спасибо сказали: 440 раз ![]() |
хм а почему не работает код:
Код db = sqlite3.open(Core.GetPtokaXPath().."scripts/Protector/Logs/MainChat.db3") т.е. не работает часть отвечающая за универсальность(((( + как проверить наличие таблицы в бд? использовать проверку на правильность запроса? |
|
|
![]()
Сообщение
#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 Невнимательно просматриваешь тему! |
|
|
![]()
Сообщение
#10
|
|
![]() Самый главный активист :-D ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 2 790 Регистрация: 29.6.2008 Из: г. Тула Пользователь №: 97 Спасибо сказали: 440 раз ![]() |
хм дело оказалось в путях. Толи из за того что присутствовали русские названия, толи слишком длинные и с пробелами.....
+ какие символы нельзя использовать в названии таблиц? не нашёл об этом инфы. Тестовым методом определил что нельзя только из цифр нельзя точки и тд |
|
|
![]()
Сообщение
#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, по причине того, что синтаксис на русском языке стал недоступен, из-за удаления его с одного из сайтов, ссылку на который я приводил выше. |
|
|
![]()
Сообщение
#12
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
В соответствии с lua 5.1 поправлен метод bind в файле sqlite3.lua
![]() |
|
|
![]()
Сообщение
#13
|
|
![]() Самый главный активист :-D ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 2 790 Регистрация: 29.6.2008 Из: г. Тула Пользователь №: 97 Спасибо сказали: 440 раз ![]() |
а по русски
![]() что это дало? |
|
|
![]()
Сообщение
#14
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
Это дало выполнимость пунктов с 7 по 10 в мануале (в начале этой темы). До этого эти пунткы на работали на языке lua 5.1.
Работа проверяется опытным путём (по приведённым примерам). Это связано с изменением принципа извлечения переменного числа параметров |
|
|
![]() ![]() |
Похожие темы
Тема | Ответов | Автор | Просмотров | Последнее сообщение | |
---|---|---|---|---|---|
![]() |
![]() win32 | База данных |
3 | Setuper | 11 269 | 2.6.2014, 15:19 Посл. сообщение: Alexey |
![]() |
![]() RusHub | Библиотека базы данных sqlite |
1 | Setuper | 10 245 | 22.9.2012, 17:52 Посл. сообщение: Alexey |
![]() |
![]() |
10 | Sasha_bc | 14 584 | 13.2.2010, 22:24 Посл. сообщение: Sasha_bc |
![]() |
От: Мануал По Работе С Sqlite3 От темы с ID: 70 |
9 | Nickolya | 13 621 | 10.10.2008, 20:48 Посл. сообщение: Setuper |
![]() |
Сейчас: 8.9.2024, 2:54 |