sqlite-ruby 2.1.0-mswin32
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 +34 -0
- data/doc/faq/faq.html +390 -0
- data/doc/faq/faq.rb +145 -0
- data/doc/faq/faq.yml +453 -0
- data/ext/extconf.rb +8 -0
- data/ext/sqlite-api.c +1414 -0
- data/lib/sqlite.rb +34 -0
- data/lib/sqlite/database.rb +682 -0
- data/lib/sqlite/parsed_statement.rb +233 -0
- data/lib/sqlite/pragmas.rb +236 -0
- data/lib/sqlite/resultset.rb +168 -0
- data/lib/sqlite/statement.rb +145 -0
- data/lib/sqlite/translator.rb +135 -0
- data/lib/sqlite/version.rb +45 -0
- data/lib/sqlite_api.so +0 -0
- data/test/db/fixtures.sql +25 -0
- data/test/tc_api_core.rb +201 -0
- data/test/tc_arrayfields.rb +74 -0
- data/test/tc_database.rb +335 -0
- data/test/tc_parsed_statement.rb +160 -0
- data/test/tc_pragmas.rb +207 -0
- data/test/tc_translator.rb +115 -0
- data/test/tc_type_translation.rb +55 -0
- data/test/tests.rb +133 -0
- metadata +67 -0
data/lib/sqlite_api.so
ADDED
Binary file
|
@@ -0,0 +1,25 @@
|
|
1
|
+
create table A
|
2
|
+
(
|
3
|
+
name VARCHAR(60),
|
4
|
+
age INTEGER
|
5
|
+
);
|
6
|
+
|
7
|
+
insert into A values ( 'Zephyr', 1 );
|
8
|
+
insert into A values ( 'Timothy', 2 );
|
9
|
+
insert into A values ( 'Juniper', 3 );
|
10
|
+
insert into A values ( 'Cinnamon', 4 );
|
11
|
+
insert into A values ( 'Amber', 5 );
|
12
|
+
insert into A values ( NULL, 6 );
|
13
|
+
|
14
|
+
create table B
|
15
|
+
(
|
16
|
+
id INTEGER PRIMARY KEY,
|
17
|
+
name VARCHAR(60)
|
18
|
+
);
|
19
|
+
|
20
|
+
create index B_idx on B ( name );
|
21
|
+
|
22
|
+
create table D
|
23
|
+
(
|
24
|
+
b_id INTEGER REFERENCES B ( id )
|
25
|
+
);
|
data/test/tc_api_core.rb
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
#--
|
2
|
+
# =============================================================================
|
3
|
+
# Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
|
4
|
+
# All rights reserved.
|
5
|
+
#
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
7
|
+
# modification, are permitted provided that the following conditions are met:
|
8
|
+
#
|
9
|
+
# * Redistributions of source code must retain the above copyright notice,
|
10
|
+
# this list of conditions and the following disclaimer.
|
11
|
+
#
|
12
|
+
# * Redistributions in binary form must reproduce the above copyright
|
13
|
+
# notice, this list of conditions and the following disclaimer in the
|
14
|
+
# documentation and/or other materials provided with the distribution.
|
15
|
+
#
|
16
|
+
# * The names of its contributors may not be used to endorse or promote
|
17
|
+
# products derived from this software without specific prior written
|
18
|
+
# permission.
|
19
|
+
#
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
23
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
24
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
25
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
26
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
27
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
28
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
29
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
# =============================================================================
|
31
|
+
#++
|
32
|
+
|
33
|
+
$:.unshift "lib"
|
34
|
+
|
35
|
+
require 'sqlite_api'
|
36
|
+
require 'test/unit'
|
37
|
+
|
38
|
+
# MISSING TESTS FOR:
|
39
|
+
# SQLite::Exceptions::BusyException (and related cases)
|
40
|
+
# API.interrupt
|
41
|
+
# API.busy_handler
|
42
|
+
# API.busy_timeout
|
43
|
+
# API.function_type
|
44
|
+
# API.set_result_error
|
45
|
+
|
46
|
+
class TC_APICore < Test::Unit::TestCase
|
47
|
+
include SQLite
|
48
|
+
|
49
|
+
def test_constants
|
50
|
+
assert_equal( "constant", defined? API::VERSION )
|
51
|
+
assert_equal( "constant", defined? API::ENCODING )
|
52
|
+
assert_equal( "constant", defined? API::NUMERIC )
|
53
|
+
assert_equal( "constant", defined? API::TEXT )
|
54
|
+
assert_equal( "constant", defined? API::ARGS )
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_open_new
|
58
|
+
assert !File.exist?( "db/dummy.db" )
|
59
|
+
db = API.open( "db/dummy.db", 0 )
|
60
|
+
assert File.exist?( "db/dummy.db" )
|
61
|
+
API.close db
|
62
|
+
File.delete "db/dummy.db"
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_compile
|
66
|
+
db = API.open( "db/fixtures.db", 0 )
|
67
|
+
vm, rest = API.compile( db, "select name, age from A order by name;extra" )
|
68
|
+
assert_equal "extra", rest
|
69
|
+
result = API.step( vm )
|
70
|
+
assert_nil result[:row][0]
|
71
|
+
assert_equal ["name","age"], result[:columns]
|
72
|
+
result = API.step( vm )
|
73
|
+
assert_equal 'Amber', result[:row][0]
|
74
|
+
result = API.step( vm )
|
75
|
+
assert_equal 'Cinnamon', result[:row][0]
|
76
|
+
result = API.step( vm )
|
77
|
+
assert_equal 'Juniper', result[:row][0]
|
78
|
+
result = API.step( vm )
|
79
|
+
assert_equal 'Timothy', result[:row][0]
|
80
|
+
result = API.step( vm )
|
81
|
+
assert_equal 'Zephyr', result[:row][0]
|
82
|
+
result = API.step( vm )
|
83
|
+
assert !result.has_key?(:row)
|
84
|
+
|
85
|
+
assert_raise( SQLite::Exceptions::MisuseException ) do
|
86
|
+
API.step( vm )
|
87
|
+
end
|
88
|
+
|
89
|
+
API.finalize( vm )
|
90
|
+
API.close( db )
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_bad_compile
|
94
|
+
db = API.open( "db/fixtures.db", 0 )
|
95
|
+
assert_raise( SQLite::Exceptions::SQLException ) do
|
96
|
+
API.compile( db, "select name, age from BOGUS order by name" )
|
97
|
+
end
|
98
|
+
API.close( db )
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_empty_compile
|
102
|
+
db = API.open( "db/fixtures.db", 0 )
|
103
|
+
vm, rest = API.compile( db, "select * from B order by name" )
|
104
|
+
result = API.step( vm )
|
105
|
+
assert !result.has_key?(:row)
|
106
|
+
assert_equal ["id","name"], result[:columns]
|
107
|
+
API.finalize( vm )
|
108
|
+
API.close( db )
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_last_insert_row_id
|
112
|
+
db = API.open( "db/dummy.db", 0 )
|
113
|
+
|
114
|
+
vm, rest = API.compile( db, "create table Z ( a integer primary key, b varchar(60) )" )
|
115
|
+
API.step(vm)
|
116
|
+
API.finalize(vm)
|
117
|
+
|
118
|
+
vm, rest = API.compile( db, "insert into Z values ( 14, 'Hello' )" )
|
119
|
+
API.step(vm)
|
120
|
+
API.finalize(vm)
|
121
|
+
|
122
|
+
assert_equal 14, API.last_insert_row_id( db )
|
123
|
+
|
124
|
+
API.close(db)
|
125
|
+
|
126
|
+
ensure
|
127
|
+
File.delete( "db/dummy.db" )
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_changes
|
131
|
+
db = API.open( "db/dummy.db", 0 )
|
132
|
+
|
133
|
+
vm, rest = API.compile( db, "create table Z ( a integer primary key, b varchar(60) )" )
|
134
|
+
API.step(vm)
|
135
|
+
API.finalize(vm)
|
136
|
+
|
137
|
+
vm, rest = API.compile( db, "insert into Z values ( 14, 'Hello' )" )
|
138
|
+
API.step(vm)
|
139
|
+
API.finalize(vm)
|
140
|
+
|
141
|
+
assert_equal 1, API.changes( db )
|
142
|
+
|
143
|
+
vm, rest = API.compile( db, "insert into Z values ( 15, 'Hello' )" )
|
144
|
+
API.step(vm)
|
145
|
+
API.finalize(vm)
|
146
|
+
|
147
|
+
vm, rest = API.compile( db, "delete from Z where 1" )
|
148
|
+
API.step(vm)
|
149
|
+
API.finalize(vm)
|
150
|
+
|
151
|
+
assert_equal 2, API.changes( db )
|
152
|
+
|
153
|
+
API.close(db)
|
154
|
+
|
155
|
+
ensure
|
156
|
+
File.delete( "db/dummy.db" )
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_complete
|
160
|
+
sql = "select * from"
|
161
|
+
assert !API.complete( sql )
|
162
|
+
sql << "a_table;"
|
163
|
+
assert API.complete( sql )
|
164
|
+
end
|
165
|
+
|
166
|
+
def test_create_function
|
167
|
+
db = API.open( "db/fixtures.db", 0 )
|
168
|
+
|
169
|
+
API.create_function( db, "maim", 1, proc { |func,arg| API.set_result( func, arg.split(//).sort.join ) } )
|
170
|
+
|
171
|
+
vm, rest = API.compile( db, "select maim(name) from A where name = 'Amber'" )
|
172
|
+
result = API.step( vm )
|
173
|
+
assert_equal "Abemr", result[:row][0]
|
174
|
+
API.finalize( vm )
|
175
|
+
|
176
|
+
API.close( db )
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_create_aggregate
|
180
|
+
db = API.open( "db/fixtures.db", 0 )
|
181
|
+
|
182
|
+
API.create_aggregate( db, "lengths", 1,
|
183
|
+
proc { |func,arg|
|
184
|
+
ctx = API.aggregate_context( func )
|
185
|
+
ctx[:count] = API.aggregate_count( func )
|
186
|
+
ctx[:len] ||= 0
|
187
|
+
ctx[:len] += ( arg.nil? ? 0 : arg.length )
|
188
|
+
},
|
189
|
+
proc { |func|
|
190
|
+
ctx = API.aggregate_context( func )
|
191
|
+
API.set_result( func, "#{ctx[:len] || 0}/#{ctx[:count] || 0}" )
|
192
|
+
} )
|
193
|
+
|
194
|
+
vm, rest = API.compile( db, "select lengths(name) from A" )
|
195
|
+
result = API.step( vm )
|
196
|
+
assert_equal "33/6", result[:row][0]
|
197
|
+
API.finalize( vm )
|
198
|
+
|
199
|
+
API.close( db )
|
200
|
+
end
|
201
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
#--
|
2
|
+
# =============================================================================
|
3
|
+
# Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
|
4
|
+
# All rights reserved.
|
5
|
+
#
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
7
|
+
# modification, are permitted provided that the following conditions are met:
|
8
|
+
#
|
9
|
+
# * Redistributions of source code must retain the above copyright notice,
|
10
|
+
# this list of conditions and the following disclaimer.
|
11
|
+
#
|
12
|
+
# * Redistributions in binary form must reproduce the above copyright
|
13
|
+
# notice, this list of conditions and the following disclaimer in the
|
14
|
+
# documentation and/or other materials provided with the distribution.
|
15
|
+
#
|
16
|
+
# * The names of its contributors may not be used to endorse or promote
|
17
|
+
# products derived from this software without specific prior written
|
18
|
+
# permission.
|
19
|
+
#
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
23
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
24
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
25
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
26
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
27
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
28
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
29
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
# =============================================================================
|
31
|
+
#++
|
32
|
+
|
33
|
+
$:.unshift "lib"
|
34
|
+
|
35
|
+
require 'sqlite'
|
36
|
+
require 'test/unit'
|
37
|
+
|
38
|
+
begin
|
39
|
+
|
40
|
+
require 'arrayfields'
|
41
|
+
|
42
|
+
class TC_ArrayFields < Test::Unit::TestCase
|
43
|
+
|
44
|
+
def setup
|
45
|
+
@db = SQLite::Database.open( "db/fixtures.db" )
|
46
|
+
@db.type_translation = true
|
47
|
+
end
|
48
|
+
|
49
|
+
def teardown
|
50
|
+
@db.close
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_fields
|
54
|
+
row = @db.get_first_row "select * from A"
|
55
|
+
assert_equal( [ "name", "age" ], row.fields )
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_name_access
|
59
|
+
row = @db.get_first_row "select * from A"
|
60
|
+
assert_equal( "Zephyr", row["name"] )
|
61
|
+
assert_equal( 1, row["age"] )
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_index_access
|
65
|
+
row = @db.get_first_row "select * from A"
|
66
|
+
assert_equal( "Zephyr", row[0] )
|
67
|
+
assert_equal( 1, row[1] )
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
rescue LoadError => e
|
73
|
+
puts "'arrayfields' does not appear to exist... skipping arrayfields integration test"
|
74
|
+
end
|
data/test/tc_database.rb
ADDED
@@ -0,0 +1,335 @@
|
|
1
|
+
#--
|
2
|
+
# =============================================================================
|
3
|
+
# Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
|
4
|
+
# All rights reserved.
|
5
|
+
#
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
7
|
+
# modification, are permitted provided that the following conditions are met:
|
8
|
+
#
|
9
|
+
# * Redistributions of source code must retain the above copyright notice,
|
10
|
+
# this list of conditions and the following disclaimer.
|
11
|
+
#
|
12
|
+
# * Redistributions in binary form must reproduce the above copyright
|
13
|
+
# notice, this list of conditions and the following disclaimer in the
|
14
|
+
# documentation and/or other materials provided with the distribution.
|
15
|
+
#
|
16
|
+
# * The names of its contributors may not be used to endorse or promote
|
17
|
+
# products derived from this software without specific prior written
|
18
|
+
# permission.
|
19
|
+
#
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
23
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
24
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
25
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
26
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
27
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
28
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
29
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
# =============================================================================
|
31
|
+
#++
|
32
|
+
|
33
|
+
$:.unshift "lib"
|
34
|
+
|
35
|
+
require 'sqlite'
|
36
|
+
require 'test/unit'
|
37
|
+
|
38
|
+
class TC_Database < Test::Unit::TestCase
|
39
|
+
|
40
|
+
def setup
|
41
|
+
@db = SQLite::Database.open( "db/fixtures.db" )
|
42
|
+
end
|
43
|
+
|
44
|
+
def teardown
|
45
|
+
@db.close
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_constants
|
49
|
+
assert_equal "constant", defined?( SQLite::Version::MAJOR )
|
50
|
+
assert_equal "constant", defined?( SQLite::Version::MINOR )
|
51
|
+
assert_equal "constant", defined?( SQLite::Version::TINY )
|
52
|
+
assert_equal "constant", defined?( SQLite::Version::STRING )
|
53
|
+
|
54
|
+
expected = [ SQLite::Version::MAJOR, SQLite::Version::MINOR,
|
55
|
+
SQLite::Version::TINY ].join( "." )
|
56
|
+
|
57
|
+
assert_equal expected, SQLite::Version::STRING
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_execute_no_block
|
61
|
+
rows = @db.execute( "select * from A order by name limit 2" )
|
62
|
+
|
63
|
+
assert_equal [ [nil, "6"], ["Amber", "5"] ], rows
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_execute_with_block
|
67
|
+
expect = [ [nil, "6"], ["Amber", "5"] ]
|
68
|
+
@db.execute( "select * from A order by name limit 2" ) do |row|
|
69
|
+
assert_equal expect.shift, row
|
70
|
+
end
|
71
|
+
assert expect.empty?
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_execute2_no_block
|
75
|
+
columns, *rows = @db.execute2( "select * from A order by name limit 2" )
|
76
|
+
|
77
|
+
assert_equal [ "name", "age" ], columns
|
78
|
+
assert_equal [ [nil, "6"], ["Amber", "5"] ], rows
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_execute2_with_block
|
82
|
+
expect = [ ["name", "age"], [nil, "6"], ["Amber", "5"] ]
|
83
|
+
@db.execute2( "select * from A order by name limit 2" ) do |row|
|
84
|
+
assert_equal expect.shift, row
|
85
|
+
end
|
86
|
+
assert expect.empty?
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_bind_vars
|
90
|
+
rows = @db.execute( "select * from A where name = ?", "Amber" )
|
91
|
+
assert_equal [ ["Amber", "5"] ], rows
|
92
|
+
rows = @db.execute( "select * from A where name = ?", 15 )
|
93
|
+
assert_equal [], rows
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_result_hash
|
97
|
+
@db.results_as_hash = true
|
98
|
+
rows = @db.execute( "select * from A where name = ?", "Amber" )
|
99
|
+
assert_equal [ {"name"=>"Amber", 0=>"Amber", "age"=>"5", 1=>"5"} ], rows
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_result_hash_types
|
103
|
+
@db.results_as_hash = true
|
104
|
+
rows = @db.execute( "select * from A where name = ?", "Amber" )
|
105
|
+
assert_equal [ "VARCHAR(60)", "INTEGER" ], rows[0].types
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_query
|
109
|
+
@db.query( "select * from A where name = ?", "Amber" ) do |result|
|
110
|
+
row = result.next
|
111
|
+
assert_equal [ "Amber", "5"], row
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_metadata
|
116
|
+
@db.query( "select * from A where name = ?", "Amber" ) do |result|
|
117
|
+
assert_equal [ "name", "age" ], result.columns
|
118
|
+
assert_equal [ "VARCHAR(60)", "INTEGER" ], result.types
|
119
|
+
assert_equal [ "Amber", "5"], result.next
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_get_first_row
|
124
|
+
row = @db.get_first_row( "select * from A order by name" )
|
125
|
+
assert_equal [ nil, "6" ], row
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_get_first_value
|
129
|
+
age = @db.get_first_value( "select age from A order by name" )
|
130
|
+
assert_equal "6", age
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_create_function
|
134
|
+
@db.create_function( "maim", 1 ) do |func, value|
|
135
|
+
if value.nil?
|
136
|
+
func.set_result nil
|
137
|
+
else
|
138
|
+
func.set_result value.split(//).sort.join
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
value = @db.get_first_value( "select maim(name) from A where name='Amber'" )
|
143
|
+
assert_equal "Abemr", value
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_create_aggregate
|
147
|
+
step = proc do |func, value|
|
148
|
+
func[ :total ] ||= 0
|
149
|
+
func[ :total ] += ( value ? value.length : 0 )
|
150
|
+
end
|
151
|
+
|
152
|
+
finalize = proc do |func|
|
153
|
+
func.set_result( func[ :total ] || 0 )
|
154
|
+
end
|
155
|
+
|
156
|
+
@db.create_aggregate( "lengths", 1, step, finalize )
|
157
|
+
|
158
|
+
value = @db.get_first_value( "select lengths(name) from A" )
|
159
|
+
assert_equal "33", value
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_set_error
|
163
|
+
@db.create_function( "barf", 1 ) do |func, value|
|
164
|
+
func.set_error "oops! I did it again"
|
165
|
+
end
|
166
|
+
|
167
|
+
assert_raise( SQLite::Exceptions::SQLException ) do
|
168
|
+
@db.get_first_value( "select barf(name) from A where name='Amber'" )
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_context_on_nonaggregate
|
173
|
+
@db.create_function( "barf1", 1 ) do |func, value|
|
174
|
+
assert_raise( SQLite::Exceptions::MisuseException ) do
|
175
|
+
func['hello']
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
@db.create_function( "barf2", 1 ) do |func, value|
|
180
|
+
assert_raise( SQLite::Exceptions::MisuseException ) do
|
181
|
+
func['hello'] = "world"
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
@db.create_function( "barf3", 1 ) do |func, value|
|
186
|
+
assert_raise( SQLite::Exceptions::MisuseException ) do
|
187
|
+
func.count
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
@db.get_first_value( "select barf1(name) from A where name='Amber'" )
|
192
|
+
@db.get_first_value( "select barf2(name) from A where name='Amber'" )
|
193
|
+
@db.get_first_value( "select barf3(name) from A where name='Amber'" )
|
194
|
+
end
|
195
|
+
|
196
|
+
class LengthsAggregate
|
197
|
+
def self.function_type
|
198
|
+
:numeric
|
199
|
+
end
|
200
|
+
|
201
|
+
def self.arity
|
202
|
+
1
|
203
|
+
end
|
204
|
+
|
205
|
+
def self.name
|
206
|
+
"lengths"
|
207
|
+
end
|
208
|
+
|
209
|
+
def initialize
|
210
|
+
@total = 0
|
211
|
+
end
|
212
|
+
|
213
|
+
def step( ctx, name )
|
214
|
+
@total += ( name ? name.length : 0 )
|
215
|
+
end
|
216
|
+
|
217
|
+
def finalize( ctx )
|
218
|
+
ctx.set_result( @total )
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def test_create_aggregate_handler
|
223
|
+
@db.create_aggregate_handler LengthsAggregate
|
224
|
+
|
225
|
+
result = @db.get_first_value( "select lengths(name) from A" )
|
226
|
+
assert_equal "33", result
|
227
|
+
end
|
228
|
+
|
229
|
+
def test_prepare
|
230
|
+
stmt = @db.prepare( "select * from A" )
|
231
|
+
assert_equal "", stmt.remainder
|
232
|
+
assert_equal [ "name", "age" ], stmt.columns
|
233
|
+
assert_equal [ "VARCHAR(60)", "INTEGER" ], stmt.types
|
234
|
+
stmt.execute do |result|
|
235
|
+
row = result.next
|
236
|
+
assert_equal [ "Zephyr", "1" ], row
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def test_execute_batch
|
241
|
+
count = @db.get_first_value( "select count(*) from A" ).to_i
|
242
|
+
|
243
|
+
@db.execute_batch( %q{--- query number one
|
244
|
+
insert into A ( age, name ) values ( 200, 'test' );
|
245
|
+
/* query number
|
246
|
+
* two */
|
247
|
+
insert into A ( age, name ) values ( 201, 'test2' );
|
248
|
+
insert into A ( age, name ) values ( 202, /* comment here */ 'test3' )} )
|
249
|
+
new_count = @db.get_first_value( "select count(*) from A" ).to_i
|
250
|
+
assert_equal 3, new_count - count
|
251
|
+
|
252
|
+
@db.execute_batch( %q{--- query number one
|
253
|
+
delete from A where age = 200;
|
254
|
+
/* query number
|
255
|
+
* two */
|
256
|
+
delete from A where age = 201;
|
257
|
+
delete from /* comment */ A where age = 202;} )
|
258
|
+
|
259
|
+
new_count = @db.get_first_value( "select count(*) from A" ).to_i
|
260
|
+
assert_equal new_count, count
|
261
|
+
end
|
262
|
+
|
263
|
+
def test_transaction_block_errors
|
264
|
+
assert_raise( SQLite::Exceptions::SQLException ) do
|
265
|
+
@db.transaction do
|
266
|
+
@db.commit
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
assert_raise( SQLite::Exceptions::SQLException ) do
|
271
|
+
@db.transaction do
|
272
|
+
@db.rollback
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
def test_transaction_errors
|
278
|
+
assert_raise( SQLite::Exceptions::SQLException ) do
|
279
|
+
@db.commit
|
280
|
+
end
|
281
|
+
assert_raise( SQLite::Exceptions::SQLException ) do
|
282
|
+
@db.rollback
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def test_transaction_block_good
|
287
|
+
count = @db.get_first_value( "select count(*) from A" ).to_i
|
288
|
+
begin
|
289
|
+
@db.transaction do |db|
|
290
|
+
assert @db.transaction_active?
|
291
|
+
db.execute( "insert into A values ( 'bogus', 1 )" )
|
292
|
+
sub_count = db.get_first_value( "select count(*) from A" ).to_i
|
293
|
+
assert_equal count+1, sub_count
|
294
|
+
raise "testing rollback..."
|
295
|
+
end
|
296
|
+
rescue Exception
|
297
|
+
end
|
298
|
+
new_count = @db.get_first_value( "select count(*) from A" ).to_i
|
299
|
+
assert_equal count, new_count
|
300
|
+
|
301
|
+
@db.transaction do |db|
|
302
|
+
db.execute( "insert into A values ( 'bogus', 1 )" )
|
303
|
+
sub_count = db.get_first_value( "select count(*) from A" ).to_i
|
304
|
+
assert_equal count+1, sub_count
|
305
|
+
end
|
306
|
+
new_count = @db.get_first_value( "select count(*) from A" ).to_i
|
307
|
+
assert_equal count+1, new_count
|
308
|
+
|
309
|
+
@db.execute( "delete from A where name = ?", "bogus" )
|
310
|
+
end
|
311
|
+
|
312
|
+
def test_transaction_explicit
|
313
|
+
count = @db.get_first_value( "select count(*) from A" ).to_i
|
314
|
+
|
315
|
+
@db.transaction
|
316
|
+
assert @db.transaction_active?
|
317
|
+
@db.execute( "insert into A values ( 'bogus', 1 )" )
|
318
|
+
sub_count = @db.get_first_value( "select count(*) from A" ).to_i
|
319
|
+
assert_equal count+1, sub_count
|
320
|
+
@db.rollback
|
321
|
+
sub_count = @db.get_first_value( "select count(*) from A" ).to_i
|
322
|
+
assert_equal count, sub_count
|
323
|
+
|
324
|
+
@db.transaction
|
325
|
+
@db.execute( "insert into A values ( 'bogus', 1 )" )
|
326
|
+
sub_count = @db.get_first_value( "select count(*) from A" ).to_i
|
327
|
+
assert_equal count+1, sub_count
|
328
|
+
@db.commit
|
329
|
+
sub_count = @db.get_first_value( "select count(*) from A" ).to_i
|
330
|
+
assert_equal count+1, sub_count
|
331
|
+
|
332
|
+
@db.execute( "delete from A where name = ?", "bogus" )
|
333
|
+
end
|
334
|
+
|
335
|
+
end
|