extralite 1.10 → 1.13
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.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +2 -2
- data/CHANGELOG.md +9 -0
- data/Gemfile.lock +3 -3
- data/README.md +91 -32
- data/Rakefile +1 -1
- data/bin/update_sqlite_source +26 -0
- data/ext/extralite/common.c +347 -0
- data/ext/extralite/database.c +385 -0
- data/ext/extralite/extconf.rb +3 -109
- data/ext/extralite/extralite.h +59 -0
- data/ext/extralite/extralite_ext.c +4 -2
- data/ext/extralite/prepared_statement.c +238 -0
- data/ext/extralite/sqlite3.c +239246 -0
- data/ext/extralite/sqlite3.h +12802 -0
- data/extralite.gemspec +1 -1
- data/lib/extralite/version.rb +1 -1
- data/test/extensions/text.dylib +0 -0
- data/test/extensions/text.so +0 -0
- data/test/helper.rb +2 -0
- data/test/perf_hash.rb +1 -1
- data/test/perf_prepared.rb +64 -0
- data/test/test_database.rb +14 -0
- data/test/test_extralite.rb +14 -0
- data/test/test_prepared_statement.rb +165 -0
- metadata +20 -9
- data/ext/extralite/extralite.c +0 -691
data/extralite.gemspec
CHANGED
|
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
|
|
|
19
19
|
s.extra_rdoc_files = ["README.md"]
|
|
20
20
|
s.extensions = ["ext/extralite/extconf.rb"]
|
|
21
21
|
s.require_paths = ["lib"]
|
|
22
|
-
s.required_ruby_version = '>= 2.
|
|
22
|
+
s.required_ruby_version = '>= 2.7'
|
|
23
23
|
|
|
24
24
|
s.add_development_dependency 'rake-compiler', '1.1.6'
|
|
25
25
|
s.add_development_dependency 'minitest', '5.15.0'
|
data/lib/extralite/version.rb
CHANGED
|
Binary file
|
|
Binary file
|
data/test/helper.rb
CHANGED
data/test/perf_hash.rb
CHANGED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bundler/inline'
|
|
4
|
+
|
|
5
|
+
gemfile do
|
|
6
|
+
source 'https://rubygems.org'
|
|
7
|
+
gem 'extralite', path: '..'
|
|
8
|
+
gem 'sqlite3'
|
|
9
|
+
gem 'benchmark-ips'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
require 'benchmark/ips'
|
|
13
|
+
require 'fileutils'
|
|
14
|
+
|
|
15
|
+
DB_PATH = '/tmp/extralite_sqlite3_perf.db'
|
|
16
|
+
|
|
17
|
+
def prepare_database(count)
|
|
18
|
+
FileUtils.rm(DB_PATH) rescue nil
|
|
19
|
+
db = Extralite::Database.new(DB_PATH)
|
|
20
|
+
db.query('create table foo ( a integer primary key, b text )')
|
|
21
|
+
db.query('begin')
|
|
22
|
+
count.times { db.query('insert into foo (b) values (?)', "hello#{rand(1000)}" )}
|
|
23
|
+
db.query('commit')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def sqlite3_prepare
|
|
27
|
+
db = SQLite3::Database.new(DB_PATH, :results_as_hash => true)
|
|
28
|
+
db.prepare('select * from foo')
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def sqlite3_run(stmt, count)
|
|
32
|
+
# db = SQLite3::Database.new(DB_PATH, :results_as_hash => true)
|
|
33
|
+
results = stmt.execute.to_a
|
|
34
|
+
raise unless results.size == count
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def extralite_prepare
|
|
38
|
+
db = Extralite::Database.new(DB_PATH)
|
|
39
|
+
db.prepare('select * from foo')
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def extralite_run(stmt, count)
|
|
43
|
+
# db = Extralite::Database.new(DB_PATH)
|
|
44
|
+
results = stmt.query
|
|
45
|
+
raise unless results.size == count
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
[10, 1000, 100000].each do |c|
|
|
49
|
+
puts; puts; puts "Record count: #{c}"
|
|
50
|
+
|
|
51
|
+
prepare_database(c)
|
|
52
|
+
|
|
53
|
+
sqlite3_stmt = sqlite3_prepare
|
|
54
|
+
extralite_stmt = extralite_prepare
|
|
55
|
+
|
|
56
|
+
Benchmark.ips do |x|
|
|
57
|
+
x.config(:time => 3, :warmup => 1)
|
|
58
|
+
|
|
59
|
+
x.report("sqlite3") { sqlite3_run(sqlite3_stmt, c) }
|
|
60
|
+
x.report("extralite") { extralite_run(extralite_stmt, c) }
|
|
61
|
+
|
|
62
|
+
x.compare!
|
|
63
|
+
end
|
|
64
|
+
end
|
data/test/test_database.rb
CHANGED
|
@@ -163,6 +163,20 @@ end
|
|
|
163
163
|
r = @db.query_single_value('select null')
|
|
164
164
|
assert_nil r
|
|
165
165
|
end
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def test_extension_loading
|
|
170
|
+
case RUBY_PLATFORM
|
|
171
|
+
when /linux/
|
|
172
|
+
@db.load_extension(File.join(__dir__, 'extensions/text.so'))
|
|
173
|
+
when /darwin/
|
|
174
|
+
@db.load_extension(File.join(__dir__, 'extensions/text.dylib'))
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
r = @db.query_single_value("select reverse('abcd')")
|
|
178
|
+
assert_equal 'dcba', r
|
|
179
|
+
end
|
|
166
180
|
end
|
|
167
181
|
|
|
168
182
|
class ScenarioTest < MiniTest::Test
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'helper'
|
|
4
|
+
|
|
5
|
+
class ExtraliteTest < MiniTest::Test
|
|
6
|
+
SQLITE3_C_PATH = File.expand_path('../ext/extralite/sqlite3.c', __dir__)
|
|
7
|
+
SQLITE_VERSION_DEFINE_REGEXP = /#define SQLITE_VERSION\s+"([\d\.]+)"/m.freeze
|
|
8
|
+
|
|
9
|
+
def test_sqlite3_version
|
|
10
|
+
version = IO.read(SQLITE3_C_PATH).match(SQLITE_VERSION_DEFINE_REGEXP)[1]
|
|
11
|
+
|
|
12
|
+
assert_equal version, Extralite.sqlite3_version
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'helper'
|
|
4
|
+
|
|
5
|
+
class PreparedStatementTest < MiniTest::Test
|
|
6
|
+
def setup
|
|
7
|
+
@db = Extralite::Database.new(':memory:')
|
|
8
|
+
@db.query('create table if not exists t (x,y,z)')
|
|
9
|
+
@db.query('delete from t')
|
|
10
|
+
@db.query('insert into t values (1, 2, 3)')
|
|
11
|
+
@db.query('insert into t values (4, 5, 6)')
|
|
12
|
+
|
|
13
|
+
@stmt = @db.prepare('select * from t where x = ?')
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# def test_foo
|
|
17
|
+
# stmt = @db.prepare('select 1')
|
|
18
|
+
# assert_equal 1, stmt.query_single_value
|
|
19
|
+
# end
|
|
20
|
+
|
|
21
|
+
def test_prepared_statement_props
|
|
22
|
+
assert_kind_of Extralite::PreparedStatement, @stmt
|
|
23
|
+
assert_equal @db, @stmt.database
|
|
24
|
+
assert_equal @db, @stmt.db
|
|
25
|
+
assert_equal 'select * from t where x = ?', @stmt.sql
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_prepared_statement_query
|
|
29
|
+
assert_equal [{ x: 1, y: 2, z: 3 }], @stmt.query(1)
|
|
30
|
+
|
|
31
|
+
buf = []
|
|
32
|
+
@stmt.query(1) { |r| buf << r }
|
|
33
|
+
assert_equal [{ x: 1, y: 2, z: 3 }], buf
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_prepared_statement_with_invalid_sql
|
|
37
|
+
assert_raises(Extralite::SQLError) { @db.prepare('blah') }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def test_prepared_statement_query_hash
|
|
41
|
+
r = @stmt.query_hash(4)
|
|
42
|
+
assert_equal [{x: 4, y: 5, z: 6}], r
|
|
43
|
+
|
|
44
|
+
r = @stmt.query_hash(5)
|
|
45
|
+
assert_equal [], r
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_prepared_statement_query_ary
|
|
49
|
+
r = @stmt.query_ary(1)
|
|
50
|
+
assert_equal [[1, 2, 3]], r
|
|
51
|
+
|
|
52
|
+
r = @stmt.query_ary(2)
|
|
53
|
+
assert_equal [], r
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def test_prepared_statement_query_single_row
|
|
57
|
+
r = @stmt.query_single_row(4)
|
|
58
|
+
assert_equal({ x: 4, y: 5, z: 6 }, r)
|
|
59
|
+
|
|
60
|
+
r = @stmt.query_single_row(5)
|
|
61
|
+
assert_nil r
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def test_prepared_statement_query_single_column
|
|
65
|
+
stmt =
|
|
66
|
+
r = @db.prepare('select y from t').query_single_column
|
|
67
|
+
assert_equal [2, 5], r
|
|
68
|
+
|
|
69
|
+
r = @db.prepare('select y from t where x = 2').query_single_column
|
|
70
|
+
assert_equal [], r
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def test_prepared_statement_query_single_value
|
|
74
|
+
r = @db.prepare('select z from t order by Z desc limit 1').query_single_value
|
|
75
|
+
assert_equal 6, r
|
|
76
|
+
|
|
77
|
+
r = @db.prepare('select z from t where x = 2').query_single_value
|
|
78
|
+
assert_nil r
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def test_prepared_statement_multiple_statements
|
|
82
|
+
assert_raises(Extralite::Error) {
|
|
83
|
+
@db.prepare("insert into t values ('a', 'b', 'c'); insert into t values ('d', 'e', 'f');")
|
|
84
|
+
}
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def test_prepared_statement_multiple_statements_with_bad_sql
|
|
88
|
+
error = nil
|
|
89
|
+
begin
|
|
90
|
+
stmt =@db.prepare("insert into t values foo; insert into t values ('d', 'e', 'f');")
|
|
91
|
+
stmt.query
|
|
92
|
+
rescue => error
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
assert_kind_of Extralite::SQLError, error
|
|
96
|
+
assert_equal 'near "foo": syntax error', error.message
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def test_prepared_statement_repeated_execution_missing_param
|
|
100
|
+
r = @stmt.query_hash(4)
|
|
101
|
+
assert_equal [{x: 4, y: 5, z: 6}], r
|
|
102
|
+
|
|
103
|
+
r = @stmt.query_hash
|
|
104
|
+
assert_equal [], r
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def test_prepared_statement_empty_sql
|
|
108
|
+
assert_raises(Extralite::Error) { @db.prepare(' ') }
|
|
109
|
+
|
|
110
|
+
r = @db.prepare('select 1 as foo; ').query
|
|
111
|
+
assert_equal [{ foo: 1 }], r
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def test_prepared_statement_parameter_binding_simple
|
|
115
|
+
r = @db.prepare('select x, y, z from t where x = ?').query(1)
|
|
116
|
+
assert_equal [{ x: 1, y: 2, z: 3 }], r
|
|
117
|
+
|
|
118
|
+
r = @db.prepare('select x, y, z from t where z = ?').query(6)
|
|
119
|
+
assert_equal [{ x: 4, y: 5, z: 6 }], r
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def test_prepared_statement_parameter_binding_with_index
|
|
123
|
+
r = @db.prepare('select x, y, z from t where x = ?2').query(0, 1)
|
|
124
|
+
assert_equal [{ x: 1, y: 2, z: 3 }], r
|
|
125
|
+
|
|
126
|
+
r = @db.prepare('select x, y, z from t where z = ?3').query(3, 4, 6)
|
|
127
|
+
assert_equal [{ x: 4, y: 5, z: 6 }], r
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def test_prepared_statement_parameter_binding_with_name
|
|
131
|
+
r = @db.prepare('select x, y, z from t where x = :x').query(x: 1, y: 2)
|
|
132
|
+
assert_equal [{ x: 1, y: 2, z: 3 }], r
|
|
133
|
+
|
|
134
|
+
r = @db.prepare('select x, y, z from t where z = :zzz').query('zzz' => 6)
|
|
135
|
+
assert_equal [{ x: 4, y: 5, z: 6 }], r
|
|
136
|
+
|
|
137
|
+
r = @db.prepare('select x, y, z from t where z = :bazzz').query(':bazzz' => 6)
|
|
138
|
+
assert_equal [{ x: 4, y: 5, z: 6 }], r
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def test_prepared_statement_parameter_binding_with_index_key
|
|
142
|
+
r = @db.prepare('select x, y, z from t where z = ?').query(1 => 3)
|
|
143
|
+
assert_equal [{ x: 1, y: 2, z: 3 }], r
|
|
144
|
+
|
|
145
|
+
r = @db.prepare('select x, y, z from t where x = ?2').query(1 => 42, 2 => 4)
|
|
146
|
+
assert_equal [{ x: 4, y: 5, z: 6 }], r
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def test_prepared_statement_value_casting
|
|
150
|
+
r = @db.prepare("select 'abc'").query_single_value
|
|
151
|
+
assert_equal 'abc', r
|
|
152
|
+
|
|
153
|
+
r = @db.prepare('select 123').query_single_value
|
|
154
|
+
assert_equal 123, r
|
|
155
|
+
|
|
156
|
+
r = @db.prepare('select 12.34').query_single_value
|
|
157
|
+
assert_equal 12.34, r
|
|
158
|
+
|
|
159
|
+
r = @db.prepare('select zeroblob(4)').query_single_value
|
|
160
|
+
assert_equal "\x00\x00\x00\x00", r
|
|
161
|
+
|
|
162
|
+
r = @db.prepare('select null').query_single_value
|
|
163
|
+
assert_nil r
|
|
164
|
+
end
|
|
165
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: extralite
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: '1.
|
|
4
|
+
version: '1.13'
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sharon Rosner
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2022-02-27 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake-compiler
|
|
@@ -80,7 +80,7 @@ dependencies:
|
|
|
80
80
|
- - '='
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: 5.51.0
|
|
83
|
-
description:
|
|
83
|
+
description:
|
|
84
84
|
email: sharon@noteflakes.com
|
|
85
85
|
executables: []
|
|
86
86
|
extensions:
|
|
@@ -98,18 +98,29 @@ files:
|
|
|
98
98
|
- README.md
|
|
99
99
|
- Rakefile
|
|
100
100
|
- TODO.md
|
|
101
|
+
- bin/update_sqlite_source
|
|
102
|
+
- ext/extralite/common.c
|
|
103
|
+
- ext/extralite/database.c
|
|
101
104
|
- ext/extralite/extconf.rb
|
|
102
|
-
- ext/extralite/extralite.
|
|
105
|
+
- ext/extralite/extralite.h
|
|
103
106
|
- ext/extralite/extralite_ext.c
|
|
107
|
+
- ext/extralite/prepared_statement.c
|
|
108
|
+
- ext/extralite/sqlite3.c
|
|
109
|
+
- ext/extralite/sqlite3.h
|
|
104
110
|
- extralite.gemspec
|
|
105
111
|
- lib/extralite.rb
|
|
106
112
|
- lib/extralite/version.rb
|
|
107
113
|
- lib/sequel/adapters/extralite.rb
|
|
114
|
+
- test/extensions/text.dylib
|
|
115
|
+
- test/extensions/text.so
|
|
108
116
|
- test/helper.rb
|
|
109
117
|
- test/perf_ary.rb
|
|
110
118
|
- test/perf_hash.rb
|
|
119
|
+
- test/perf_prepared.rb
|
|
111
120
|
- test/run.rb
|
|
112
121
|
- test/test_database.rb
|
|
122
|
+
- test/test_extralite.rb
|
|
123
|
+
- test/test_prepared_statement.rb
|
|
113
124
|
- test/test_sequel.rb
|
|
114
125
|
homepage: https://github.com/digital-fabric/extralite
|
|
115
126
|
licenses:
|
|
@@ -119,7 +130,7 @@ metadata:
|
|
|
119
130
|
documentation_uri: https://www.rubydoc.info/gems/extralite
|
|
120
131
|
homepage_uri: https://github.com/digital-fabric/extralite
|
|
121
132
|
changelog_uri: https://github.com/digital-fabric/extralite/blob/master/CHANGELOG.md
|
|
122
|
-
post_install_message:
|
|
133
|
+
post_install_message:
|
|
123
134
|
rdoc_options:
|
|
124
135
|
- "--title"
|
|
125
136
|
- extralite
|
|
@@ -131,15 +142,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
131
142
|
requirements:
|
|
132
143
|
- - ">="
|
|
133
144
|
- !ruby/object:Gem::Version
|
|
134
|
-
version: '2.
|
|
145
|
+
version: '2.7'
|
|
135
146
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
136
147
|
requirements:
|
|
137
148
|
- - ">="
|
|
138
149
|
- !ruby/object:Gem::Version
|
|
139
150
|
version: '0'
|
|
140
151
|
requirements: []
|
|
141
|
-
rubygems_version: 3.
|
|
142
|
-
signing_key:
|
|
152
|
+
rubygems_version: 3.3.3
|
|
153
|
+
signing_key:
|
|
143
154
|
specification_version: 4
|
|
144
155
|
summary: Extra-lightweight SQLite3 wrapper for Ruby
|
|
145
156
|
test_files: []
|