sqlite3 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,68 @@
1
+ require "sqlite3/constants"
2
+
3
+ module SQLite3
4
+
5
+ class Exception < ::StandardError
6
+ @code = 0
7
+
8
+ # The numeric error code that this exception represents.
9
+ def self.code
10
+ @code
11
+ end
12
+
13
+ # A convenience for accessing the error code for this exception.
14
+ def code
15
+ self.class.code
16
+ end
17
+ end
18
+
19
+ class SQLException < Exception; end
20
+ class InternalException < Exception; end
21
+ class PermissionException < Exception; end
22
+ class AbortException < Exception; end
23
+ class BusyException < Exception; end
24
+ class LockedException < Exception; end
25
+ class MemoryException < Exception; end
26
+ class ReadOnlyException < Exception; end
27
+ class InterruptException < Exception; end
28
+ class IOException < Exception; end
29
+ class CorruptException < Exception; end
30
+ class NotFoundException < Exception; end
31
+ class FullException < Exception; end
32
+ class CantOpenException < Exception; end
33
+ class ProtocolException < Exception; end
34
+ class EmptyException < Exception; end
35
+ class SchemaChangedException < Exception; end
36
+ class TooBigException < Exception; end
37
+ class ConstraintException < Exception; end
38
+ class MismatchException < Exception; end
39
+ class MisuseException < Exception; end
40
+ class UnsupportedException < Exception; end
41
+ class AuthorizationException < Exception; end
42
+ class FormatException < Exception; end
43
+ class RangeException < Exception; end
44
+ class NotADatabaseException < Exception; end
45
+
46
+ EXCEPTIONS = [
47
+ nil,
48
+ SQLException, InternalException, PermissionException,
49
+ AbortException, BusyException, LockedException, MemoryException,
50
+ ReadOnlyException, InterruptException, IOException, CorruptException,
51
+ NotFoundException, FullException, CantOpenException, ProtocolException,
52
+ EmptyException, SchemaChangedException, TooBigException,
53
+ ConstraintException, MismatchException, MisuseException,
54
+ UnsupportedException, AuthorizationException, FormatException,
55
+ RangeException, NotADatabaseException
56
+ ].each_with_index { |e,i| e.instance_variable_set( :@code, i ) if e }
57
+
58
+ module Error
59
+ def check( result, db=nil, msg=nil )
60
+ unless result == Constants::ErrorCode::OK
61
+ msg = ( msg ? msg + ": " : "" ) + db.errmsg if db
62
+ raise(( EXCEPTIONS[result] || SQLite3::Exception ), msg)
63
+ end
64
+ end
65
+ module_function :check
66
+ end
67
+
68
+ end
@@ -0,0 +1,272 @@
1
+ require "sqlite3/errors"
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"
26
+ mode = "'ON'"
27
+ when "off", "no", "false", "n", "f"
28
+ mode = "'OFF'"
29
+ else
30
+ raise Exception, "unrecognized pragma parameter #{mode.inspect}"
31
+ end
32
+ when true, 1
33
+ mode = "ON"
34
+ when false, 0, nil
35
+ mode = "OFF"
36
+ else
37
+ raise Exception,
38
+ "unrecognized pragma parameter #{mode.inspect}"
39
+ end
40
+
41
+ execute("PRAGMA #{name}=#{mode}")
42
+ end
43
+ private :set_boolean_pragma
44
+
45
+ # Requests the given pragma (and parameters), and if the block is given,
46
+ # each row of the result set will be yielded to it. Otherwise, the results
47
+ # are returned as an array.
48
+ def get_query_pragma(name, *parms, &block) # :yields: row
49
+ if parms.empty?
50
+ execute("PRAGMA #{name}", &block)
51
+ else
52
+ args = "'" + parms.join("','") + "'"
53
+ execute("PRAGMA #{name}(#{args})", &block)
54
+ end
55
+ end
56
+ private :get_query_pragma
57
+
58
+ # Return the value of the given pragma.
59
+ def get_enum_pragma(name)
60
+ get_first_value("PRAGMA #{name}")
61
+ end
62
+ private :get_enum_pragma
63
+
64
+ # Set the value of the given pragma to +mode+. The +mode+ parameter must
65
+ # conform to one of the values in the given +enum+ array. Each entry in
66
+ # the array is another array comprised of elements in the enumeration that
67
+ # have duplicate values. See #synchronous, #default_synchronous,
68
+ # #temp_store, and #default_temp_store for usage examples.
69
+ def set_enum_pragma(name, mode, enums)
70
+ match = enums.find { |p| p.find { |i| i.to_s.downcase == mode.to_s.downcase } }
71
+ raise Exception,
72
+ "unrecognized #{name} #{mode.inspect}" unless match
73
+ execute("PRAGMA #{name}='#{match.first.upcase}'")
74
+ end
75
+ private :set_enum_pragma
76
+
77
+ # Returns the value of the given pragma as an integer.
78
+ def get_int_pragma(name)
79
+ get_first_value("PRAGMA #{name}").to_i
80
+ end
81
+ private :get_int_pragma
82
+
83
+ # Set the value of the given pragma to the integer value of the +value+
84
+ # parameter.
85
+ def set_int_pragma(name, value)
86
+ execute("PRAGMA #{name}=#{value.to_i}")
87
+ end
88
+ private :set_int_pragma
89
+
90
+ # The enumeration of valid synchronous modes.
91
+ SYNCHRONOUS_MODES = [ [ "full", 2 ], [ "normal", 1 ], [ "off", 0 ] ]
92
+
93
+ # The enumeration of valid temp store modes.
94
+ TEMP_STORE_MODES = [ [ "default", 0 ], [ "file", 1 ], [ "memory", 2 ] ]
95
+
96
+ # Does an integrity check on the database. If the check fails, a
97
+ # SQLite3::Exception will be raised. Otherwise it
98
+ # returns silently.
99
+ def integrity_check
100
+ execute("PRAGMA integrity_check") do |row|
101
+ raise Exception, row[0] if row[0] != "ok"
102
+ end
103
+ end
104
+
105
+ def auto_vacuum
106
+ get_boolean_pragma "auto_vacuum"
107
+ end
108
+
109
+ def auto_vacuum=(mode)
110
+ set_boolean_pragma "auto_vacuum", mode
111
+ end
112
+
113
+ def schema_cookie
114
+ get_int_pragma "schema_cookie"
115
+ end
116
+
117
+ def schema_cookie=(cookie)
118
+ set_int_pragma "schema_cookie", cookie
119
+ end
120
+
121
+ def user_cookie
122
+ get_int_pragma "user_cookie"
123
+ end
124
+
125
+ def user_cookie=(cookie)
126
+ set_int_pragma "user_cookie", cookie
127
+ end
128
+
129
+ def cache_size
130
+ get_int_pragma "cache_size"
131
+ end
132
+
133
+ def cache_size=(size)
134
+ set_int_pragma "cache_size", size
135
+ end
136
+
137
+ def default_cache_size
138
+ get_int_pragma "default_cache_size"
139
+ end
140
+
141
+ def default_cache_size=(size)
142
+ set_int_pragma "default_cache_size", size
143
+ end
144
+
145
+ def default_synchronous
146
+ get_enum_pragma "default_synchronous"
147
+ end
148
+
149
+ def default_synchronous=(mode)
150
+ set_enum_pragma "default_synchronous", mode, SYNCHRONOUS_MODES
151
+ end
152
+
153
+ def synchronous
154
+ get_enum_pragma "synchronous"
155
+ end
156
+
157
+ def synchronous=(mode)
158
+ set_enum_pragma "synchronous", mode, SYNCHRONOUS_MODES
159
+ end
160
+
161
+ def default_temp_store
162
+ get_enum_pragma "default_temp_store"
163
+ end
164
+
165
+ def default_temp_store=(mode)
166
+ set_enum_pragma "default_temp_store", mode, TEMP_STORE_MODES
167
+ end
168
+
169
+ def temp_store
170
+ get_enum_pragma "temp_store"
171
+ end
172
+
173
+ def temp_store=(mode)
174
+ set_enum_pragma "temp_store", mode, TEMP_STORE_MODES
175
+ end
176
+
177
+ def full_column_names
178
+ get_boolean_pragma "full_column_names"
179
+ end
180
+
181
+ def full_column_names=(mode)
182
+ set_boolean_pragma "full_column_names", mode
183
+ end
184
+
185
+ def parser_trace
186
+ get_boolean_pragma "parser_trace"
187
+ end
188
+
189
+ def parser_trace=(mode)
190
+ set_boolean_pragma "parser_trace", mode
191
+ end
192
+
193
+ def vdbe_trace
194
+ get_boolean_pragma "vdbe_trace"
195
+ end
196
+
197
+ def vdbe_trace=(mode)
198
+ set_boolean_pragma "vdbe_trace", mode
199
+ end
200
+
201
+ def database_list(&block) # :yields: row
202
+ get_query_pragma "database_list", &block
203
+ end
204
+
205
+ def foreign_key_list(table, &block) # :yields: row
206
+ get_query_pragma "foreign_key_list", table, &block
207
+ end
208
+
209
+ def index_info(index, &block) # :yields: row
210
+ get_query_pragma "index_info", index, &block
211
+ end
212
+
213
+ def index_list(table, &block) # :yields: row
214
+ get_query_pragma "index_list", table, &block
215
+ end
216
+
217
+ def table_info(table, &block) # :yields: row
218
+ columns, *rows = execute2("PRAGMA table_info(#{table})")
219
+
220
+ needs_tweak_default = version_compare(driver.libversion, "3.3.7") > 0
221
+
222
+ result = [] unless block_given?
223
+ rows.each do |row|
224
+ new_row = {}
225
+ columns.each_with_index do |name, index|
226
+ new_row[name] = row[index]
227
+ end
228
+
229
+ tweak_default(new_row) if needs_tweak_default
230
+
231
+ if block_given?
232
+ yield new_row
233
+ else
234
+ result << new_row
235
+ end
236
+ end
237
+
238
+ result
239
+ end
240
+
241
+ private
242
+
243
+ # Compares two version strings
244
+ def version_compare(v1, v2)
245
+ v1 = v1.split(".").map { |i| i.to_i }
246
+ v2 = v2.split(".").map { |i| i.to_i }
247
+ parts = [v1.length, v2.length].max
248
+ v1.push 0 while v1.length < parts
249
+ v2.push 0 while v2.length < parts
250
+ v1.zip(v2).each do |a,b|
251
+ return -1 if a < b
252
+ return 1 if a > b
253
+ end
254
+ return 0
255
+ end
256
+
257
+ # Since SQLite 3.3.8, the table_info pragma has returned the default
258
+ # value of the row as a quoted SQL value. This method essentially
259
+ # unquotes those values.
260
+ def tweak_default(hash)
261
+ case hash["dflt_value"]
262
+ when /^null$/i
263
+ hash["dflt_value"] = nil
264
+ when /^'(.*)'$/
265
+ hash["dflt_value"] = $1.gsub(/''/, "'")
266
+ when /^"(.*)"$/
267
+ hash["dflt_value"] = $1.gsub(/""/, '"')
268
+ end
269
+ end
270
+ end
271
+
272
+ end
@@ -0,0 +1,176 @@
1
+ require "sqlite3/constants"
2
+ require "sqlite3/errors"
3
+
4
+ module SQLite3
5
+
6
+ # The ResultSet object encapsulates the enumerability of a query's output.
7
+ # It is a simple cursor over the data that the query returns. It will
8
+ # very rarely (if ever) be instantiated directly. Instead, client's should
9
+ # obtain a ResultSet instance via Statement#execute.
10
+ class ResultSet
11
+ include Enumerable
12
+
13
+ # The class of which we return an object in case we want an Array as
14
+ # result. (ArrayFields is installed.)
15
+ class ArrayWithTypes < Array
16
+ attr_accessor :types
17
+ end
18
+
19
+ # The class of which we return an object in case we want an Array as
20
+ # result. (ArrayFields is not installed.)
21
+ class ArrayWithTypesAndFields < Array
22
+ attr_accessor :types
23
+ attr_accessor :fields
24
+ end
25
+
26
+ # The class of which we return an object in case we want a Hash as
27
+ # result.
28
+ class HashWithTypes < Hash
29
+ attr_accessor :types
30
+ end
31
+
32
+ # Create a new ResultSet attached to the given database, using the
33
+ # given sql text.
34
+ def initialize(db, stmt)
35
+ @db = db
36
+ @driver = @db.driver
37
+ @stmt = stmt
38
+ commence
39
+ end
40
+
41
+ # A convenience method for compiling the virtual machine and stepping
42
+ # to the first row of the result set.
43
+ def commence
44
+ result = @driver.step(@stmt.handle)
45
+ if result == Constants::ErrorCode::ERROR
46
+ @driver.reset(@stmt.handle)
47
+ end
48
+ check result
49
+ @first_row = true
50
+ end
51
+ private :commence
52
+
53
+ def check(result)
54
+ @eof = (result == Constants::ErrorCode::DONE)
55
+ found = (result == Constants::ErrorCode::ROW)
56
+ Error.check(result, @db) unless @eof || found
57
+ end
58
+ private :check
59
+
60
+ # Reset the cursor, so that a result set which has reached end-of-file
61
+ # can be rewound and reiterated.
62
+ def reset(*bind_params)
63
+ @stmt.must_be_open!
64
+ @stmt.reset!(false)
65
+ @driver.reset(@stmt.handle)
66
+ @stmt.bind_params(*bind_params)
67
+ @eof = false
68
+ commence
69
+ end
70
+
71
+ # Query whether the cursor has reached the end of the result set or not.
72
+ def eof?
73
+ @eof
74
+ end
75
+
76
+ # Obtain the next row from the cursor. If there are no more rows to be
77
+ # had, this will return +nil+. If type translation is active on the
78
+ # corresponding database, the values in the row will be translated
79
+ # according to their types.
80
+ #
81
+ # The returned value will be an array, unless Database#results_as_hash has
82
+ # been set to +true+, in which case the returned value will be a hash.
83
+ #
84
+ # For arrays, the column names are accessible via the +fields+ property,
85
+ # and the column types are accessible via the +types+ property.
86
+ #
87
+ # For hashes, the column names are the keys of the hash, and the column
88
+ # types are accessible via the +types+ property.
89
+ def next
90
+ return nil if @eof
91
+
92
+ @stmt.must_be_open!
93
+
94
+ unless @first_row
95
+ result = @driver.step(@stmt.handle)
96
+ check result
97
+ end
98
+
99
+ @first_row = false
100
+
101
+ unless @eof
102
+ row = []
103
+ @driver.data_count(@stmt.handle).times do |column|
104
+ type = @driver.column_type(@stmt.handle, column)
105
+
106
+ if type == Constants::ColumnType::TEXT
107
+ row << @driver.column_text(@stmt.handle, column)
108
+ elsif type == Constants::ColumnType::NULL
109
+ row << nil
110
+ elsif type == Constants::ColumnType::BLOB
111
+ row << @driver.column_blob(@stmt.handle, column)
112
+ else
113
+ row << @driver.column_text(@stmt.handle, column)
114
+ end
115
+ end
116
+
117
+ if @db.type_translation
118
+ row = @stmt.types.zip(row).map do |type, value|
119
+ @db.translator.translate(type, value)
120
+ end
121
+ end
122
+
123
+ if @db.results_as_hash
124
+ new_row = HashWithTypes[ *(@stmt.columns.zip(row).to_a.flatten) ]
125
+ row.each_with_index { |value,idx| new_row[idx] = value }
126
+ row = new_row
127
+ else
128
+ if row.respond_to?(:fields)
129
+ row = ArrayWithTypes.new(row)
130
+ else
131
+ row = ArrayWithTypesAndFields.new(row)
132
+ end
133
+ row.fields = @stmt.columns
134
+ end
135
+
136
+ row.types = @stmt.types
137
+
138
+ return row
139
+ end
140
+
141
+ nil
142
+ end
143
+
144
+ # Required by the Enumerable mixin. Provides an internal iterator over the
145
+ # rows of the result set.
146
+ def each
147
+ while row=self.next
148
+ yield row
149
+ end
150
+ end
151
+
152
+ # Closes the statement that spawned this result set.
153
+ # <em>Use with caution!</em> Closing a result set will automatically
154
+ # close any other result sets that were spawned from the same statement.
155
+ def close
156
+ @stmt.close
157
+ end
158
+
159
+ # Queries whether the underlying statement has been closed or not.
160
+ def closed?
161
+ @stmt.closed?
162
+ end
163
+
164
+ # Returns the types of the columns returned by this result set.
165
+ def types
166
+ @stmt.types
167
+ end
168
+
169
+ # Returns the names of the columns returned by this result set.
170
+ def columns
171
+ @stmt.columns
172
+ end
173
+
174
+ end
175
+
176
+ end