sqlite3-fiddle 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|