Initial support/tests for SQLite flags and db dump
This commit adds a pass through for specifying SQLite3 flags. This is an absolute requirement for being able to create in-memory DB representations.
This commit is contained in:
parent
67ef13caed
commit
fa220a1c4c
|
@ -8,6 +8,12 @@ ensure
|
||||||
File.delete(DB_FILENAME)
|
File.delete(DB_FILENAME)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private def with_db(name)
|
||||||
|
yield Database.new name
|
||||||
|
ensure
|
||||||
|
File.delete(name)
|
||||||
|
end
|
||||||
|
|
||||||
describe Database do
|
describe Database do
|
||||||
it "opens a database" do
|
it "opens a database" do
|
||||||
with_db do |db|
|
with_db do |db|
|
||||||
|
@ -15,6 +21,41 @@ describe Database do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "opens a database and then backs it up to another db" do
|
||||||
|
with_db do |db|
|
||||||
|
db.execute "create table person (name string, age integer)"
|
||||||
|
db.execute "insert into person values (\"foo\", 10)"
|
||||||
|
with_db("./test2.db") do |backup_database|
|
||||||
|
db.dump(backup_database)
|
||||||
|
|
||||||
|
backup_rows = backup_database.execute "select * from person"
|
||||||
|
source_rows = db.execute "select * from person"
|
||||||
|
backup_rows.should eq(source_rows)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "opens a database, inserts records, dumps to an in-memory db, insers some more, then dumps to the source" do
|
||||||
|
with_db do |db|
|
||||||
|
db.execute "create table person (name string, age integer)"
|
||||||
|
db.execute "insert into person values (\"foo\", 10)"
|
||||||
|
in_memory_db = Database.new("file:memdb1?mode=memory&cache=shared",
|
||||||
|
LibSQLite3::Flag::URI | LibSQLite3::Flag::CREATE | LibSQLite3::Flag::READWRITE |
|
||||||
|
LibSQLite3::Flag::FULLMUTEX)
|
||||||
|
source_rows = db.execute "select * from person"
|
||||||
|
|
||||||
|
db.dump(in_memory_db)
|
||||||
|
in_memory_db_rows = in_memory_db.execute "select * from person"
|
||||||
|
in_memory_db_rows.should eq(source_rows)
|
||||||
|
in_memory_db.execute "insert into person values (\"bar\", 22)"
|
||||||
|
in_memory_db.dump(db)
|
||||||
|
|
||||||
|
in_memory_db_rows = in_memory_db.execute "select * from person"
|
||||||
|
source_rows = db.execute "select * from person"
|
||||||
|
in_memory_db_rows.should eq(source_rows)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
[nil, 1, 1_i64, "hello", 1.5, 1.5_f32].each do |value|
|
[nil, 1, 1_i64, "hello", 1.5, 1.5_f32].each do |value|
|
||||||
it "executes and select #{value}" do
|
it "executes and select #{value}" do
|
||||||
with_db(&.execute("select #{value ? value.inspect : "null"}")).should eq([[value]])
|
with_db(&.execute("select #{value ? value.inspect : "null"}")).should eq([[value]])
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# ```
|
# ```
|
||||||
# require "sqlite3"
|
# require "sqlite3"
|
||||||
#
|
#
|
||||||
# db = SQLite3::Database.new( "data.db" )
|
# db = SQLite3::Database.new("data.db")
|
||||||
# db.execute("select * from table") do |row|
|
# db.execute("select * from table") do |row|
|
||||||
# p row
|
# p row
|
||||||
# end
|
# end
|
||||||
|
@ -21,6 +21,16 @@ class SQLite3::Database
|
||||||
@closed = false
|
@closed = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Allows for initialization with specific flags. Primary use case is to allow
|
||||||
|
# for sqlite3 URI opening and in memory DB operations.
|
||||||
|
def initialize(filename, flags : LibSQLite3::Flag)
|
||||||
|
code = LibSQLite3.open_v2(filename, out @db, flags, nil)
|
||||||
|
if code != 0
|
||||||
|
raise Exception.new(@db)
|
||||||
|
end
|
||||||
|
@closed = false
|
||||||
|
end
|
||||||
|
|
||||||
# Creates a new Database object that opens the given file, yields it, and closes it at the end.
|
# Creates a new Database object that opens the given file, yields it, and closes it at the end.
|
||||||
def self.new(filename)
|
def self.new(filename)
|
||||||
db = new filename
|
db = new filename
|
||||||
|
@ -31,6 +41,37 @@ class SQLite3::Database
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Dump the database to another SQLite3 instance. This can be used for backing up a SQLite3::Database
|
||||||
|
# to disk or the opposite
|
||||||
|
# Example:
|
||||||
|
# ```
|
||||||
|
# source_database = SQLite3::Database.new("mydatabase.db")
|
||||||
|
# in_memory_db = SQLite3::Database.new(
|
||||||
|
# "file:memdb1?mode=memory&cache=shared",
|
||||||
|
# LibSQLite3::Flag::URI | LibSQLite3::Flag::CREATE | LibSQLite3::Flag::READWRITE |
|
||||||
|
# LibSQLite3::Flag::FULLMUTEX)
|
||||||
|
# source_database.dump(in_memory_db)
|
||||||
|
# source_database.close()
|
||||||
|
# in_memory_db.exectute { |row|
|
||||||
|
# ...
|
||||||
|
# }
|
||||||
|
# ```
|
||||||
|
def dump(to : SQLite3::Database)
|
||||||
|
backup_item = LibSQLite3.backup_init(to.@db, "main", @db, "main")
|
||||||
|
if backup_item.nil?
|
||||||
|
raise Exception.new(to.@db)
|
||||||
|
end
|
||||||
|
code = LibSQLite3.backup_step(backup_item, -1)
|
||||||
|
|
||||||
|
if code != LibSQLite3::Code::DONE
|
||||||
|
raise Exception.new(to.@db)
|
||||||
|
end
|
||||||
|
code = LibSQLite3.backup_finish(backup_item)
|
||||||
|
if code != LibSQLite3::Code::OKAY
|
||||||
|
raise Exception.new(to.@db)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Executes the given SQL statement. If additional parameters are given, they are treated as bind variables,
|
# Executes the given SQL statement. If additional parameters are given, they are treated as bind variables,
|
||||||
# and are bound to the placeholders in the query.
|
# and are bound to the placeholders in the query.
|
||||||
#
|
#
|
||||||
|
|
|
@ -4,6 +4,7 @@ require "./type"
|
||||||
lib LibSQLite3
|
lib LibSQLite3
|
||||||
type SQLite3 = Void*
|
type SQLite3 = Void*
|
||||||
type Statement = Void*
|
type Statement = Void*
|
||||||
|
type SQLite3Backup = Void*
|
||||||
|
|
||||||
enum Flag
|
enum Flag
|
||||||
READONLY = 0x00000001 # Ok for sqlite3_open_v2()
|
READONLY = 0x00000001 # Ok for sqlite3_open_v2()
|
||||||
|
@ -29,6 +30,7 @@ lib LibSQLite3
|
||||||
end
|
end
|
||||||
|
|
||||||
enum Code
|
enum Code
|
||||||
|
OKAY = 0
|
||||||
ROW = 100
|
ROW = 100
|
||||||
DONE = 101
|
DONE = 101
|
||||||
end
|
end
|
||||||
|
@ -41,6 +43,10 @@ lib LibSQLite3
|
||||||
fun errcode = sqlite3_errcode(SQLite3) : Int32
|
fun errcode = sqlite3_errcode(SQLite3) : Int32
|
||||||
fun errmsg = sqlite3_errmsg(SQLite3) : UInt8*
|
fun errmsg = sqlite3_errmsg(SQLite3) : UInt8*
|
||||||
|
|
||||||
|
fun backup_init = sqlite3_backup_init(SQLite3, UInt8*, SQLite3, UInt8*) : SQLite3Backup
|
||||||
|
fun backup_step = sqlite3_backup_step(SQLite3Backup, Int8): Code
|
||||||
|
fun backup_finish = sqlite3_backup_finish(SQLite3Backup): Code
|
||||||
|
|
||||||
fun prepare_v2 = sqlite3_prepare_v2(db : SQLite3, zSql : UInt8*, nByte : Int32, ppStmt : Statement*, pzTail : UInt8**) : Int32
|
fun prepare_v2 = sqlite3_prepare_v2(db : SQLite3, zSql : UInt8*, nByte : Int32, ppStmt : Statement*, pzTail : UInt8**) : Int32
|
||||||
fun step = sqlite3_step(stmt : Statement) : Int32
|
fun step = sqlite3_step(stmt : Statement) : Int32
|
||||||
fun column_count = sqlite3_column_count(stmt : Statement) : Int32
|
fun column_count = sqlite3_column_count(stmt : Statement) : Int32
|
||||||
|
|
Loading…
Reference in New Issue