sqlite-ruby 2.2.1 → 2.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,233 +0,0 @@
1
- #--
2
- # =============================================================================
3
- # Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
4
- # All rights reserved.
5
- #
6
- # Redistribution and use in source and binary forms, with or without
7
- # modification, are permitted provided that the following conditions are met:
8
- #
9
- # * Redistributions of source code must retain the above copyright notice,
10
- # this list of conditions and the following disclaimer.
11
- #
12
- # * Redistributions in binary form must reproduce the above copyright
13
- # notice, this list of conditions and the following disclaimer in the
14
- # documentation and/or other materials provided with the distribution.
15
- #
16
- # * The names of its contributors may not be used to endorse or promote
17
- # products derived from this software without specific prior written
18
- # permission.
19
- #
20
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
- # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
- # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
- # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
24
- # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
- # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
- # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
- # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
- # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
- # =============================================================================
31
- #++
32
-
33
- require 'strscan'
34
-
35
- module SQLite
36
-
37
- # A ParsedStatement instance represents a tokenized version of an SQL
38
- # statement. This makes it possible to do bind variable replacements multiple
39
- # times, fairly efficiently.
40
- #
41
- # Within the SQLite interfaces, this is used only by the Statement class.
42
- # However, it could be reused by other SQL-reliant classes easily.
43
- class ParsedStatement
44
-
45
- # This represents a textual token in an SQL statement. It is only used by
46
- # ParsedStatement.
47
- class Token # :nodoc:
48
-
49
- # Create a new Token that encapsulates the given text.
50
- def initialize( text )
51
- @text = text
52
- end
53
-
54
- # Append the given text onto the the contents of this Token.
55
- def <<( text )
56
- @text << text.to_s
57
- end
58
-
59
- # Convert this Token into a string. The +vars+ parameter is ignored.
60
- def to_s( vars=nil )
61
- @text
62
- end
63
-
64
- end
65
-
66
- # This represents a bind variable in a tokenized SQL stream. It is used
67
- # only by ParsedStatement.
68
- class BindVariable # :nodoc:
69
-
70
- # Create a new BindVariable token encapsulating the given name. The
71
- # name is used when looking up a bind variable to bind to the place
72
- # holder represented by this token. The name may be either a Fixnum
73
- # (in which case it represents an positional placeholder) or a
74
- # a String (in which case it represents a named placeholder).
75
- def initialize( name )
76
- @name = name
77
- end
78
-
79
- # Convert the token to a string. If the +vars+ parameter is +nil+, then
80
- # the string will be in the format <tt>?nnn</tt> (where _nnn_ is the
81
- # index that was used to initialize this token). Otherwise, the +vars+
82
- # parameter must be a hash, and the value bound to this token is the
83
- # element with the key given to this token when it was created. If that
84
- # element is +nil+, this will return the string "NULL". If the element
85
- # is a String, then it will be quoted and escaped and returned.
86
- # Otherwise, the "to_s" method of the element will be called and the
87
- # result returned.
88
- def to_s( vars=nil )
89
- if vars.nil?
90
- ":#{@name}"
91
- else
92
- var = vars[ @name ]
93
- case var
94
- when nil
95
- "NULL"
96
- when String
97
- "'#{var.gsub(/'/,"''")}'"
98
- else
99
- var.to_s
100
- end
101
- end
102
- end
103
-
104
- end
105
-
106
- # The text trailing the first recognized SQL statement that was parsed from
107
- # the buffer given to this object. If there was no trailing SQL statement,
108
- # this property will be the empty string.
109
- attr_reader :trailing
110
-
111
- # Create a new ParsedStatement. This will tokenize the given buffer. As an
112
- # optimization, the tokenization is only performed if the string matches
113
- # /[?:;]/, otherwise the string is used as-is.
114
- def initialize( sql )
115
- @bind_values = Hash.new
116
-
117
- if sql.index( /[?:;]/ )
118
- @tokens, @trailing = tokenize( sql )
119
- else
120
- @tokens, @trailing = [ Token.new(sql) ], ""
121
- end
122
- end
123
-
124
- # Returns an array of the placeholders known to this statement. This will
125
- # either be empty (if the statement has no placeholders), or will contain
126
- # numbers (indexes) and strings (names).
127
- def placeholders
128
- @bind_values.keys
129
- end
130
-
131
- # Returns the SQL that was given to this parsed statement when it was
132
- # created, with bind placeholders intact.
133
- def sql
134
- @tokens.inject( "" ) { |sql,tok| sql << tok.to_s }
135
- end
136
-
137
- # Returns the statement as an SQL string, with all placeholders bound to
138
- # their corresponding values.
139
- def to_s
140
- @tokens.inject( "" ) { |sql,tok| sql << tok.to_s( @bind_values ) }
141
- end
142
-
143
- alias :to_str :to_s
144
-
145
- # Binds the given parameters to the placeholders in the statement. It does
146
- # this by iterating over each argument and calling #bind_param with the
147
- # corresponding index (starting at 1). However, if any element is a hash,
148
- # the hash is iterated through and #bind_param called for each key/value
149
- # pair. Hash's do not increment the index.
150
- def bind_params( *bind_vars )
151
- index = 1
152
- bind_vars.each do |value|
153
- if value.is_a?( Hash )
154
- value.each_pair { |key, value| bind_param( key, value ) }
155
- else
156
- bind_param index, value
157
- index += 1
158
- end
159
- end
160
- self
161
- end
162
-
163
- # Binds the given value to the placeholder indicated by +param+, which may
164
- # be either a Fixnum or a String. If the indicated placeholder does not
165
- # exist in the statement, this method does nothing.
166
- def bind_param( param, value )
167
- return unless @bind_values.has_key?( param )
168
- @bind_values[ param ] = value
169
- end
170
-
171
- # Tokenizes the given SQL string, returning a tuple containing the array of
172
- # tokens (optimized so that each text token contains the longest run of
173
- # text possible), and any trailing text that follows the statement.
174
- def tokenize( sql )
175
- tokens = []
176
-
177
- scanner = StringScanner.new( sql )
178
- variable_index = 0
179
-
180
- until scanner.eos?
181
- tokens << " " unless tokens.empty? if scanner.scan( /\s+/ )
182
- break if scanner.eos?
183
-
184
- if scanner.scan( /;/ )
185
- break
186
- elsif scanner.scan( /---.*$/ ) || scanner.scan( %r{/\*.*?\*/}m )
187
- # comments
188
- next
189
- elsif scanner.scan( /[-+*\/\w=<>!(),.]+/ )
190
- tokens << Token.new( scanner.matched )
191
- elsif scanner.scan( /['"]/ )
192
- delim = scanner.matched
193
- token = delim.dup
194
- loop do
195
- token << scanner.scan_until( /#{delim}/ )
196
- match = scanner.matched
197
- break if match.length % 2 == 1
198
- end
199
- tokens << Token.new( token )
200
- elsif scanner.scan( /\?(\d+)?/ )
201
- variable_index = ( scanner[1] ? scanner[1].to_i : variable_index+1 )
202
- tokens << BindVariable.new( variable_index )
203
- @bind_values[variable_index] = nil
204
- elsif scanner.scan( /:(\w+):?/ )
205
- name = scanner[1]
206
- variable_index = name = name.to_i if name !~ /\D/
207
- tokens << BindVariable.new( name )
208
- @bind_values[name] = nil
209
- else
210
- raise "unknown token #{scanner.rest.inspect}"
211
- end
212
- end
213
-
214
- # optimize the parsed list
215
- tokens.pop while tokens.last == " "
216
- optimized = []
217
- tokens.each do |tok|
218
- last = optimized.last
219
- if tok.is_a?( BindVariable ) || last.nil? || last.is_a?( BindVariable )
220
- tok = Token.new(tok) if tok == " "
221
- optimized << tok
222
- else
223
- last << tok
224
- end
225
- end
226
-
227
- return optimized, scanner.rest
228
- end
229
- private :tokenize
230
-
231
- end
232
-
233
- end
@@ -1,236 +0,0 @@
1
- #--
2
- # =============================================================================
3
- # Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
4
- # All rights reserved.
5
- #
6
- # Redistribution and use in source and binary forms, with or without
7
- # modification, are permitted provided that the following conditions are met:
8
- #
9
- # * Redistributions of source code must retain the above copyright notice,
10
- # this list of conditions and the following disclaimer.
11
- #
12
- # * Redistributions in binary form must reproduce the above copyright
13
- # notice, this list of conditions and the following disclaimer in the
14
- # documentation and/or other materials provided with the distribution.
15
- #
16
- # * The names of its contributors may not be used to endorse or promote
17
- # products derived from this software without specific prior written
18
- # permission.
19
- #
20
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
- # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
- # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
- # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
24
- # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
- # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
- # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
- # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
- # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
- # =============================================================================
31
- #++
32
-
33
- module SQLite
34
-
35
- # This module is intended for inclusion solely by the Database class. It
36
- # defines convenience methods for the various pragmas supported by SQLite.
37
- #
38
- # Two pragmas that have been intentionally excluded are SHOW_DATATYPES
39
- # and EMPTY_RESULT_SETS, since these apply only to queries that use the
40
- # SQLite "exec" function. The SQLite API does not employ that function,
41
- # preferring instead the compile/step/finalize interface.
42
- #
43
- # However, if you really must have those pragmas, you can always execute
44
- # a pragma as if it were an SQL statement.
45
- #
46
- # For a detailed description of these pragmas, see the SQLite documentation
47
- # at http://sqlite.org/lang.html#pragma.
48
- module Pragmas
49
-
50
- # Returns +true+ or +false+ depending on the value of the named pragma.
51
- def get_boolean_pragma( name )
52
- get_first_value( "PRAGMA #{name}" ) != "0"
53
- end
54
- private :get_boolean_pragma
55
-
56
- # Sets the given pragma to the given boolean value. The value itself
57
- # may be +true+ or +false+, or any other commonly used string or
58
- # integer that represents truth.
59
- def set_boolean_pragma( name, mode )
60
- case mode
61
- when String
62
- case mode.downcase
63
- when "on", "yes", "true", "y", "t": mode = "'ON'"
64
- when "off", "no", "false", "n", "f": mode = "'OFF'"
65
- else
66
- raise Exceptions::DatabaseException,
67
- "unrecognized pragma parameter #{mode.inspect}"
68
- end
69
- when true, 1
70
- mode = "ON"
71
- when false, 0, nil
72
- mode = "OFF"
73
- else
74
- raise Exceptions::DatabaseException,
75
- "unrecognized pragma parameter #{mode.inspect}"
76
- end
77
-
78
- execute( "PRAGMA #{name}=#{mode}" )
79
- end
80
- private :set_boolean_pragma
81
-
82
- # Requests the given pragma (and parameters), and if the block is given,
83
- # each row of the result set will be yielded to it. Otherwise, the results
84
- # are returned as an array.
85
- def get_query_pragma( name, *parms, &block ) # :yields: row
86
- if parms.empty?
87
- execute( "PRAGMA #{name}", &block )
88
- else
89
- args = "'" + parms.join("','") + "'"
90
- execute( "PRAGMA #{name}( #{args} )", &block )
91
- end
92
- end
93
- private :get_query_pragma
94
-
95
- # Return the value of the given pragma.
96
- def get_enum_pragma( name )
97
- get_first_value( "PRAGMA #{name}" )
98
- end
99
- private :get_enum_pragma
100
-
101
- # Set the value of the given pragma to +mode+. The +mode+ parameter must
102
- # conform to one of the values in the given +enum+ array. Each entry in
103
- # the array is another array comprised of elements in the enumeration that
104
- # have duplicate values. See #synchronous, #default_synchronous,
105
- # #temp_store, and #default_temp_store for usage examples.
106
- def set_enum_pragma( name, mode, enums )
107
- match = enums.find { |p| p.find { |i| i.to_s.downcase == mode.to_s.downcase } }
108
- raise Exceptions::DatabaseException,
109
- "unrecognized #{name} #{mode.inspect}" unless match
110
- execute( "PRAGMA #{name}='#{match.first.upcase}'" )
111
- end
112
- private :set_enum_pragma
113
-
114
- # Returns the value of the given pragma as an integer.
115
- def get_int_pragma( name )
116
- get_first_value( "PRAGMA #{name}" ).to_i
117
- end
118
- private :get_int_pragma
119
-
120
- # Set the value of the given pragma to the integer value of the +value+
121
- # parameter.
122
- def set_int_pragma( name, value )
123
- execute( "PRAGMA #{name}=#{value.to_i}" )
124
- end
125
- private :set_int_pragma
126
-
127
- # The enumeration of valid synchronous modes.
128
- SYNCHRONOUS_MODES = [ [ 'full', 2 ], [ 'normal', 1 ], [ 'off', 0 ] ]
129
-
130
- # The enumeration of valid temp store modes.
131
- TEMP_STORE_MODES = [ [ 'default', 0 ], [ 'file', 1 ], [ 'memory', 2 ] ]
132
-
133
- # Does an integrity check on the database. If the check fails, a
134
- # SQLite::Exceptions::DatabaseException will be raised. Otherwise it
135
- # returns silently.
136
- def integrity_check
137
- execute( "PRAGMA integrity_check" ) do |row|
138
- raise Exceptions::DatabaseException, row[0] if row[0] != "ok"
139
- end
140
- end
141
-
142
- def cache_size
143
- get_int_pragma "cache_size"
144
- end
145
-
146
- def cache_size=( size )
147
- set_int_pragma "cache_size", size
148
- end
149
-
150
- def default_cache_size
151
- get_int_pragma "default_cache_size"
152
- end
153
-
154
- def default_cache_size=( size )
155
- set_int_pragma "default_cache_size", size
156
- end
157
-
158
- def default_synchronous
159
- get_enum_pragma "default_synchronous"
160
- end
161
-
162
- def default_synchronous=( mode )
163
- set_enum_pragma "default_synchronous", mode, SYNCHRONOUS_MODES
164
- end
165
-
166
- def synchronous
167
- get_enum_pragma "synchronous"
168
- end
169
-
170
- def synchronous=( mode )
171
- set_enum_pragma "synchronous", mode, SYNCHRONOUS_MODES
172
- end
173
-
174
- def default_temp_store
175
- get_enum_pragma "default_temp_store"
176
- end
177
-
178
- def default_temp_store=( mode )
179
- set_enum_pragma "default_temp_store", mode, TEMP_STORE_MODES
180
- end
181
-
182
- def temp_store
183
- get_enum_pragma "temp_store"
184
- end
185
-
186
- def temp_store=( mode )
187
- set_enum_pragma "temp_store", mode, TEMP_STORE_MODES
188
- end
189
-
190
- def full_column_names
191
- get_boolean_pragma "full_column_names"
192
- end
193
-
194
- def full_column_names=( mode )
195
- set_boolean_pragma "full_column_names", mode
196
- end
197
-
198
- def parser_trace
199
- get_boolean_pragma "parser_trace"
200
- end
201
-
202
- def parser_trace=( mode )
203
- set_boolean_pragma "parser_trace", mode
204
- end
205
-
206
- def vdbe_trace
207
- get_boolean_pragma "vdbe_trace"
208
- end
209
-
210
- def vdbe_trace=( mode )
211
- set_boolean_pragma "vdbe_trace", mode
212
- end
213
-
214
- def database_list( &block ) # :yields: row
215
- get_query_pragma "database_list", &block
216
- end
217
-
218
- def foreign_key_list( table, &block ) # :yields: row
219
- get_query_pragma "foreign_key_list", table, &block
220
- end
221
-
222
- def index_info( index, &block ) # :yields: row
223
- get_query_pragma "index_info", index, &block
224
- end
225
-
226
- def index_list( table, &block ) # :yields: row
227
- get_query_pragma "index_list", table, &block
228
- end
229
-
230
- def table_info( table, &block ) # :yields: row
231
- get_query_pragma "table_info", table, &block
232
- end
233
-
234
- end
235
-
236
- end