do_sqlite3 0.2.5 → 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README +2 -2
- data/Rakefile +46 -25
- data/TODO +4 -0
- data/ext/do_sqlite3_ext.c +538 -0
- data/ext/extconf.rb +28 -4
- data/lib/do_sqlite3.rb +4 -209
- data/lib/do_sqlite3/transaction.rb +36 -0
- data/spec/integration/do_sqlite3_spec.rb +244 -0
- data/spec/integration/logging_spec.rb +47 -0
- data/spec/integration/quoting_spec.rb +19 -0
- data/spec/spec_helper.rb +47 -0
- data/spec/unit/transaction_spec.rb +34 -0
- metadata +60 -48
- data/ext/sqlite3_c.c +0 -4725
- data/ext/sqlite_c.i +0 -168
data/ext/extconf.rb
CHANGED
@@ -1,11 +1,35 @@
|
|
1
|
-
ENV["RC_ARCHS"] = `uname -m`.chomp if `uname -sr` =~ /^Darwin/
|
1
|
+
# ENV["RC_ARCHS"] = `uname -m`.chomp if `uname -sr` =~ /^Darwin/
|
2
|
+
#
|
3
|
+
# require 'mkmf'
|
4
|
+
#
|
5
|
+
# SWIG_WRAP = "sqlite3_api_wrap.c"
|
6
|
+
#
|
7
|
+
# dir_config( "sqlite3", "/usr/local" )
|
8
|
+
#
|
9
|
+
# if have_header( "sqlite3.h" ) && have_library( "sqlite3", "sqlite3_open" )
|
10
|
+
# create_makefile( "sqlite3_c" )
|
11
|
+
# end
|
2
12
|
|
13
|
+
if RUBY_PLATFORM =~ /darwin/
|
14
|
+
ENV["RC_ARCHS"] = `uname -m`.chomp if `uname -sr` =~ /^Darwin/
|
15
|
+
|
16
|
+
# On PowerPC the defaults are fine
|
17
|
+
ENV["RC_ARCHS"] = '' if `uname -m` =~ /^Power Macintosh/
|
18
|
+
end
|
19
|
+
|
20
|
+
# Loads mkmf which is used to make makefiles for Ruby extensions
|
3
21
|
require 'mkmf'
|
4
22
|
|
5
|
-
|
23
|
+
# Give it a name
|
24
|
+
extension_name = 'do_sqlite3_ext'
|
25
|
+
|
26
|
+
dir_config("sqlite3")
|
6
27
|
|
7
|
-
|
28
|
+
# NOTE: use GCC flags unless Visual C compiler is used
|
29
|
+
$CFLAGS << ' -Wall ' unless RUBY_PLATFORM =~ /mswin/
|
8
30
|
|
31
|
+
# Do the work
|
32
|
+
# create_makefile(extension_name)
|
9
33
|
if have_header( "sqlite3.h" ) && have_library( "sqlite3", "sqlite3_open" )
|
10
|
-
create_makefile(
|
34
|
+
create_makefile(extension_name)
|
11
35
|
end
|
data/lib/do_sqlite3.rb
CHANGED
@@ -1,210 +1,5 @@
|
|
1
|
-
require 'sqlite3_c'
|
2
|
-
require 'data_objects'
|
3
|
-
|
4
|
-
module DataObject
|
5
|
-
module Sqlite3
|
6
|
-
|
7
|
-
QUOTE_STRING = "\""
|
8
|
-
QUOTE_COLUMN = "'"
|
9
|
-
|
10
|
-
class Connection < DataObject::Connection
|
11
|
-
|
12
|
-
attr_reader :db
|
13
|
-
|
14
|
-
def initialize(connection_string)
|
15
|
-
@state = STATE_CLOSED
|
16
|
-
@connection_string = connection_string
|
17
|
-
@conn = Hash[*connection_string.split(" ").map {|x| x.split("=")}.flatten]["dbname"]
|
18
|
-
end
|
19
|
-
|
20
|
-
def open
|
21
|
-
r, d = Sqlite3_c.sqlite3_open(@conn)
|
22
|
-
unless r == Sqlite3_c::SQLITE_OK
|
23
|
-
raise ConnectionFailed, "Unable to connect to database with provided connection string. \n#{Sqlite3_c.sqlite3_errmsg(d)}"
|
24
|
-
else
|
25
|
-
@db = d
|
26
|
-
end
|
27
|
-
@state = STATE_OPEN
|
28
|
-
true
|
29
|
-
end
|
30
|
-
|
31
|
-
def close
|
32
|
-
Sqlite3_c.sqlite3_close(@db)
|
33
|
-
@state = STATE_CLOSED
|
34
|
-
true
|
35
|
-
end
|
36
|
-
|
37
|
-
def create_command(text)
|
38
|
-
Command.new(self, text)
|
39
|
-
end
|
40
|
-
|
41
|
-
def begin_transaction
|
42
|
-
Transaction.new(self)
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
46
|
-
|
47
|
-
class Transaction < DataObject::Transaction
|
48
|
-
|
49
|
-
attr_reader :connection
|
50
|
-
|
51
|
-
def initialize(conn)
|
52
|
-
@connection = conn
|
53
|
-
exec_sql("BEGIN")
|
54
|
-
end
|
55
1
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
# Rolls back the transaction
|
62
|
-
def rollback(savepoint = nil)
|
63
|
-
raise NotImplementedError, "SQLite3 does not support savepoints" if savepoint
|
64
|
-
exec_sql("ROLLBACK")
|
65
|
-
end
|
66
|
-
|
67
|
-
# Creates a savepoint for rolling back later (not commonly supported)
|
68
|
-
def save(name)
|
69
|
-
raise NotImplementedError, "SQLite3 does not support savepoints"
|
70
|
-
end
|
71
|
-
|
72
|
-
def create_command(*args)
|
73
|
-
@connection.create_command(*args)
|
74
|
-
end
|
75
|
-
|
76
|
-
protected
|
77
|
-
|
78
|
-
def exec_sql(sql)
|
79
|
-
@connection.logger.debug { sql }
|
80
|
-
result, reader = Sqlite3_c.sqlite3_prepare_v2(@connection.db, sql, sql.size + 1)
|
81
|
-
exec_result = Sqlite3_c.sqlite3_step(reader)
|
82
|
-
Sqlite3_c.sqlite3_finalize(reader)
|
83
|
-
exec_result
|
84
|
-
end
|
85
|
-
|
86
|
-
end
|
87
|
-
|
88
|
-
class Reader < DataObject::Reader
|
89
|
-
|
90
|
-
def initialize(db, reader)
|
91
|
-
@reader = reader
|
92
|
-
result = Sqlite3_c.sqlite3_step(reader)
|
93
|
-
rows_affected, field_count = Sqlite3_c.sqlite3_changes(db), Sqlite3_c.sqlite3_column_count(reader)
|
94
|
-
if field_count == 0
|
95
|
-
@records_affected = rows_affected
|
96
|
-
close
|
97
|
-
else
|
98
|
-
@field_count = field_count
|
99
|
-
@fields, @field_types = [], []
|
100
|
-
i = 0
|
101
|
-
while(i < @field_count)
|
102
|
-
@field_types.push(Sqlite3_c.sqlite3_column_type(reader, i))
|
103
|
-
@fields.push(Sqlite3_c.sqlite3_column_name(reader, i))
|
104
|
-
i += 1
|
105
|
-
end
|
106
|
-
case result
|
107
|
-
when Sqlite3_c::SQLITE_BUSY, Sqlite3_c::SQLITE_ERROR, Sqlite3_c::SQLITE_MISUSE
|
108
|
-
raise ReaderError, "An error occurred while trying to get the next row\n#{Sqlite3_c.sqlite3_errmsg(db)}"
|
109
|
-
else
|
110
|
-
@has_rows = result == Sqlite3_c::SQLITE_ROW
|
111
|
-
@state = STATE_OPEN
|
112
|
-
close unless @has_rows
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
def real_close
|
118
|
-
Sqlite3_c.sqlite3_finalize(@reader)
|
119
|
-
end
|
120
|
-
|
121
|
-
def name(idx)
|
122
|
-
super
|
123
|
-
@fields[idx]
|
124
|
-
end
|
125
|
-
|
126
|
-
def get_index(name)
|
127
|
-
super
|
128
|
-
@fields.index(name)
|
129
|
-
end
|
130
|
-
|
131
|
-
def null?(idx)
|
132
|
-
super
|
133
|
-
item(idx).nil?
|
134
|
-
end
|
135
|
-
|
136
|
-
def item(idx)
|
137
|
-
super
|
138
|
-
case @field_types[idx]
|
139
|
-
when 1 # SQLITE_INTEGER
|
140
|
-
Sqlite3_c.sqlite3_column_int(@reader, idx).to_i
|
141
|
-
when 2 # SQLITE_FLOAT
|
142
|
-
Sqlite3_c.sqlite3_column_double(@reader, idx)
|
143
|
-
else
|
144
|
-
Sqlite3_c.sqlite3_column_text(@reader, idx)
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
def each
|
149
|
-
return unless has_rows?
|
150
|
-
|
151
|
-
while(true) do
|
152
|
-
yield
|
153
|
-
break unless Sqlite3_c.sqlite3_step(@reader) == Sqlite3_c::SQLITE_ROW
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
end
|
158
|
-
|
159
|
-
class Command < DataObject::Command
|
160
|
-
|
161
|
-
def execute_reader(*args)
|
162
|
-
super
|
163
|
-
sql = escape_sql(args)
|
164
|
-
@connection.logger.debug { sql }
|
165
|
-
result, ptr = Sqlite3_c.sqlite3_prepare_v2(@connection.db, sql, sql.size + 1)
|
166
|
-
unless result == Sqlite3_c::SQLITE_OK
|
167
|
-
raise QueryError, "Your query failed.\n#{Sqlite3_c.sqlite3_errmsg(@connection.db)}\nQUERY: \"#{sql}\""
|
168
|
-
else
|
169
|
-
reader = Reader.new(@connection.db, ptr)
|
170
|
-
|
171
|
-
if block_given?
|
172
|
-
return_value = yield(reader)
|
173
|
-
reader.close
|
174
|
-
return_value
|
175
|
-
else
|
176
|
-
reader
|
177
|
-
end
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
def execute_non_query(*args)
|
182
|
-
super
|
183
|
-
sql = escape_sql(args)
|
184
|
-
@connection.logger.debug { sql }
|
185
|
-
result, reader = Sqlite3_c.sqlite3_prepare_v2(@connection.db, sql, -1)
|
186
|
-
unless result == Sqlite3_c::SQLITE_OK
|
187
|
-
Sqlite3_c.sqlite3_finalize(reader)
|
188
|
-
raise QueryError, "Your query failed.\n#{Sqlite3_c.sqlite3_errmsg(@connection.db)}\nQUERY: \"#{sql}\""
|
189
|
-
else
|
190
|
-
exec_result = Sqlite3_c.sqlite3_step(reader)
|
191
|
-
Sqlite3_c.sqlite3_finalize(reader)
|
192
|
-
if exec_result == Sqlite3_c::SQLITE_DONE
|
193
|
-
ResultData.new(@connection, Sqlite3_c.sqlite3_changes(@connection.db), Sqlite3_c.sqlite3_last_insert_rowid(@connection.db))
|
194
|
-
else
|
195
|
-
raise QueryError, "Your query failed or you tried to execute a SELECT query through execute_non_reader\n#{Sqlite3_c.sqlite3_errmsg(@connection.db)}\nQUERY: \"#{@text}\""
|
196
|
-
end
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
def quote_symbol(value)
|
201
|
-
value.to_s
|
202
|
-
end
|
203
|
-
|
204
|
-
def quote_boolean(value)
|
205
|
-
value ? '1' : '0'
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
end
|
210
|
-
end
|
2
|
+
require 'rubygems'
|
3
|
+
require 'data_objects'
|
4
|
+
require 'do_sqlite3_ext'
|
5
|
+
require 'do_sqlite3/transaction'
|
@@ -0,0 +1,36 @@
|
|
1
|
+
|
2
|
+
module DataObjects
|
3
|
+
|
4
|
+
module Sqlite3
|
5
|
+
|
6
|
+
class Transaction < DataObjects::Transaction
|
7
|
+
|
8
|
+
def begin
|
9
|
+
cmd = "BEGIN"
|
10
|
+
connection.create_command(cmd).execute_non_query
|
11
|
+
end
|
12
|
+
|
13
|
+
def commit
|
14
|
+
cmd = "COMMIT"
|
15
|
+
connection.create_command(cmd).execute_non_query
|
16
|
+
end
|
17
|
+
|
18
|
+
def rollback
|
19
|
+
cmd = "ROLLBACK"
|
20
|
+
connection.create_command(cmd).execute_non_query
|
21
|
+
end
|
22
|
+
|
23
|
+
def rollback_prepared
|
24
|
+
cmd = "ROLLBACK"
|
25
|
+
connection.create_command(cmd).execute_non_query
|
26
|
+
end
|
27
|
+
|
28
|
+
def prepare
|
29
|
+
# Eek, I don't know how to do this. Lets hope a commit arrives soon...
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,244 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
|
3
|
+
|
4
|
+
describe "DataObjects::Sqlite3" do
|
5
|
+
include Sqlite3SpecHelpers
|
6
|
+
|
7
|
+
it "should raise error on bad connection string" do
|
8
|
+
lambda { DataObjects::Connection.new("sqlite3:///ac0d9iopalmsdcasd/asdc9pomasd/test.db") }.should raise_error("unable to open database file")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
NOW = DateTime.now
|
13
|
+
|
14
|
+
describe "DataObjects::Sqlite3::Result" do
|
15
|
+
include Sqlite3SpecHelpers
|
16
|
+
|
17
|
+
before(:all) do
|
18
|
+
@connection = DataObjects::Connection.new("sqlite3://#{File.expand_path(File.dirname(__FILE__))}/test.db")
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should raise an error for a bad query" do
|
22
|
+
command = @connection.create_command("INSER INTO table_which_doesnt_exist (id) VALUES (1)")
|
23
|
+
lambda { command.execute_non_query }.should raise_error('near "INSER": syntax error')
|
24
|
+
|
25
|
+
command = @connection.create_command("INSERT INTO table_which_doesnt_exist (id) VALUES (1)")
|
26
|
+
lambda { command.execute_non_query }.should raise_error("no such table: table_which_doesnt_exist")
|
27
|
+
|
28
|
+
command = @connection.create_command("SELECT * FROM table_which_doesnt_exist")
|
29
|
+
lambda { command.execute_reader }.should raise_error("no such table: table_which_doesnt_exist")
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return the affected rows and insert_id" do
|
33
|
+
command = @connection.create_command("DROP TABLE users")
|
34
|
+
command.execute_non_query rescue nil
|
35
|
+
command = @connection.create_command("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, type TEXT, age INTEGER, created_at DATETIME, balance DECIMAL default '0.00')")
|
36
|
+
result = command.execute_non_query
|
37
|
+
command = @connection.create_command("INSERT INTO users (name) VALUES ('test')")
|
38
|
+
result = command.execute_non_query
|
39
|
+
result.insert_id.should == 1
|
40
|
+
result.to_i.should == 1
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should do a reader query" do
|
44
|
+
command = @connection.create_command("SELECT * FROM users")
|
45
|
+
reader = command.execute_reader
|
46
|
+
|
47
|
+
lambda { reader.values }.should raise_error
|
48
|
+
|
49
|
+
while ( reader.next! )
|
50
|
+
lambda { reader.values }.should_not raise_error
|
51
|
+
reader.values.should be_a_kind_of(Array)
|
52
|
+
end
|
53
|
+
|
54
|
+
lambda { reader.values }.should raise_error
|
55
|
+
|
56
|
+
reader.close
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should do a paramaterized reader query" do
|
60
|
+
command = @connection.create_command("SELECT * FROM users WHERE id = ?")
|
61
|
+
reader = command.execute_reader(1)
|
62
|
+
reader.next!
|
63
|
+
|
64
|
+
reader.values[0].should == 1
|
65
|
+
|
66
|
+
reader.next!
|
67
|
+
|
68
|
+
lambda { reader.values }.should raise_error
|
69
|
+
|
70
|
+
reader.close
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should do a custom typecast reader" do
|
74
|
+
command = @connection.create_command("SELECT name, id FROM users")
|
75
|
+
command.set_types [String, String]
|
76
|
+
reader = command.execute_reader
|
77
|
+
|
78
|
+
while ( reader.next! )
|
79
|
+
reader.fields.should == ["name", "id"]
|
80
|
+
reader.values.each { |v| v.should be_a_kind_of(String) }
|
81
|
+
end
|
82
|
+
|
83
|
+
reader.close
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should handle a null value" do
|
88
|
+
id = insert("INSERT INTO users (name) VALUES (NULL)")
|
89
|
+
select("SELECT name from users WHERE name is null") do |reader|
|
90
|
+
reader.values[0].should == nil
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should not convert empty strings to null" do
|
95
|
+
id = insert("INSERT INTO users (name) VALUES ('')")
|
96
|
+
select("SELECT name FROM users WHERE id = ?", [String], id) do |reader|
|
97
|
+
reader.values.first.should == ''
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should raise an error when you pass too many or too few types for the expected result set" do
|
102
|
+
lambda { select("SELECT name, id FROM users", [String, Integer, String]) }.should raise_error(Sqlite3Error)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should do a custom typecast reader with Class" do
|
106
|
+
class Person; end
|
107
|
+
|
108
|
+
id = insert("INSERT INTO users (name, age, type) VALUES (?, ?, ?)", 'Sam', 30, Person)
|
109
|
+
|
110
|
+
select("SELECT name, age, type FROM users WHERE id = ?", [String, Integer, Class], id) do |reader|
|
111
|
+
reader.fields.should == ["name", "age", "type"]
|
112
|
+
reader.values.should == ["Sam", 30, Person]
|
113
|
+
end
|
114
|
+
|
115
|
+
exec("DELETE FROM users WHERE id = ?", id)
|
116
|
+
end
|
117
|
+
|
118
|
+
[
|
119
|
+
NOW.strftime('%Y-%m-%dT%H:%M:%S'),
|
120
|
+
NOW.strftime('%Y-%m-%d %H:%M:%S')
|
121
|
+
].each do |raw_value|
|
122
|
+
it "should return #{NOW.to_s} using the LOCAL timezone when typecasting '#{raw_value}'" do
|
123
|
+
|
124
|
+
# Insert a timezone-less DateTime into the DB
|
125
|
+
id = insert("INSERT INTO users (name, age, type, created_at) VALUES (?, ?, ?, ?)", 'Sam', 30, Person, raw_value)
|
126
|
+
|
127
|
+
select("SELECT created_at FROM users WHERE id = ?", [DateTime], id) do |reader|
|
128
|
+
reader.values.last.to_s.should == NOW.to_s
|
129
|
+
end
|
130
|
+
|
131
|
+
exec("DELETE FROM users WHERE id = ?", id)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should return DateTimes using the same timezone that was used to insert it" do
|
136
|
+
pending "improved support for timezone checking"
|
137
|
+
|
138
|
+
dates = [
|
139
|
+
NOW,
|
140
|
+
NOW.new_offset( (-11 * 3600).to_r / 86400), # GMT -11:00
|
141
|
+
NOW.new_offset( (-9 * 3600 + 10 * 60).to_r / 86400), # GMT -9:10
|
142
|
+
NOW.new_offset( (-8 * 3600).to_r / 86400), # GMT -08:00
|
143
|
+
NOW.new_offset( (+3 * 3600).to_r / 86400), # GMT +03:00
|
144
|
+
NOW.new_offset( (+5 * 3600 + 30 * 60).to_r / 86400) # GMT +05:30 (New Delhi)
|
145
|
+
]
|
146
|
+
|
147
|
+
dates.each do |date|
|
148
|
+
id = insert("INSERT INTO users (name, age, type, created_at) VALUES (?, ?, ?, ?)", 'Sam', 30, Person, date)
|
149
|
+
|
150
|
+
select("SELECT created_at FROM users WHERE id = ?", [DateTime], id) do |reader|
|
151
|
+
reader.values.last.year.should == date.year
|
152
|
+
reader.values.last.month.should == date.month
|
153
|
+
reader.values.last.day.should == date.day
|
154
|
+
reader.values.last.hour.should == date.hour
|
155
|
+
reader.values.last.min.should == date.min
|
156
|
+
reader.values.last.sec.should == date.sec
|
157
|
+
reader.values.last.zone.should == date.zone
|
158
|
+
end
|
159
|
+
|
160
|
+
exec("DELETE FROM users WHERE id = ?", id)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should return a BigDecimal" do
|
165
|
+
balance = BigDecimal.new('10000000000.00')
|
166
|
+
|
167
|
+
id = insert("INSERT INTO users (name, age, type, created_at, balance) VALUES (?, ?, ?, ?, ?)", 'Scott', 27, Person, DateTime.now, balance)
|
168
|
+
|
169
|
+
select("SELECT balance FROM users WHERE id = ?", [BigDecimal], id) do |reader|
|
170
|
+
reader.values.last.should == balance
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe "quoting" do
|
175
|
+
|
176
|
+
before do
|
177
|
+
@connection.create_command("DROP TABLE IF EXISTS sail_boats").execute_non_query
|
178
|
+
@connection.create_command("CREATE TABLE sail_boats ( id INTEGER PRIMARY KEY, name VARCHAR(50), port VARCHAR(50), notes VARCHAR(50), vintage BOOLEAN )").execute_non_query
|
179
|
+
command = @connection.create_command("INSERT INTO sail_boats (id, name, port, name, vintage) VALUES (?, ?, ?, ?, ?)")
|
180
|
+
command.execute_non_query(1, "A", "C", "Fortune Pig!", false)
|
181
|
+
command.execute_non_query(2, "B", "B", "Happy Cow!", true)
|
182
|
+
command.execute_non_query(3, "C", "A", "Spoon", true)
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should quote a String" do
|
186
|
+
command = @connection.create_command("INSERT INTO users (name) VALUES (?)")
|
187
|
+
result = command.execute_non_query("John Doe")
|
188
|
+
result.to_i.should == 1
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should quote multiple values" do
|
192
|
+
command = @connection.create_command("INSERT INTO users (name, age) VALUES (?, ?)")
|
193
|
+
result = command.execute_non_query("Sam Smoot", 1)
|
194
|
+
result.to_i.should == 1
|
195
|
+
end
|
196
|
+
|
197
|
+
|
198
|
+
it "should handle boolean columns gracefully" do
|
199
|
+
command = @connection.create_command("INSERT INTO sail_boats (id, name, port, name, vintage) VALUES (?, ?, ?, ?, ?)")
|
200
|
+
result = command.execute_non_query(4, "Scooner", "Port au Prince", "This is one gangster boat!", true)
|
201
|
+
result.to_i.should == 1
|
202
|
+
end
|
203
|
+
|
204
|
+
it "should quote an Array" do
|
205
|
+
command = @connection.create_command("SELECT id, notes FROM sail_boats WHERE (id IN ?)")
|
206
|
+
reader = command.execute_reader([1, 2, 3])
|
207
|
+
|
208
|
+
i = 1
|
209
|
+
while(reader.next!)
|
210
|
+
reader.values[0].should == i
|
211
|
+
i += 1
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should quote an Array with NULL values returned" do
|
216
|
+
command = @connection.create_command("SELECT id, NULL AS notes FROM sail_boats WHERE (id IN ?)")
|
217
|
+
reader = command.execute_reader([1, 2, 3])
|
218
|
+
|
219
|
+
i = 1
|
220
|
+
while(reader.next!)
|
221
|
+
reader.values[0].should == i
|
222
|
+
i += 1
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
it "should quote an Array with NULL values returned AND set_types called" do
|
227
|
+
command = @connection.create_command("SELECT id, NULL AS notes FROM sail_boats WHERE (id IN ?)")
|
228
|
+
command.set_types [ Integer, String ]
|
229
|
+
|
230
|
+
reader = command.execute_reader([1, 2, 3])
|
231
|
+
|
232
|
+
i = 1
|
233
|
+
while(reader.next!)
|
234
|
+
reader.values[0].should == i
|
235
|
+
i += 1
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
after do
|
240
|
+
@connection.create_command("DROP TABLE sail_boats").execute_non_query
|
241
|
+
end
|
242
|
+
|
243
|
+
end # describe "quoting"
|
244
|
+
end
|