sqlite3-ruby 1.2.3-x86-mingw32

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.

Potentially problematic release.


This version of sqlite3-ruby might be problematic. Click here for more details.

@@ -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
@@ -0,0 +1,230 @@
1
+ require 'sqlite3/errors'
2
+ require 'sqlite3/resultset'
3
+
4
+ class String
5
+ def to_blob
6
+ SQLite3::Blob.new( self )
7
+ end
8
+ end
9
+
10
+ module SQLite3
11
+
12
+ # A class for differentiating between strings and blobs, when binding them
13
+ # into statements.
14
+ class Blob < String; end
15
+
16
+ # A statement represents a prepared-but-unexecuted SQL query. It will rarely
17
+ # (if ever) be instantiated directly by a client, and is most often obtained
18
+ # via the Database#prepare method.
19
+ class Statement
20
+
21
+ # This is any text that followed the first valid SQL statement in the text
22
+ # with which the statement was initialized. If there was no trailing text,
23
+ # this will be the empty string.
24
+ attr_reader :remainder
25
+
26
+ # The underlying opaque handle used to access the SQLite @driver.
27
+ attr_reader :handle
28
+
29
+ # Create a new statement attached to the given Database instance, and which
30
+ # encapsulates the given SQL text. If the text contains more than one
31
+ # statement (i.e., separated by semicolons), then the #remainder property
32
+ # will be set to the trailing text.
33
+ def initialize( db, sql, utf16=false )
34
+ @db = db
35
+ @driver = @db.driver
36
+ @closed = false
37
+ @results = @columns = nil
38
+ result, @handle, @remainder = @driver.prepare( @db.handle, sql )
39
+ Error.check( result, @db )
40
+ end
41
+
42
+ # Closes the statement by finalizing the underlying statement
43
+ # handle. The statement must not be used after being closed.
44
+ def close
45
+ must_be_open!
46
+ @closed = true
47
+ @driver.finalize( @handle )
48
+ end
49
+
50
+ # Returns true if the underlying statement has been closed.
51
+ def closed?
52
+ @closed
53
+ end
54
+
55
+ # Binds the given variables to the corresponding placeholders in the SQL
56
+ # text.
57
+ #
58
+ # See Database#execute for a description of the valid placeholder
59
+ # syntaxes.
60
+ #
61
+ # Example:
62
+ #
63
+ # stmt = db.prepare( "select * from table where a=? and b=?" )
64
+ # stmt.bind_params( 15, "hello" )
65
+ #
66
+ # See also #execute, #bind_param, Statement#bind_param, and
67
+ # Statement#bind_params.
68
+ def bind_params( *bind_vars )
69
+ index = 1
70
+ bind_vars.flatten.each do |var|
71
+ if Hash === var
72
+ var.each { |key, val| bind_param key, val }
73
+ else
74
+ bind_param index, var
75
+ index += 1
76
+ end
77
+ end
78
+ end
79
+
80
+ # Binds value to the named (or positional) placeholder. If +param+ is a
81
+ # Fixnum, it is treated as an index for a positional placeholder.
82
+ # Otherwise it is used as the name of the placeholder to bind to.
83
+ #
84
+ # See also #bind_params.
85
+ def bind_param( param, value )
86
+ must_be_open!
87
+ reset! if active?
88
+ if Fixnum === param
89
+ case value
90
+ when Bignum then
91
+ @driver.bind_int64( @handle, param, value )
92
+ when Integer then
93
+ if value >= (2 ** 31)
94
+ @driver.bind_int64( @handle, param, value )
95
+ else
96
+ @driver.bind_int( @handle, param, value )
97
+ end
98
+ when Numeric then
99
+ @driver.bind_double( @handle, param, value.to_f )
100
+ when Blob then
101
+ @driver.bind_blob( @handle, param, value )
102
+ when nil then
103
+ @driver.bind_null( @handle, param )
104
+ else
105
+ @driver.bind_text( @handle, param, value )
106
+ end
107
+ else
108
+ param = param.to_s
109
+ param = ":#{param}" unless param[0] == ?:
110
+ index = @driver.bind_parameter_index( @handle, param )
111
+ raise Exception, "no such bind parameter '#{param}'" if index == 0
112
+ bind_param index, value
113
+ end
114
+ end
115
+
116
+ # Execute the statement. This creates a new ResultSet object for the
117
+ # statement's virtual machine. If a block was given, the new ResultSet will
118
+ # be yielded to it; otherwise, the ResultSet will be returned.
119
+ #
120
+ # Any parameters will be bound to the statement using #bind_params.
121
+ #
122
+ # Example:
123
+ #
124
+ # stmt = db.prepare( "select * from table" )
125
+ # stmt.execute do |result|
126
+ # ...
127
+ # end
128
+ #
129
+ # See also #bind_params, #execute!.
130
+ def execute( *bind_vars )
131
+ must_be_open!
132
+ reset! if active?
133
+
134
+ bind_params(*bind_vars) unless bind_vars.empty?
135
+ @results = ResultSet.new( @db, self )
136
+
137
+ if block_given?
138
+ yield @results
139
+ else
140
+ return @results
141
+ end
142
+ end
143
+
144
+ # Execute the statement. If no block was given, this returns an array of
145
+ # rows returned by executing the statement. Otherwise, each row will be
146
+ # yielded to the block.
147
+ #
148
+ # Any parameters will be bound to the statement using #bind_params.
149
+ #
150
+ # Example:
151
+ #
152
+ # stmt = db.prepare( "select * from table" )
153
+ # stmt.execute! do |row|
154
+ # ...
155
+ # end
156
+ #
157
+ # See also #bind_params, #execute.
158
+ def execute!( *bind_vars )
159
+ result = execute( *bind_vars )
160
+ rows = [] unless block_given?
161
+ while row = result.next
162
+ if block_given?
163
+ yield row
164
+ else
165
+ rows << row
166
+ end
167
+ end
168
+ rows
169
+ end
170
+
171
+ # Resets the statement. This is typically done internally, though it might
172
+ # occassionally be necessary to manually reset the statement.
173
+ def reset!(clear_result=true)
174
+ @driver.reset(@handle)
175
+ @results = nil if clear_result
176
+ end
177
+
178
+ # Returns true if the statement is currently active, meaning it has an
179
+ # open result set.
180
+ def active?
181
+ not @results.nil?
182
+ end
183
+
184
+ # Return an array of the column names for this statement. Note that this
185
+ # may execute the statement in order to obtain the metadata; this makes it
186
+ # a (potentially) expensive operation.
187
+ def columns
188
+ get_metadata unless @columns
189
+ return @columns
190
+ end
191
+
192
+ # Return an array of the data types for each column in this statement. Note
193
+ # that this may execute the statement in order to obtain the metadata; this
194
+ # makes it a (potentially) expensive operation.
195
+ def types
196
+ get_metadata unless @types
197
+ return @types
198
+ end
199
+
200
+ # A convenience method for obtaining the metadata about the query. Note
201
+ # that this will actually execute the SQL, which means it can be a
202
+ # (potentially) expensive operation.
203
+ def get_metadata
204
+ must_be_open!
205
+
206
+ @columns = []
207
+ @types = []
208
+
209
+ column_count = @driver.column_count( @handle )
210
+ column_count.times do |column|
211
+ @columns << @driver.column_name( @handle, column )
212
+ @types << @driver.column_decltype( @handle, column )
213
+ end
214
+
215
+ @columns.freeze
216
+ @types.freeze
217
+ end
218
+ private :get_metadata
219
+
220
+ # Performs a sanity check to ensure that the statement is not
221
+ # closed. If it is, an exception is raised.
222
+ def must_be_open! # :nodoc:
223
+ if @closed
224
+ raise SQLite3::Exception, "cannot use a closed statement"
225
+ end
226
+ end
227
+
228
+ end
229
+
230
+ end
@@ -0,0 +1,109 @@
1
+ require 'time'
2
+ require 'date'
3
+
4
+ module SQLite3
5
+
6
+ # The Translator class encapsulates the logic and callbacks necessary for
7
+ # converting string data to a value of some specified type. Every Database
8
+ # instance may have a Translator instance, in order to assist in type
9
+ # translation (Database#type_translation).
10
+ #
11
+ # Further, applications may define their own custom type translation logic
12
+ # by registering translator blocks with the corresponding database's
13
+ # translator instance (Database#translator).
14
+ class Translator
15
+
16
+ # Create a new Translator instance. It will be preinitialized with default
17
+ # translators for most SQL data types.
18
+ def initialize
19
+ @translators = Hash.new( proc { |type,value| value } )
20
+ @type_name_cache = {}
21
+ register_default_translators
22
+ end
23
+
24
+ # Add a new translator block, which will be invoked to process type
25
+ # translations to the given type. The type should be an SQL datatype, and
26
+ # may include parentheses (i.e., "VARCHAR(30)"). However, any parenthetical
27
+ # information is stripped off and discarded, so type translation decisions
28
+ # are made solely on the "base" type name.
29
+ #
30
+ # The translator block itself should accept two parameters, "type" and
31
+ # "value". In this case, the "type" is the full type name (including
32
+ # parentheses), so the block itself may include logic for changing how a
33
+ # type is translated based on the additional data. The "value" parameter
34
+ # is the (string) data to convert.
35
+ #
36
+ # The block should return the translated value.
37
+ def add_translator( type, &block ) # :yields: type, value
38
+ @translators[ type_name( type ) ] = block
39
+ end
40
+
41
+ # Translate the given string value to a value of the given type. In the
42
+ # absense of an installed translator block for the given type, the value
43
+ # itself is always returned. Further, +nil+ values are never translated,
44
+ # and are always passed straight through regardless of the type parameter.
45
+ def translate( type, value )
46
+ unless value.nil?
47
+ @translators[ type_name( type ) ].call( type, value )
48
+ end
49
+ end
50
+
51
+ # A convenience method for working with type names. This returns the "base"
52
+ # type name, without any parenthetical data.
53
+ def type_name( type )
54
+ @type_name_cache[type] ||= begin
55
+ type = "" if type.nil?
56
+ type = $1 if type =~ /^(.*?)\(/
57
+ type.upcase
58
+ end
59
+ end
60
+ private :type_name
61
+
62
+ # Register the default translators for the current Translator instance.
63
+ # This includes translators for most major SQL data types.
64
+ def register_default_translators
65
+ [ "time",
66
+ "timestamp" ].each { |type| add_translator( type ) { |t, v| Time.parse( v ) } }
67
+
68
+ add_translator( "date" ) { |t,v| Date.parse(v) }
69
+ add_translator( "datetime" ) { |t,v| DateTime.parse(v) }
70
+
71
+ [ "decimal",
72
+ "float",
73
+ "numeric",
74
+ "double",
75
+ "real",
76
+ "dec",
77
+ "fixed" ].each { |type| add_translator( type ) { |t,v| v.to_f } }
78
+
79
+ [ "integer",
80
+ "smallint",
81
+ "mediumint",
82
+ "int",
83
+ "bigint" ].each { |type| add_translator( type ) { |t,v| v.to_i } }
84
+
85
+ [ "bit",
86
+ "bool",
87
+ "boolean" ].each do |type|
88
+ add_translator( type ) do |t,v|
89
+ !( v.strip.gsub(/00+/,"0") == "0" ||
90
+ v.downcase == "false" ||
91
+ v.downcase == "f" ||
92
+ v.downcase == "no" ||
93
+ v.downcase == "n" )
94
+ end
95
+ end
96
+
97
+ add_translator( "tinyint" ) do |type, value|
98
+ if type =~ /\(\s*1\s*\)/
99
+ value.to_i == 1
100
+ else
101
+ value.to_i
102
+ end
103
+ end
104
+ end
105
+ private :register_default_translators
106
+
107
+ end
108
+
109
+ end