sqlite3-fiddle 1.0.0

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