sqlite3-fiddle 1.0.0
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 +7 -0
- data/.gitignore +9 -0
- data/.ruby-version +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/LICENSE +28 -0
- data/README.md +46 -0
- data/Rakefile +9 -0
- data/lib/.DS_Store +0 -0
- data/lib/sqlite3.rb +9 -0
- data/lib/sqlite3/backup.rb +26 -0
- data/lib/sqlite3/constants.rb +140 -0
- data/lib/sqlite3/database.rb +823 -0
- data/lib/sqlite3/driver.rb +115 -0
- data/lib/sqlite3/pragmas.rb +280 -0
- data/lib/sqlite3/resultset.rb +158 -0
- data/lib/sqlite3/statement.rb +290 -0
- data/lib/sqlite3/value.rb +71 -0
- data/lib/sqlite3/version.rb +10 -0
- data/sqlite3-fiddle.gemspec +25 -0
- metadata +105 -0
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'fiddle'
|
2
|
+
require 'fiddle/import'
|
3
|
+
|
4
|
+
module SQLite3
|
5
|
+
module Driver
|
6
|
+
extend Fiddle::Importer
|
7
|
+
|
8
|
+
if path = $LIBSQLITE3 || ENV['LIBSQLITE3']
|
9
|
+
dlload path
|
10
|
+
else
|
11
|
+
dlload 'libsqlite3.dylib' rescue begin
|
12
|
+
dlload 'libsqlite3.so' rescue begin
|
13
|
+
dlload 'libsqlite3.dll' rescue fail('Unable to find libsqlite3, set ' +
|
14
|
+
'the global $LIBSQLITE3 or the environment variable LIBSQLITE3')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
extern 'const char *sqlite3_libversion()'
|
20
|
+
extern 'int sqlite3_busy_timeout(void*, int)'
|
21
|
+
extern 'int sqlite3_open_v2(const char *, sqlite3 **, int, const char *)'
|
22
|
+
extern 'int sqlite3_open16(const void *,sqlite3 **)'
|
23
|
+
extern 'int sqlite3_close(sqlite3*)'
|
24
|
+
extern 'int sqlite3_changes(void*)'
|
25
|
+
extern 'int sqlite3_total_changes(sqlite3*)'
|
26
|
+
extern 'long long sqlite3_last_insert_rowid(void*)'
|
27
|
+
extern 'int sqlite3_prepare_v2(void*, void*, int, void*, void*)'
|
28
|
+
extern 'int sqlite3_step(void*)'
|
29
|
+
extern 'int sqlite3_finalize(void*)'
|
30
|
+
extern 'int sqlite3_reset(void *)'
|
31
|
+
extern 'int sqlite3_clear_bindings(void*)'
|
32
|
+
extern 'int sqlite3_bind_parameter_count(void*)'
|
33
|
+
extern 'int sqlite3_column_count(void*)'
|
34
|
+
extern 'const char *sqlite3_column_name(void*, int)' rescue nil
|
35
|
+
extern 'const char *sqlite3_column_decltype(void*, int)'
|
36
|
+
extern 'const char *sqlite3_column_database_name(void*,int)' rescue nil
|
37
|
+
extern 'const char *sqlite3_column_table_name(void*,int)' rescue nil
|
38
|
+
extern 'const char *sqlite3_column_origin_name(void*,int)' rescue nil
|
39
|
+
extern 'int sqlite3_column_type(void*, int)'
|
40
|
+
extern 'const void *sqlite3_column_blob(void*, int)'
|
41
|
+
extern 'int sqlite3_column_bytes(void*, int)'
|
42
|
+
extern 'double sqlite3_column_double(void*, int)'
|
43
|
+
extern 'long long sqlite3_column_int64(void*, int)'
|
44
|
+
extern 'const unsigned char *sqlite3_column_text(void*, int)'
|
45
|
+
extern 'int sqlite3_bind_blob(void*, int, const void*, int, void*)'
|
46
|
+
extern 'int sqlite3_bind_double(void*, int, double)'
|
47
|
+
extern 'int sqlite3_bind_int64(void*, int, long long)'
|
48
|
+
extern 'int sqlite3_bind_null(void*, int)'
|
49
|
+
extern 'int sqlite3_bind_text(void*,int,const char*,int,void*)'
|
50
|
+
extern 'int sqlite3_bind_text16(void*,int,const char*,int,void*)'
|
51
|
+
extern 'int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *)'
|
52
|
+
extern 'int sqlite3_errcode(sqlite3 *)'
|
53
|
+
extern 'int sqlite3_complete(const char *)'
|
54
|
+
extern 'int sqlite3_get_autocommit(sqlite3*)'
|
55
|
+
extern 'int sqlite3_db_readonly(sqlite3 *, const char *)'
|
56
|
+
extern 'const char *sqlite3_errmsg(sqlite3*)'
|
57
|
+
extern 'void *sqlite3_trace(void*, void*, void*)'
|
58
|
+
extern 'int sqlite3_set_authorizer(sqlite3*, void*, void*)'
|
59
|
+
extern 'const void *sqlite3_value_blob(sqlite3_value*)'
|
60
|
+
extern 'int sqlite3_value_bytes(sqlite3_value*)'
|
61
|
+
extern 'int sqlite3_value_bytes16(sqlite3_value*)'
|
62
|
+
extern 'double sqlite3_value_double(sqlite3_value*)'
|
63
|
+
extern 'int sqlite3_value_int(sqlite3_value*)'
|
64
|
+
extern 'long long sqlite3_value_int64(sqlite3_value*)'
|
65
|
+
extern 'const unsigned char *sqlite3_value_text(sqlite3_value*)'
|
66
|
+
extern 'const void *sqlite3_value_text16(sqlite3_value*)'
|
67
|
+
extern 'const void *sqlite3_value_text16le(sqlite3_value*)'
|
68
|
+
extern 'const void *sqlite3_value_text16be(sqlite3_value*)'
|
69
|
+
extern 'int sqlite3_value_type(sqlite3_value*)'
|
70
|
+
extern 'int sqlite3_value_numeric_type(sqlite3_value*)'
|
71
|
+
extern 'void sqlite3_result_blob(sqlite3_context*, const void*, int, void*)'
|
72
|
+
extern 'void sqlite3_result_double(sqlite3_context*, double)'
|
73
|
+
extern 'void sqlite3_result_error(sqlite3_context*, const char*, int)'
|
74
|
+
extern 'void sqlite3_result_int(sqlite3_context*, int)'
|
75
|
+
extern 'void sqlite3_result_int64(sqlite3_context*, long long)'
|
76
|
+
extern 'void sqlite3_result_null(sqlite3_context*)'
|
77
|
+
extern 'void sqlite3_result_text(sqlite3_context*, const char*, int, void*)'
|
78
|
+
extern 'void sqlite3_result_text16(sqlite3_context*, const char*, int, void*)'
|
79
|
+
extern 'int sqlite3_create_function(sqlite3 *,const char *,int,int,void*,void*,void*,void*)'
|
80
|
+
extern 'void *sqlite3_user_data(sqlite3_context*)'
|
81
|
+
extern 'void sqlite3_interrupt(sqlite3*)'
|
82
|
+
extern 'int sqlite3_busy_handler(sqlite3*, void*, void*)'
|
83
|
+
extern 'int sqlite3_create_collation(sqlite3*,const char *,int,void *,void*)'
|
84
|
+
extern 'const char *sqlite3_errmsg(sqlite3*)'
|
85
|
+
extern 'sqlite3_backup *sqlite3_backup_init(sqlite3 *, const char *, sqlite3 *, const char *)'
|
86
|
+
extern 'int sqlite3_backup_step(sqlite3_backup *, int)'
|
87
|
+
extern 'int sqlite3_backup_finish(sqlite3_backup *)'
|
88
|
+
extern 'int sqlite3_backup_remaining(sqlite3_backup *)'
|
89
|
+
extern 'int sqlite3_backup_pagecount(sqlite3_backup *)'
|
90
|
+
|
91
|
+
def self.set_context_result(ctx, var)
|
92
|
+
case var
|
93
|
+
when Blob
|
94
|
+
Driver.sqlite3_result_blob(ctx, var.to_s, var.to_s.size, nil)
|
95
|
+
when String
|
96
|
+
if var.encoding == Encoding::UTF_16LE ||
|
97
|
+
var.encoding == Encoding::UTF_16BE
|
98
|
+
Driver.sqlite3_result_text16(ctx, var, -1, nil)
|
99
|
+
else
|
100
|
+
Driver.sqlite3_result_text(ctx, var.encode(Encoding::UTF_8), -1, nil)
|
101
|
+
end
|
102
|
+
when Fixnum, Bignum
|
103
|
+
Driver.sqlite3_result_int64(ctx, var)
|
104
|
+
when Float
|
105
|
+
Driver.sqlite3_result_double(ctx, var)
|
106
|
+
when NilClass
|
107
|
+
Driver.sqlite3_result_null(ctx)
|
108
|
+
when TrueClass, FalseClass
|
109
|
+
Driver.sqlite3_result_int(ctx, var ? 1 : 0)
|
110
|
+
else
|
111
|
+
raise RuntimeError, "can't return #{var.class}"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,280 @@
|
|
1
|
+
require 'sqlite3/constants'
|
2
|
+
|
3
|
+
module SQLite3
|
4
|
+
|
5
|
+
# This module is intended for inclusion solely by the Database class. It
|
6
|
+
# defines convenience methods for the various pragmas supported by SQLite3.
|
7
|
+
#
|
8
|
+
# For a detailed description of these pragmas, see the SQLite3 documentation
|
9
|
+
# at http://sqlite.org/pragma.html.
|
10
|
+
module Pragmas
|
11
|
+
|
12
|
+
# Returns +true+ or +false+ depending on the value of the named pragma.
|
13
|
+
def get_boolean_pragma( name )
|
14
|
+
get_first_value( "PRAGMA #{name}" ) != "0"
|
15
|
+
end
|
16
|
+
private :get_boolean_pragma
|
17
|
+
|
18
|
+
# Sets the given pragma to the given boolean value. The value itself
|
19
|
+
# may be +true+ or +false+, or any other commonly used string or
|
20
|
+
# integer that represents truth.
|
21
|
+
def set_boolean_pragma( name, mode )
|
22
|
+
case mode
|
23
|
+
when String
|
24
|
+
case mode.downcase
|
25
|
+
when "on", "yes", "true", "y", "t"; mode = "'ON'"
|
26
|
+
when "off", "no", "false", "n", "f"; mode = "'OFF'"
|
27
|
+
else
|
28
|
+
raise Exception,
|
29
|
+
"unrecognized pragma parameter #{mode.inspect}"
|
30
|
+
end
|
31
|
+
when true, 1
|
32
|
+
mode = "ON"
|
33
|
+
when false, 0, nil
|
34
|
+
mode = "OFF"
|
35
|
+
else
|
36
|
+
raise Exception,
|
37
|
+
"unrecognized pragma parameter #{mode.inspect}"
|
38
|
+
end
|
39
|
+
|
40
|
+
execute( "PRAGMA #{name}=#{mode}" )
|
41
|
+
end
|
42
|
+
private :set_boolean_pragma
|
43
|
+
|
44
|
+
# Requests the given pragma (and parameters), and if the block is given,
|
45
|
+
# each row of the result set will be yielded to it. Otherwise, the results
|
46
|
+
# are returned as an array.
|
47
|
+
def get_query_pragma( name, *parms, &block ) # :yields: row
|
48
|
+
if parms.empty?
|
49
|
+
execute( "PRAGMA #{name}", &block )
|
50
|
+
else
|
51
|
+
args = "'" + parms.join("','") + "'"
|
52
|
+
execute( "PRAGMA #{name}( #{args} )", &block )
|
53
|
+
end
|
54
|
+
end
|
55
|
+
private :get_query_pragma
|
56
|
+
|
57
|
+
# Return the value of the given pragma.
|
58
|
+
def get_enum_pragma( name )
|
59
|
+
get_first_value( "PRAGMA #{name}" )
|
60
|
+
end
|
61
|
+
private :get_enum_pragma
|
62
|
+
|
63
|
+
# Set the value of the given pragma to +mode+. The +mode+ parameter must
|
64
|
+
# conform to one of the values in the given +enum+ array. Each entry in
|
65
|
+
# the array is another array comprised of elements in the enumeration that
|
66
|
+
# have duplicate values. See #synchronous, #default_synchronous,
|
67
|
+
# #temp_store, and #default_temp_store for usage examples.
|
68
|
+
def set_enum_pragma( name, mode, enums )
|
69
|
+
match = enums.find { |p| p.find { |i| i.to_s.downcase == mode.to_s.downcase } }
|
70
|
+
raise Exception,
|
71
|
+
"unrecognized #{name} #{mode.inspect}" unless match
|
72
|
+
execute( "PRAGMA #{name}='#{match.first.upcase}'" )
|
73
|
+
end
|
74
|
+
private :set_enum_pragma
|
75
|
+
|
76
|
+
# Returns the value of the given pragma as an integer.
|
77
|
+
def get_int_pragma( name )
|
78
|
+
get_first_value( "PRAGMA #{name}" ).to_i
|
79
|
+
end
|
80
|
+
private :get_int_pragma
|
81
|
+
|
82
|
+
# Set the value of the given pragma to the integer value of the +value+
|
83
|
+
# parameter.
|
84
|
+
def set_int_pragma( name, value )
|
85
|
+
execute( "PRAGMA #{name}=#{value.to_i}" )
|
86
|
+
end
|
87
|
+
private :set_int_pragma
|
88
|
+
|
89
|
+
# The enumeration of valid synchronous modes.
|
90
|
+
SYNCHRONOUS_MODES = [ [ 'full', 2 ], [ 'normal', 1 ], [ 'off', 0 ] ]
|
91
|
+
|
92
|
+
# The enumeration of valid temp store modes.
|
93
|
+
TEMP_STORE_MODES = [ [ 'default', 0 ], [ 'file', 1 ], [ 'memory', 2 ] ]
|
94
|
+
|
95
|
+
# Does an integrity check on the database. If the check fails, a
|
96
|
+
# SQLite3::Exception will be raised. Otherwise it
|
97
|
+
# returns silently.
|
98
|
+
def integrity_check
|
99
|
+
execute( "PRAGMA integrity_check" ) do |row|
|
100
|
+
raise Exception, row[0] if row[0] != "ok"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def auto_vacuum
|
105
|
+
get_boolean_pragma "auto_vacuum"
|
106
|
+
end
|
107
|
+
|
108
|
+
def auto_vacuum=( mode )
|
109
|
+
set_boolean_pragma "auto_vacuum", mode
|
110
|
+
end
|
111
|
+
|
112
|
+
def schema_cookie
|
113
|
+
get_int_pragma "schema_cookie"
|
114
|
+
end
|
115
|
+
|
116
|
+
def schema_cookie=( cookie )
|
117
|
+
set_int_pragma "schema_cookie", cookie
|
118
|
+
end
|
119
|
+
|
120
|
+
def user_cookie
|
121
|
+
get_int_pragma "user_cookie"
|
122
|
+
end
|
123
|
+
|
124
|
+
def user_cookie=( cookie )
|
125
|
+
set_int_pragma "user_cookie", cookie
|
126
|
+
end
|
127
|
+
|
128
|
+
def cache_size
|
129
|
+
get_int_pragma "cache_size"
|
130
|
+
end
|
131
|
+
|
132
|
+
def cache_size=( size )
|
133
|
+
set_int_pragma "cache_size", size
|
134
|
+
end
|
135
|
+
|
136
|
+
def default_cache_size
|
137
|
+
get_int_pragma "default_cache_size"
|
138
|
+
end
|
139
|
+
|
140
|
+
def default_cache_size=( size )
|
141
|
+
set_int_pragma "default_cache_size", size
|
142
|
+
end
|
143
|
+
|
144
|
+
def default_synchronous
|
145
|
+
get_enum_pragma "default_synchronous"
|
146
|
+
end
|
147
|
+
|
148
|
+
def default_synchronous=( mode )
|
149
|
+
set_enum_pragma "default_synchronous", mode, SYNCHRONOUS_MODES
|
150
|
+
end
|
151
|
+
|
152
|
+
def synchronous
|
153
|
+
get_enum_pragma "synchronous"
|
154
|
+
end
|
155
|
+
|
156
|
+
def synchronous=( mode )
|
157
|
+
set_enum_pragma "synchronous", mode, SYNCHRONOUS_MODES
|
158
|
+
end
|
159
|
+
|
160
|
+
def default_temp_store
|
161
|
+
get_enum_pragma "default_temp_store"
|
162
|
+
end
|
163
|
+
|
164
|
+
def default_temp_store=( mode )
|
165
|
+
set_enum_pragma "default_temp_store", mode, TEMP_STORE_MODES
|
166
|
+
end
|
167
|
+
|
168
|
+
def temp_store
|
169
|
+
get_enum_pragma "temp_store"
|
170
|
+
end
|
171
|
+
|
172
|
+
def temp_store=( mode )
|
173
|
+
set_enum_pragma "temp_store", mode, TEMP_STORE_MODES
|
174
|
+
end
|
175
|
+
|
176
|
+
def full_column_names
|
177
|
+
get_boolean_pragma "full_column_names"
|
178
|
+
end
|
179
|
+
|
180
|
+
def full_column_names=( mode )
|
181
|
+
set_boolean_pragma "full_column_names", mode
|
182
|
+
end
|
183
|
+
|
184
|
+
def parser_trace
|
185
|
+
get_boolean_pragma "parser_trace"
|
186
|
+
end
|
187
|
+
|
188
|
+
def parser_trace=( mode )
|
189
|
+
set_boolean_pragma "parser_trace", mode
|
190
|
+
end
|
191
|
+
|
192
|
+
def vdbe_trace
|
193
|
+
get_boolean_pragma "vdbe_trace"
|
194
|
+
end
|
195
|
+
|
196
|
+
def vdbe_trace=( mode )
|
197
|
+
set_boolean_pragma "vdbe_trace", mode
|
198
|
+
end
|
199
|
+
|
200
|
+
def database_list( &block ) # :yields: row
|
201
|
+
get_query_pragma "database_list", &block
|
202
|
+
end
|
203
|
+
|
204
|
+
def foreign_key_list( table, &block ) # :yields: row
|
205
|
+
get_query_pragma "foreign_key_list", table, &block
|
206
|
+
end
|
207
|
+
|
208
|
+
def index_info( index, &block ) # :yields: row
|
209
|
+
get_query_pragma "index_info", index, &block
|
210
|
+
end
|
211
|
+
|
212
|
+
def index_list( table, &block ) # :yields: row
|
213
|
+
get_query_pragma "index_list", table, &block
|
214
|
+
end
|
215
|
+
|
216
|
+
###
|
217
|
+
# Returns information about +table+. Yields each row of table information
|
218
|
+
# if a block is provided.
|
219
|
+
def table_info table
|
220
|
+
stmt = prepare "PRAGMA table_info(#{table})"
|
221
|
+
columns = stmt.columns
|
222
|
+
|
223
|
+
needs_tweak_default =
|
224
|
+
version_compare(SQLite3.libversion.to_s, "3.3.7") > 0
|
225
|
+
|
226
|
+
result = [] unless block_given?
|
227
|
+
stmt.each do |row|
|
228
|
+
new_row = Hash[columns.zip(row)]
|
229
|
+
|
230
|
+
# FIXME: This should be removed but is required for older versions
|
231
|
+
# of rails
|
232
|
+
if(Object.const_defined?(:ActiveRecord))
|
233
|
+
new_row['notnull'] = new_row['notnull'].to_s
|
234
|
+
end
|
235
|
+
|
236
|
+
tweak_default(new_row) if needs_tweak_default
|
237
|
+
|
238
|
+
if block_given?
|
239
|
+
yield new_row
|
240
|
+
else
|
241
|
+
result << new_row
|
242
|
+
end
|
243
|
+
end
|
244
|
+
stmt.close
|
245
|
+
|
246
|
+
result
|
247
|
+
end
|
248
|
+
|
249
|
+
private
|
250
|
+
|
251
|
+
# Compares two version strings
|
252
|
+
def version_compare(v1, v2)
|
253
|
+
v1 = v1.split(".").map { |i| i.to_i }
|
254
|
+
v2 = v2.split(".").map { |i| i.to_i }
|
255
|
+
parts = [v1.length, v2.length].max
|
256
|
+
v1.push 0 while v1.length < parts
|
257
|
+
v2.push 0 while v2.length < parts
|
258
|
+
v1.zip(v2).each do |a,b|
|
259
|
+
return -1 if a < b
|
260
|
+
return 1 if a > b
|
261
|
+
end
|
262
|
+
return 0
|
263
|
+
end
|
264
|
+
|
265
|
+
# Since SQLite 3.3.8, the table_info pragma has returned the default
|
266
|
+
# value of the row as a quoted SQL value. This method essentially
|
267
|
+
# unquotes those values.
|
268
|
+
def tweak_default(hash)
|
269
|
+
case hash["dflt_value"]
|
270
|
+
when /^null$/i
|
271
|
+
hash["dflt_value"] = nil
|
272
|
+
when /^'(.*)'$/m
|
273
|
+
hash["dflt_value"] = $1.gsub(/''/, "'")
|
274
|
+
when /^"(.*)"$/m
|
275
|
+
hash["dflt_value"] = $1.gsub(/""/, '"')
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
module SQLite3
|
2
|
+
|
3
|
+
# The ResultSet object encapsulates the enumerability of a query's output.
|
4
|
+
# It is a simple cursor over the data that the query returns. It will
|
5
|
+
# very rarely (if ever) be instantiated directly. Instead, clients should
|
6
|
+
# obtain a ResultSet instance via Statement#execute.
|
7
|
+
class ResultSet
|
8
|
+
include Enumerable
|
9
|
+
|
10
|
+
class ArrayWithTypes < Array # :nodoc:
|
11
|
+
attr_accessor :types
|
12
|
+
end
|
13
|
+
|
14
|
+
class ArrayWithTypesAndFields < Array # :nodoc:
|
15
|
+
attr_writer :types
|
16
|
+
attr_writer :fields
|
17
|
+
|
18
|
+
def types
|
19
|
+
@types
|
20
|
+
end
|
21
|
+
|
22
|
+
def fields
|
23
|
+
@fields
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# The class of which we return an object in case we want a Hash as
|
28
|
+
# result.
|
29
|
+
class HashWithTypesAndFields < Hash # :nodoc:
|
30
|
+
attr_writer :types
|
31
|
+
attr_writer :fields
|
32
|
+
|
33
|
+
def types
|
34
|
+
@types
|
35
|
+
end
|
36
|
+
|
37
|
+
def fields
|
38
|
+
@fields
|
39
|
+
end
|
40
|
+
|
41
|
+
def [] key
|
42
|
+
key = fields[key] if key.is_a? Numeric
|
43
|
+
super key
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Create a new ResultSet attached to the given database, using the
|
48
|
+
# given sql text.
|
49
|
+
def initialize db, stmt
|
50
|
+
@db = db
|
51
|
+
@stmt = stmt
|
52
|
+
end
|
53
|
+
|
54
|
+
# Reset the cursor, so that a result set which has reached end-of-file
|
55
|
+
# can be rewound and reiterated.
|
56
|
+
def reset( *bind_params )
|
57
|
+
must_be_open!
|
58
|
+
@stmt.reset!
|
59
|
+
@stmt.bind_params( *bind_params )
|
60
|
+
@eof = false
|
61
|
+
end
|
62
|
+
|
63
|
+
# Query whether the cursor has reached the end of the result set or not.
|
64
|
+
def eof?
|
65
|
+
@stmt.done?
|
66
|
+
end
|
67
|
+
|
68
|
+
# Obtain the next row from the cursor. If there are no more rows to be
|
69
|
+
# had, this will return +nil+. If type translation is active on the
|
70
|
+
# corresponding database, the values in the row will be translated
|
71
|
+
# according to their types.
|
72
|
+
#
|
73
|
+
# The returned value will be an array, unless Database#results_as_hash has
|
74
|
+
# been set to +true+, in which case the returned value will be a hash.
|
75
|
+
#
|
76
|
+
# For arrays, the column names are accessible via the +fields+ property,
|
77
|
+
# and the column types are accessible via the +types+ property.
|
78
|
+
#
|
79
|
+
# For hashes, the column names are the keys of the hash, and the column
|
80
|
+
# types are accessible via the +types+ property.
|
81
|
+
def next
|
82
|
+
must_be_open!
|
83
|
+
if @db.results_as_hash
|
84
|
+
return next_hash
|
85
|
+
end
|
86
|
+
|
87
|
+
row = @stmt.step
|
88
|
+
return nil if @stmt.done?
|
89
|
+
row = ArrayWithTypesAndFields.new(row)
|
90
|
+
row.fields = @stmt.columns
|
91
|
+
row.types = @stmt.types
|
92
|
+
row
|
93
|
+
end
|
94
|
+
|
95
|
+
# Required by the Enumerable mixin. Provides an internal iterator over the
|
96
|
+
# rows of the result set.
|
97
|
+
def each
|
98
|
+
must_be_open!
|
99
|
+
while node = self.next
|
100
|
+
yield node
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Provides an internal iterator over the rows of the result set where
|
105
|
+
# each row is yielded as a hash.
|
106
|
+
def each_hash
|
107
|
+
while node = next_hash
|
108
|
+
yield node
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Closes the statement that spawned this result set.
|
113
|
+
# <em>Use with caution!</em> Closing a result set will automatically
|
114
|
+
# close any other result sets that were spawned from the same statement.
|
115
|
+
def close
|
116
|
+
@stmt.close
|
117
|
+
end
|
118
|
+
|
119
|
+
# Queries whether the underlying statement has been closed or not.
|
120
|
+
def closed?
|
121
|
+
@stmt.closed?
|
122
|
+
end
|
123
|
+
|
124
|
+
# Returns the types of the columns returned by this result set.
|
125
|
+
def types
|
126
|
+
must_be_open!
|
127
|
+
@stmt.types
|
128
|
+
end
|
129
|
+
|
130
|
+
# Returns the names of the columns returned by this result set.
|
131
|
+
def columns
|
132
|
+
must_be_open!
|
133
|
+
@stmt.columns
|
134
|
+
end
|
135
|
+
|
136
|
+
# Return the next row as a hash
|
137
|
+
def next_hash
|
138
|
+
must_be_open!
|
139
|
+
row = @stmt.step
|
140
|
+
return nil if @stmt.done?
|
141
|
+
|
142
|
+
# FIXME: this can be switched to a regular hash in 2.0
|
143
|
+
row = HashWithTypesAndFields[*@stmt.columns.zip(row).flatten]
|
144
|
+
|
145
|
+
# FIXME: these methods are deprecated for version 2.0, so we can remove
|
146
|
+
# this code in 2.0
|
147
|
+
row.fields = @stmt.columns
|
148
|
+
row.types = @stmt.types
|
149
|
+
row
|
150
|
+
end
|
151
|
+
|
152
|
+
private
|
153
|
+
|
154
|
+
def must_be_open!
|
155
|
+
raise Exception, "#{self.class} is closed!" if closed?
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|