sqlite3 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +2 -2
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/sqlite3.rb +3 -0
- data/lib/sqlite3/api.rb +52 -0
- data/lib/sqlite3/database.rb +2 -30
- data/lib/sqlite3/driver.rb +134 -0
- data/lib/sqlite3/extensions.rb +27 -0
- data/sqlite3.gemspec +89 -0
- data/test/helper.rb +3 -1
- data/test/test_active_record.rb +13 -4
- data/test/test_statement.rb +42 -0
- metadata +9 -5
- data/lib/sqlite3/driver/ffi/api.rb +0 -47
- data/lib/sqlite3/driver/ffi/driver.rb +0 -128
data/README.rdoc
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
Description goes here.
|
4
4
|
|
5
5
|
== Note on Patches/Pull Requests
|
6
|
-
|
6
|
+
|
7
7
|
* Fork the project.
|
8
8
|
* Make your feature addition or bug fix.
|
9
9
|
* Add tests for it. This is important so I don't break it in a
|
@@ -15,4 +15,4 @@ Description goes here.
|
|
15
15
|
|
16
16
|
== Copyright
|
17
17
|
|
18
|
-
Copyright (c)
|
18
|
+
Copyright (c) 2010 Jakub Kuźma. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -12,7 +12,7 @@ begin
|
|
12
12
|
gem.email = "qoobaa@gmail.com"
|
13
13
|
gem.homepage = "http://github.com/qoobaa/sqlite3"
|
14
14
|
gem.authors = ["Jakub Kuźma"]
|
15
|
-
gem.add_dependency "ffi", ">= 0.
|
15
|
+
gem.add_dependency "ffi", ">= 0.6.0"
|
16
16
|
gem.add_development_dependency "test-unit", ">= 2.0"
|
17
17
|
gem.add_development_dependency "activerecord", ">= 2.3.5"
|
18
18
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.8
|
data/lib/sqlite3.rb
CHANGED
data/lib/sqlite3/api.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module SQLite3
|
2
|
+
module API
|
3
|
+
extend FFI::Library
|
4
|
+
|
5
|
+
lib_paths = Array(ENV["SQLITE3_LIB"] || Dir["/{opt,usr}/{,local/}lib{,64}/libsqlite3.{dylib,so*}"])
|
6
|
+
fallback_names = ["libsqlite3", "sqlite3"]
|
7
|
+
ffi_lib(lib_paths + fallback_names)
|
8
|
+
|
9
|
+
attach_function :sqlite3_bind_blob, [:pointer, :int, :pointer, :int, :pointer], :int
|
10
|
+
attach_function :sqlite3_bind_double, [:pointer, :int, :double], :int
|
11
|
+
attach_function :sqlite3_bind_int, [:pointer, :int, :int], :int
|
12
|
+
attach_function :sqlite3_bind_int64, [:pointer, :int, :int64], :int
|
13
|
+
attach_function :sqlite3_bind_null, [:pointer, :int], :int
|
14
|
+
attach_function :sqlite3_bind_parameter_index, [:pointer, :string], :int
|
15
|
+
attach_function :sqlite3_bind_text, [:pointer, :int, :string, :int, :pointer], :int
|
16
|
+
attach_function :sqlite3_bind_text16, [:pointer, :int, :pointer, :int, :pointer], :int
|
17
|
+
attach_function :sqlite3_busy_timeout, [:pointer, :int], :int
|
18
|
+
attach_function :sqlite3_changes, [:pointer], :int
|
19
|
+
attach_function :sqlite3_close, [:pointer], :int
|
20
|
+
attach_function :sqlite3_column_blob, [:pointer, :int], :pointer
|
21
|
+
attach_function :sqlite3_column_bytes, [:pointer, :int], :int
|
22
|
+
attach_function :sqlite3_column_bytes16, [:pointer, :int], :int
|
23
|
+
attach_function :sqlite3_column_count, [:pointer], :int
|
24
|
+
attach_function :sqlite3_column_decltype, [:pointer, :int], :string
|
25
|
+
attach_function :sqlite3_column_double, [:pointer, :int], :double
|
26
|
+
attach_function :sqlite3_column_int64, [:pointer, :int], :int64
|
27
|
+
attach_function :sqlite3_column_name, [:pointer, :int], :string
|
28
|
+
attach_function :sqlite3_column_text, [:pointer, :int], :string
|
29
|
+
attach_function :sqlite3_column_text16, [:pointer, :int], :pointer
|
30
|
+
attach_function :sqlite3_column_type, [:pointer, :int], :int
|
31
|
+
attach_function :sqlite3_data_count, [:pointer], :int
|
32
|
+
attach_function :sqlite3_errcode, [:pointer], :int
|
33
|
+
attach_function :sqlite3_errmsg, [:pointer], :string
|
34
|
+
attach_function :sqlite3_errmsg16, [:pointer], :pointer
|
35
|
+
attach_function :sqlite3_finalize, [:pointer], :int
|
36
|
+
attach_function :sqlite3_last_insert_rowid, [:pointer], :int64
|
37
|
+
attach_function :sqlite3_libversion, [], :string
|
38
|
+
attach_function :sqlite3_open, [:string, :pointer], :int
|
39
|
+
attach_function :sqlite3_open16, [:pointer, :pointer], :int
|
40
|
+
attach_function :sqlite3_prepare, [:pointer, :string, :int, :pointer, :pointer], :int
|
41
|
+
attach_function :sqlite3_reset, [:pointer], :int
|
42
|
+
attach_function :sqlite3_step, [:pointer], :int
|
43
|
+
|
44
|
+
begin
|
45
|
+
attach_function :sqlite3_enable_load_extension, [:pointer, :int], :int
|
46
|
+
attach_function :sqlite3_load_extension, [:pointer, :string, :string, :string], :int
|
47
|
+
EXTENSION_SUPPORT = true
|
48
|
+
rescue FFI::NotFoundError
|
49
|
+
EXTENSION_SUPPORT = false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/sqlite3/database.rb
CHANGED
@@ -29,6 +29,7 @@ module SQLite3
|
|
29
29
|
# hashes, then the results will all be indexible by field name.
|
30
30
|
class Database
|
31
31
|
include Pragmas
|
32
|
+
include Extensions
|
32
33
|
|
33
34
|
class << self
|
34
35
|
|
@@ -64,7 +65,7 @@ module SQLite3
|
|
64
65
|
def initialize(file_name, options = {})
|
65
66
|
@encoding = Encoding.find(options.fetch(:encoding, "utf-8"))
|
66
67
|
|
67
|
-
|
68
|
+
@driver = Driver.new
|
68
69
|
|
69
70
|
@statement_factory = options[:statement_factory] || Statement
|
70
71
|
|
@@ -275,34 +276,5 @@ module SQLite3
|
|
275
276
|
def transaction_active?
|
276
277
|
@transaction_active
|
277
278
|
end
|
278
|
-
|
279
|
-
private
|
280
|
-
|
281
|
-
# Loads the corresponding driver, or if it is nil, attempts to locate a
|
282
|
-
# suitable driver.
|
283
|
-
def load_driver(driver)
|
284
|
-
case driver
|
285
|
-
when Class
|
286
|
-
# do nothing--use what was given
|
287
|
-
when Symbol, String
|
288
|
-
require "sqlite3/driver/#{driver.to_s.downcase}/driver"
|
289
|
-
driver = SQLite3::Driver.const_get(driver)::Driver
|
290
|
-
else
|
291
|
-
["FFI"].each do |d|
|
292
|
-
begin
|
293
|
-
require "sqlite3/driver/#{d.downcase}/driver"
|
294
|
-
driver = SQLite3::Driver.const_get(d)::Driver
|
295
|
-
break
|
296
|
-
rescue SyntaxError
|
297
|
-
raise
|
298
|
-
rescue ScriptError, Exception, NameError
|
299
|
-
end
|
300
|
-
end
|
301
|
-
raise "no driver for sqlite3 found" unless driver
|
302
|
-
end
|
303
|
-
|
304
|
-
@driver = driver.new
|
305
|
-
end
|
306
|
-
|
307
279
|
end
|
308
280
|
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
module SQLite3
|
2
|
+
class Driver
|
3
|
+
TRANSIENT = FFI::Pointer.new(-1)
|
4
|
+
|
5
|
+
def open(filename, utf_16 = false)
|
6
|
+
handle = FFI::MemoryPointer.new(:pointer)
|
7
|
+
if utf_16
|
8
|
+
filename = filename.encode(Encoding.utf_16native)
|
9
|
+
result = API.sqlite3_open16(c_string(filename), handle)
|
10
|
+
else
|
11
|
+
filename = filename.encode(Encoding.utf_8)
|
12
|
+
result = API.sqlite3_open(filename, handle)
|
13
|
+
end
|
14
|
+
[result, handle.get_pointer(0)]
|
15
|
+
end
|
16
|
+
|
17
|
+
def errmsg(db, utf_16 = false)
|
18
|
+
if utf_16
|
19
|
+
ptr = API.sqlite3_errmsg16(db)
|
20
|
+
get_string_utf_16(ptr).force_encoding(Encoding.utf_16native)
|
21
|
+
else
|
22
|
+
API.sqlite3_errmsg(db).force_encoding(Encoding.utf_8)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def prepare(db, sql)
|
27
|
+
handle = FFI::MemoryPointer.new(:pointer)
|
28
|
+
remainder = FFI::MemoryPointer.new(:pointer)
|
29
|
+
|
30
|
+
if Encoding.utf_16?(sql)
|
31
|
+
str = c_string(sql)
|
32
|
+
result = API.sqlite3_prepare16(db, str, str.bytesize, handle, remainder)
|
33
|
+
remainder_string = get_string_utf_16(remainder.get_pointer(0))
|
34
|
+
else
|
35
|
+
result = API.sqlite3_prepare(db, sql, sql.bytesize, handle, remainder)
|
36
|
+
remainder_string = remainder.get_pointer(0).get_string(0)
|
37
|
+
end
|
38
|
+
|
39
|
+
[result, handle.get_pointer(0), remainder_string]
|
40
|
+
end
|
41
|
+
|
42
|
+
def bind_string(stmt, index, value)
|
43
|
+
case value.encoding
|
44
|
+
when Encoding.utf_8, Encoding.us_ascii
|
45
|
+
API.sqlite3_bind_text(stmt, index, value, value.bytesize, TRANSIENT)
|
46
|
+
when Encoding.utf_16le, Encoding.utf_16be
|
47
|
+
value = add_byte_order_mask(value)
|
48
|
+
API.sqlite3_bind_text16(stmt, index, value, value.bytesize, TRANSIENT)
|
49
|
+
else
|
50
|
+
API.sqlite3_bind_blob(stmt, index, value, value.bytesize, TRANSIENT)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def column_blob(stmt, column)
|
55
|
+
blob = API.sqlite3_column_blob(stmt, column)
|
56
|
+
length = API.sqlite3_column_bytes(stmt, column)
|
57
|
+
blob.get_bytes(0, length) # free?
|
58
|
+
end
|
59
|
+
|
60
|
+
def column_text(stmt, column, utf_16 = false)
|
61
|
+
if utf_16
|
62
|
+
ptr = API.sqlite3_column_text16(stmt, column)
|
63
|
+
length = API.sqlite3_column_bytes16(stmt, column)
|
64
|
+
ptr.get_bytes(0, length).force_encoding(Encoding.utf_16native) # free?
|
65
|
+
else
|
66
|
+
API.sqlite3_column_text(stmt, column).force_encoding(Encoding.utf_8)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def extension_support?
|
71
|
+
API::EXTENSION_SUPPORT
|
72
|
+
end
|
73
|
+
|
74
|
+
def load_extension(db, name, entry_point = nil)
|
75
|
+
result = API.sqlite3_load_extension(db, name, entry_point, nil)
|
76
|
+
[result, nil]
|
77
|
+
end
|
78
|
+
|
79
|
+
def enable_load_extension(db, onoff = false)
|
80
|
+
API.sqlite3_enable_load_extension(db, (onoff ? 1 : 0))
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.api_delegate(name)
|
84
|
+
define_method(name) { |*args| API.send("sqlite3_#{name}", *args) }
|
85
|
+
end
|
86
|
+
|
87
|
+
api_delegate :bind_double
|
88
|
+
api_delegate :bind_int
|
89
|
+
api_delegate :bind_int64
|
90
|
+
api_delegate :bind_null
|
91
|
+
api_delegate :bind_parameter_index
|
92
|
+
api_delegate :busy_timeout
|
93
|
+
api_delegate :changes
|
94
|
+
api_delegate :close
|
95
|
+
api_delegate :column_count
|
96
|
+
api_delegate :column_decltype
|
97
|
+
api_delegate :column_double
|
98
|
+
api_delegate :column_int64
|
99
|
+
api_delegate :column_name
|
100
|
+
api_delegate :column_type
|
101
|
+
api_delegate :data_count
|
102
|
+
api_delegate :errcode
|
103
|
+
api_delegate :finalize
|
104
|
+
api_delegate :last_insert_rowid
|
105
|
+
api_delegate :libversion
|
106
|
+
api_delegate :reset
|
107
|
+
api_delegate :step
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def c_string(string)
|
112
|
+
if Encoding.utf_16?(string)
|
113
|
+
result = add_byte_order_mask(string)
|
114
|
+
terminate_string!(result)
|
115
|
+
else
|
116
|
+
string # FFI does the job
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def add_byte_order_mask(string)
|
121
|
+
"\uFEFF".encode(string.encoding) + string
|
122
|
+
end
|
123
|
+
|
124
|
+
def terminate_string!(string)
|
125
|
+
string << "\0\0".force_encoding(string.encoding)
|
126
|
+
end
|
127
|
+
|
128
|
+
def get_string_utf_16(ptr)
|
129
|
+
length = 0
|
130
|
+
length += 2 until ptr.get_bytes(length, 2) == "\0\0"
|
131
|
+
ptr.get_bytes(0, length)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module SQLite3
|
2
|
+
module Extensions
|
3
|
+
def enable_load_extension(onoff=true)
|
4
|
+
must_support_extensions!
|
5
|
+
result = @driver.enable_load_extension(@handle, onoff)
|
6
|
+
Error.check(result, self)
|
7
|
+
end
|
8
|
+
|
9
|
+
def disable_load_extension
|
10
|
+
must_support_extensions!
|
11
|
+
result = @driver.enable_load_extension(@handle, false)
|
12
|
+
Error.check(result, self)
|
13
|
+
end
|
14
|
+
|
15
|
+
def load_extension(name, entry_point=nil)
|
16
|
+
must_support_extensions!
|
17
|
+
result, message = @driver.load_extension(@handle, name, entry_point)
|
18
|
+
Error.check(result, self, message)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def must_support_extensions!
|
24
|
+
raise SQLite3::Exception, "extensions API not supported" unless @driver.extension_support?
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/sqlite3.gemspec
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{sqlite3}
|
8
|
+
s.version = "0.0.8"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Jakub Kuźma"]
|
12
|
+
s.date = %q{2010-02-09}
|
13
|
+
s.description = %q{SQLite3 FFI bindings for Ruby 1.9}
|
14
|
+
s.email = %q{qoobaa@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"lib/sqlite3.rb",
|
27
|
+
"lib/sqlite3/api.rb",
|
28
|
+
"lib/sqlite3/constants.rb",
|
29
|
+
"lib/sqlite3/database.rb",
|
30
|
+
"lib/sqlite3/driver.rb",
|
31
|
+
"lib/sqlite3/encoding.rb",
|
32
|
+
"lib/sqlite3/errors.rb",
|
33
|
+
"lib/sqlite3/extensions.rb",
|
34
|
+
"lib/sqlite3/pragmas.rb",
|
35
|
+
"lib/sqlite3/resultset.rb",
|
36
|
+
"lib/sqlite3/statement.rb",
|
37
|
+
"sqlite3.gemspec",
|
38
|
+
"test/fixtures/SQLite.gif",
|
39
|
+
"test/helper.rb",
|
40
|
+
"test/test_active_record.rb",
|
41
|
+
"test/test_database_initialization.rb",
|
42
|
+
"test/test_database_queries_utf_16.rb",
|
43
|
+
"test/test_database_queries_utf_8.rb",
|
44
|
+
"test/test_statement.rb"
|
45
|
+
]
|
46
|
+
s.homepage = %q{http://github.com/qoobaa/sqlite3}
|
47
|
+
s.post_install_message = %q{==== WARNING ===================================================================
|
48
|
+
This is an early alpha version of SQLite3/Ruby FFI bindings!
|
49
|
+
Currently we support Ruby 1.9 ONLY.
|
50
|
+
|
51
|
+
If you need native bindings for Ruby 1.8 - install sqlite3-ruby instead.
|
52
|
+
You may need to uninstall this sqlite3 gem as well.
|
53
|
+
|
54
|
+
Thank you for installing sqlite3 gem! Suggestions: qoobaa@gmail.com
|
55
|
+
================================================================================
|
56
|
+
}
|
57
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
58
|
+
s.require_paths = ["lib"]
|
59
|
+
s.rubygems_version = %q{1.3.5}
|
60
|
+
s.summary = %q{SQLite3 FFI bindings for Ruby 1.9}
|
61
|
+
s.test_files = [
|
62
|
+
"test/test_database_queries_utf_8.rb",
|
63
|
+
"test/test_statement.rb",
|
64
|
+
"test/test_active_record.rb",
|
65
|
+
"test/test_database_queries_utf_16.rb",
|
66
|
+
"test/test_database_initialization.rb",
|
67
|
+
"test/helper.rb"
|
68
|
+
]
|
69
|
+
|
70
|
+
if s.respond_to? :specification_version then
|
71
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
72
|
+
s.specification_version = 3
|
73
|
+
|
74
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
75
|
+
s.add_runtime_dependency(%q<ffi>, [">= 0.6.0"])
|
76
|
+
s.add_development_dependency(%q<test-unit>, [">= 2.0"])
|
77
|
+
s.add_development_dependency(%q<activerecord>, [">= 2.3.5"])
|
78
|
+
else
|
79
|
+
s.add_dependency(%q<ffi>, [">= 0.6.0"])
|
80
|
+
s.add_dependency(%q<test-unit>, [">= 2.0"])
|
81
|
+
s.add_dependency(%q<activerecord>, [">= 2.3.5"])
|
82
|
+
end
|
83
|
+
else
|
84
|
+
s.add_dependency(%q<ffi>, [">= 0.6.0"])
|
85
|
+
s.add_dependency(%q<test-unit>, [">= 2.0"])
|
86
|
+
s.add_dependency(%q<activerecord>, [">= 2.3.5"])
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
data/test/helper.rb
CHANGED
data/test/test_active_record.rb
CHANGED
@@ -21,9 +21,7 @@ class CreateUsers < ActiveRecord::Migration
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
class User < ActiveRecord::Base
|
25
|
-
|
26
|
-
end
|
24
|
+
class User < ActiveRecord::Base; end
|
27
25
|
|
28
26
|
class TestActiveRecord < Test::Unit::TestCase
|
29
27
|
def setup
|
@@ -54,7 +52,7 @@ class TestActiveRecord < Test::Unit::TestCase
|
|
54
52
|
|
55
53
|
def test_user_create
|
56
54
|
login = "bob"
|
57
|
-
avatar = open("
|
55
|
+
avatar = open(fixture("SQLite.gif"), "rb").read
|
58
56
|
login_count = 0
|
59
57
|
ranking = 1.0
|
60
58
|
active = true
|
@@ -146,4 +144,15 @@ class TestActiveRecord < Test::Unit::TestCase
|
|
146
144
|
user.save!
|
147
145
|
assert_equal 1, User.count
|
148
146
|
end
|
147
|
+
|
148
|
+
def test_attribute_assignment
|
149
|
+
user = User.new
|
150
|
+
avatar = open(fixture("SQLite.gif"), "rb").read
|
151
|
+
user.avatar = avatar
|
152
|
+
user.avatar = nil
|
153
|
+
user.save!
|
154
|
+
user.avatar = avatar
|
155
|
+
user.reload
|
156
|
+
assert_equal 1, User.count
|
157
|
+
end
|
149
158
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
class TestStatement < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@db = SQLite3::Database.new(":memory:")
|
6
|
+
@db.execute("CREATE TABLE t1(id INTEGER PRIMARY KEY ASC, t TEXT, nu1 NUMERIC, i1 INTEGER, i2 INTEGER, no BLOB)")
|
7
|
+
@statement = @db.prepare("INSERT INTO t1 VALUES(:ID, :T, :NU1, :I1, :I2, :NO)")
|
8
|
+
end
|
9
|
+
|
10
|
+
def teardown
|
11
|
+
@statement.close
|
12
|
+
@db.close
|
13
|
+
end
|
14
|
+
|
15
|
+
test "bind param by name" do
|
16
|
+
@statement.bind_param("T", "test")
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
test "bind param by name with colon" do
|
21
|
+
@statement.bind_param(":T", "test")
|
22
|
+
end
|
23
|
+
|
24
|
+
test "bind param by number" do
|
25
|
+
@statement.bind_param(1, "test")
|
26
|
+
end
|
27
|
+
|
28
|
+
test "bind non existing param name" do
|
29
|
+
assert_raises(SQLite3::Exception) { @statement.bind_param(":NONEXISTING", "test") }
|
30
|
+
end
|
31
|
+
|
32
|
+
test "execute statement" do
|
33
|
+
@statement.execute
|
34
|
+
end
|
35
|
+
|
36
|
+
test "execute statement multiple times" do
|
37
|
+
@statement.bind_param("T", "test")
|
38
|
+
@statement.execute
|
39
|
+
@statement.bind_param("NU1", 500)
|
40
|
+
@statement.execute
|
41
|
+
end
|
42
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sqlite3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "Jakub Ku\xC5\xBAma"
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-02-
|
12
|
+
date: 2010-02-09 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -20,7 +20,7 @@ dependencies:
|
|
20
20
|
requirements:
|
21
21
|
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: 0.
|
23
|
+
version: 0.6.0
|
24
24
|
version:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: test-unit
|
@@ -59,21 +59,24 @@ files:
|
|
59
59
|
- Rakefile
|
60
60
|
- VERSION
|
61
61
|
- lib/sqlite3.rb
|
62
|
+
- lib/sqlite3/api.rb
|
62
63
|
- lib/sqlite3/constants.rb
|
63
64
|
- lib/sqlite3/database.rb
|
64
|
-
- lib/sqlite3/driver
|
65
|
-
- lib/sqlite3/driver/ffi/driver.rb
|
65
|
+
- lib/sqlite3/driver.rb
|
66
66
|
- lib/sqlite3/encoding.rb
|
67
67
|
- lib/sqlite3/errors.rb
|
68
|
+
- lib/sqlite3/extensions.rb
|
68
69
|
- lib/sqlite3/pragmas.rb
|
69
70
|
- lib/sqlite3/resultset.rb
|
70
71
|
- lib/sqlite3/statement.rb
|
72
|
+
- sqlite3.gemspec
|
71
73
|
- test/fixtures/SQLite.gif
|
72
74
|
- test/helper.rb
|
73
75
|
- test/test_active_record.rb
|
74
76
|
- test/test_database_initialization.rb
|
75
77
|
- test/test_database_queries_utf_16.rb
|
76
78
|
- test/test_database_queries_utf_8.rb
|
79
|
+
- test/test_statement.rb
|
77
80
|
has_rdoc: true
|
78
81
|
homepage: http://github.com/qoobaa/sqlite3
|
79
82
|
licenses: []
|
@@ -114,6 +117,7 @@ specification_version: 3
|
|
114
117
|
summary: SQLite3 FFI bindings for Ruby 1.9
|
115
118
|
test_files:
|
116
119
|
- test/test_database_queries_utf_8.rb
|
120
|
+
- test/test_statement.rb
|
117
121
|
- test/test_active_record.rb
|
118
122
|
- test/test_database_queries_utf_16.rb
|
119
123
|
- test/test_database_initialization.rb
|
@@ -1,47 +0,0 @@
|
|
1
|
-
module SQLite3
|
2
|
-
module Driver
|
3
|
-
module FFI
|
4
|
-
|
5
|
-
module API
|
6
|
-
extend ::FFI::Library
|
7
|
-
|
8
|
-
# TODO: cleanup
|
9
|
-
ffi_lib "libsqlite3.dylib", "libsqlite3.so" "sqlite3.dll"
|
10
|
-
|
11
|
-
attach_function :sqlite3_libversion, [], :string
|
12
|
-
attach_function :sqlite3_open, [:string, :pointer], :int
|
13
|
-
attach_function :sqlite3_open16, [:pointer, :pointer], :int
|
14
|
-
attach_function :sqlite3_close, [:pointer], :int
|
15
|
-
attach_function :sqlite3_errmsg, [:pointer], :string
|
16
|
-
attach_function :sqlite3_errmsg16, [:pointer], :pointer
|
17
|
-
attach_function :sqlite3_errcode, [:pointer], :int
|
18
|
-
attach_function :sqlite3_prepare, [:pointer, :string, :int, :pointer, :pointer], :int
|
19
|
-
attach_function :sqlite3_finalize, [:pointer], :int
|
20
|
-
attach_function :sqlite3_step, [:pointer], :int
|
21
|
-
attach_function :sqlite3_last_insert_rowid, [:pointer], :int64
|
22
|
-
attach_function :sqlite3_changes, [:pointer], :int
|
23
|
-
attach_function :sqlite3_busy_timeout, [:pointer, :int], :int
|
24
|
-
attach_function :sqlite3_bind_blob, [:pointer, :int, :pointer, :int, :pointer], :int
|
25
|
-
attach_function :sqlite3_bind_double, [:pointer, :int, :double], :int
|
26
|
-
attach_function :sqlite3_bind_int, [:pointer, :int, :int], :int
|
27
|
-
attach_function :sqlite3_bind_int64, [:pointer, :int, :int64], :int
|
28
|
-
attach_function :sqlite3_bind_null, [:pointer, :int], :int
|
29
|
-
attach_function :sqlite3_bind_text, [:pointer, :int, :string, :int, :pointer], :int
|
30
|
-
attach_function :sqlite3_bind_text16, [:pointer, :int, :pointer, :int, :pointer], :int
|
31
|
-
attach_function :sqlite3_column_count, [:pointer], :int
|
32
|
-
attach_function :sqlite3_data_count, [:pointer], :int
|
33
|
-
attach_function :sqlite3_column_blob, [:pointer, :int], :pointer
|
34
|
-
attach_function :sqlite3_column_bytes, [:pointer, :int], :int
|
35
|
-
attach_function :sqlite3_column_bytes16, [:pointer, :int], :int
|
36
|
-
attach_function :sqlite3_column_decltype, [:pointer, :int], :string
|
37
|
-
attach_function :sqlite3_column_double, [:pointer, :int], :double
|
38
|
-
attach_function :sqlite3_column_int64, [:pointer, :int], :int64
|
39
|
-
attach_function :sqlite3_column_name, [:pointer, :int], :string
|
40
|
-
attach_function :sqlite3_column_text, [:pointer, :int], :string
|
41
|
-
attach_function :sqlite3_column_text16, [:pointer, :int], :pointer
|
42
|
-
attach_function :sqlite3_column_type, [:pointer, :int], :int
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
@@ -1,128 +0,0 @@
|
|
1
|
-
require 'sqlite3/driver/ffi/api'
|
2
|
-
|
3
|
-
module SQLite3
|
4
|
-
module Driver
|
5
|
-
module FFI
|
6
|
-
|
7
|
-
class Driver
|
8
|
-
TRANSIENT = ::FFI::Pointer.new(-1)
|
9
|
-
|
10
|
-
def open(filename, utf_16 = false)
|
11
|
-
handle = ::FFI::MemoryPointer.new(:pointer)
|
12
|
-
if utf_16
|
13
|
-
filename = filename.encode(Encoding.utf_16native)
|
14
|
-
result = API.sqlite3_open16(c_string(filename), handle)
|
15
|
-
else
|
16
|
-
filename = filename.encode(Encoding.utf_8)
|
17
|
-
result = API.sqlite3_open(filename, handle)
|
18
|
-
end
|
19
|
-
[result, handle.get_pointer(0)]
|
20
|
-
end
|
21
|
-
|
22
|
-
def errmsg(db, utf_16 = false)
|
23
|
-
if utf_16
|
24
|
-
ptr = API.sqlite3_errmsg16(db)
|
25
|
-
get_string_utf_16(ptr).force_encoding(Encoding.utf_16native)
|
26
|
-
else
|
27
|
-
API.sqlite3_errmsg(db).force_encoding(Encoding.utf_8)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def prepare(db, sql)
|
32
|
-
handle = ::FFI::MemoryPointer.new(:pointer)
|
33
|
-
remainder = ::FFI::MemoryPointer.new(:pointer)
|
34
|
-
|
35
|
-
if Encoding.utf_16?(sql)
|
36
|
-
str = c_string(sql)
|
37
|
-
result = API.sqlite3_prepare16(db, str, str.bytesize, handle, remainder)
|
38
|
-
remainder_string = get_string_utf_16(remainder.get_pointer(0))
|
39
|
-
else
|
40
|
-
result = API.sqlite3_prepare(db, sql, sql.bytesize, handle, remainder)
|
41
|
-
remainder_string = remainder.get_pointer(0).get_string(0)
|
42
|
-
end
|
43
|
-
|
44
|
-
[result, handle.get_pointer(0), remainder_string]
|
45
|
-
end
|
46
|
-
|
47
|
-
def bind_string(stmt, index, value)
|
48
|
-
case value.encoding
|
49
|
-
when Encoding.utf_8, Encoding.us_ascii
|
50
|
-
API.sqlite3_bind_text(stmt, index, value, value.bytesize, TRANSIENT)
|
51
|
-
when Encoding.utf_16le, Encoding.utf_16be
|
52
|
-
value = add_byte_order_mask(value)
|
53
|
-
API.sqlite3_bind_text16(stmt, index, value, value.bytesize, TRANSIENT)
|
54
|
-
else
|
55
|
-
API.sqlite3_bind_blob(stmt, index, value, value.bytesize, TRANSIENT)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def column_blob(stmt, column)
|
60
|
-
blob = API.sqlite3_column_blob(stmt, column)
|
61
|
-
length = API.sqlite3_column_bytes(stmt, column)
|
62
|
-
blob.get_bytes(0, length) # free?
|
63
|
-
end
|
64
|
-
|
65
|
-
def column_text(stmt, column, utf_16 = false)
|
66
|
-
if utf_16
|
67
|
-
ptr = API.sqlite3_column_text16(stmt, column)
|
68
|
-
length = API.sqlite3_column_bytes16(stmt, column)
|
69
|
-
ptr.get_bytes(0, length).force_encoding(Encoding.utf_16native) # free?
|
70
|
-
else
|
71
|
-
API.sqlite3_column_text(stmt, column).force_encoding(Encoding.utf_8)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def self.api_delegate(name)
|
76
|
-
define_method(name) { |*args| API.send("sqlite3_#{name}", *args) }
|
77
|
-
end
|
78
|
-
|
79
|
-
api_delegate :column_name
|
80
|
-
api_delegate :column_decltype
|
81
|
-
api_delegate :bind_double
|
82
|
-
api_delegate :bind_int
|
83
|
-
api_delegate :bind_int64
|
84
|
-
api_delegate :bind_null
|
85
|
-
api_delegate :bind_parameter_index
|
86
|
-
api_delegate :bind_parameter_name
|
87
|
-
api_delegate :busy_timeout
|
88
|
-
api_delegate :changes
|
89
|
-
api_delegate :close
|
90
|
-
api_delegate :column_count
|
91
|
-
api_delegate :column_double
|
92
|
-
api_delegate :column_int64
|
93
|
-
api_delegate :column_type
|
94
|
-
api_delegate :data_count
|
95
|
-
api_delegate :errcode
|
96
|
-
api_delegate :finalize
|
97
|
-
api_delegate :last_insert_rowid
|
98
|
-
api_delegate :libversion
|
99
|
-
api_delegate :step
|
100
|
-
|
101
|
-
private
|
102
|
-
|
103
|
-
def c_string(string)
|
104
|
-
if Encoding.utf_16?(string)
|
105
|
-
result = add_byte_order_mask(string)
|
106
|
-
terminate_string!(result)
|
107
|
-
else
|
108
|
-
string # FFI does the job
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def add_byte_order_mask(string)
|
113
|
-
"\uFEFF".encode(string.encoding) + string
|
114
|
-
end
|
115
|
-
|
116
|
-
def terminate_string!(string)
|
117
|
-
string << "\0\0".force_encoding(string.encoding)
|
118
|
-
end
|
119
|
-
|
120
|
-
def get_string_utf_16(ptr)
|
121
|
-
length = 0
|
122
|
-
length += 2 until ptr.get_bytes(length, 2) == "\0\0"
|
123
|
-
ptr.get_bytes(0, length)
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|