ironruby-dbi 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,65 @@
1
+ module DBI
2
+ # Exceptions (borrowed by Python API 2.0)
3
+
4
+ # Base class of all other error exceptions. Use this to catch all DBI
5
+ # errors.
6
+ class Error < RuntimeError
7
+ end
8
+
9
+ # For important warnings like data truncation, etc.
10
+ class Warning < RuntimeError
11
+ end
12
+
13
+ # Exception for errors related to the DBI interface rather than the
14
+ # database itself.
15
+ class InterfaceError < Error
16
+ end
17
+
18
+ # Exception raised if the DBD driver has not specified a mandatory method.
19
+ class NotImplementedError < InterfaceError
20
+ end
21
+
22
+ # Exception for errors related to the database.
23
+ class DatabaseError < Error
24
+ attr_reader :err, :errstr, :state
25
+
26
+ def initialize(errstr="", err=nil, state=nil)
27
+ super(errstr)
28
+ @err, @errstr, @state = err, errstr, state
29
+ end
30
+ end
31
+
32
+ # Exception for errors due to problems with the processed
33
+ # data such as division by zero, numeric value out of range, etc.
34
+ class DataError < DatabaseError
35
+ end
36
+
37
+ # Exception for errors related to the database's operation which are not
38
+ # necessarily under the control of the programmer. This includes such
39
+ # things as unexpected disconnect, datasource name not found, transaction
40
+ # could not be processed, a memory allocation error occured during
41
+ # processing, etc.
42
+ class OperationalError < DatabaseError
43
+ end
44
+
45
+ # Exception raised when the relational integrity of the database
46
+ # is affected, e.g. a foreign key check fails.
47
+ class IntegrityError < DatabaseError
48
+ end
49
+
50
+ # Exception raised when the database encounters an internal error,
51
+ # e.g. the cursor is not valid anymore, the transaction is out of sync.
52
+ class InternalError < DatabaseError
53
+ end
54
+
55
+ # Exception raised for programming errors, e.g. table not found
56
+ # or already exists, syntax error in SQL statement, wrong number
57
+ # of parameters specified, etc.
58
+ class ProgrammingError < DatabaseError
59
+ end
60
+
61
+ # Exception raised if e.g. commit() is called for a database which do not
62
+ # support transactions.
63
+ class NotSupportedError < DatabaseError
64
+ end
65
+ end
@@ -0,0 +1,49 @@
1
+ #
2
+ # Dispatch classes (Handle, DriverHandle, DatabaseHandle and StatementHandle)
3
+ #
4
+
5
+ module DBI
6
+ #
7
+ # Base class for all handles.
8
+ #
9
+ class Handle
10
+ attr_reader :trace_mode, :trace_output
11
+ attr_reader :handle
12
+ attr :convert_types, true
13
+
14
+ def initialize(handle, convert_types=true)
15
+ @handle = handle
16
+ @trace_mode = @trace_output = nil
17
+ @convert_types = convert_types
18
+ end
19
+
20
+ # Please seee DBI.trace.
21
+ def trace(mode=nil, output=nil)
22
+ # FIXME trace
23
+ raise InterfaceError, "the trace module has been removed until it actually works."
24
+ @trace_mode = mode || @trace_mode || DBI::DEFAULT_TRACE_MODE
25
+ @trace_output = output || @trace_output || DBI::DEFAULT_TRACE_OUTPUT
26
+ end
27
+
28
+ #
29
+ # Leverage a driver-specific method. The method name will have "__"
30
+ # prepended to them before calling, and the DBD must define them as
31
+ # such for them to work.
32
+ #
33
+ def func(function, *values)
34
+ if @handle.respond_to?("__" + function.to_s) then
35
+ @handle.send("__" + function.to_s, *values)
36
+ else
37
+ raise InterfaceError, "Driver specific function <#{function}> not available."
38
+ end
39
+ rescue ArgumentError
40
+ raise InterfaceError, "Wrong # of arguments for driver specific function"
41
+ end
42
+
43
+ # error functions?
44
+ end
45
+ end
46
+
47
+ require 'dbi/handles/driver'
48
+ require 'dbi/handles/database'
49
+ require 'dbi/handles/statement'
@@ -0,0 +1,229 @@
1
+ module DBI
2
+ # DatabaseHandle is the interface the consumer sees after connecting to the
3
+ # database via DBI.connect.
4
+ #
5
+ # It is strongly discouraged that DBDs inherit from this class directly;
6
+ # please inherit from the DBI::BaseDatabase instead.
7
+ #
8
+ # Note: almost all methods in this class will raise InterfaceError if the
9
+ # database is not connected.
10
+ class DatabaseHandle < Handle
11
+
12
+ attr_accessor :raise_error
13
+
14
+ # This is the driver name as supplied by the DBD's driver_name method.
15
+ # Its primary utility is in DBI::TypeUtil#convert.
16
+ def driver_name
17
+ return @driver_name.dup if @driver_name
18
+ return nil
19
+ end
20
+
21
+ # Assign the driver name. This can be leveraged to create custom type
22
+ # management via DBI::TypeUtil#convert.
23
+ def driver_name=(name)
24
+ @driver_name = name
25
+ @driver_name.freeze
26
+ end
27
+
28
+ #
29
+ # Boolean if we are still connected to the database. See #ping.
30
+ #
31
+ def connected?
32
+ not @handle.nil?
33
+ end
34
+
35
+ #
36
+ # Disconnect from the database. Will raise InterfaceError if this was
37
+ # already done prior.
38
+ #
39
+ def disconnect
40
+ sanity_check
41
+ @handle.disconnect
42
+ @handle = nil
43
+ end
44
+
45
+ #
46
+ # Prepare a StatementHandle and return it. If given a block, it will
47
+ # supply that StatementHandle as the first argument to the block, and
48
+ # BaseStatement#finish it when the block is done executing.
49
+ #
50
+ def prepare(stmt)
51
+ sanity_check(stmt)
52
+ sth = StatementHandle.new(@handle.prepare(stmt), false, true, @convert_types)
53
+ # FIXME trace sth.trace(@trace_mode, @trace_output)
54
+ sth.dbh = self
55
+ sth.raise_error = raise_error
56
+
57
+ if block_given?
58
+ begin
59
+ yield sth
60
+ ensure
61
+ sth.finish unless sth.finished?
62
+ end
63
+ else
64
+ return sth
65
+ end
66
+ end
67
+
68
+ #
69
+ # Prepare and execute a statement. It has block semantics equivalent to #prepare.
70
+ #
71
+ def execute(stmt, bindvars={})
72
+ sanity_check(stmt)
73
+
74
+ if @convert_types
75
+ bindvars = DBI::Utils::ConvParam.conv_param(driver_name, bindvars)
76
+ end
77
+
78
+ sth = StatementHandle.new(@handle.execute(stmt, bindvars), true, true, @convert_types, true)
79
+ # FIXME trace sth.trace(@trace_mode, @trace_output)
80
+ sth.dbh = self
81
+ sth.raise_error = raise_error
82
+
83
+ if block_given?
84
+ begin
85
+ yield sth
86
+ ensure
87
+ sth.finish unless sth.finished?
88
+ end
89
+ else
90
+ return sth
91
+ end
92
+ end
93
+
94
+ #
95
+ # Perform a statement. This goes straight to the DBD's implementation
96
+ # of #do (and consequently, BaseDatabase#do), and does not work like
97
+ # #execute and #prepare. Should return a row modified count.
98
+ #
99
+ def do(stmt, bindvars={})
100
+ sanity_check(stmt)
101
+ @handle.do(stmt, bindvars)
102
+ #@handle.do(stmt, DBI::Utils::ConvParam.conv_param(driver_name, bindvars))
103
+ end
104
+
105
+ #
106
+ # Executes a statement and returns the first row from the result.
107
+ #
108
+ def select_one(stmt, bindvars={})
109
+ sanity_check(stmt)
110
+ row = nil
111
+ execute(stmt, bindvars) do |sth|
112
+ row = sth.fetch
113
+ end
114
+ row
115
+ end
116
+
117
+ #
118
+ # Executes a statement and returns all rows from the result. If a block
119
+ # is given, it is executed for each row.
120
+ #
121
+ def select_all(stmt, bindvars={}, &p)
122
+ sanity_check(stmt)
123
+ rows = nil
124
+ execute(stmt, bindvars) do |sth|
125
+ if block_given?
126
+ sth.each(&p)
127
+ else
128
+ rows = sth.fetch_all
129
+ end
130
+ end
131
+ return rows
132
+ end
133
+
134
+ #
135
+ # Return the tables available to this DatabaseHandle as an array of strings.
136
+ #
137
+ def tables
138
+ sanity_check
139
+ @handle.tables
140
+ end
141
+
142
+ #
143
+ # Returns the columns of the provided table as an array of ColumnInfo
144
+ # objects. See BaseDatabase#columns for the minimum parameters that
145
+ # this method must provide.
146
+ #
147
+ def columns( table )
148
+ sanity_check
149
+ @handle.columns( table ).collect {|col| ColumnInfo.new(col) }
150
+ end
151
+
152
+ #
153
+ # Attempt to establish if the database is still connected. While
154
+ # #connected? returns the state the DatabaseHandle thinks is true, this
155
+ # is an active operation that will contact the database.
156
+ #
157
+ def ping
158
+ sanity_check
159
+ @handle.ping
160
+ end
161
+
162
+ #
163
+ # Attempt to escape the value, rendering it suitable for inclusion in a SQL statement.
164
+ #
165
+ def quote(value)
166
+ sanity_check
167
+ @handle.quote(value)
168
+ end
169
+
170
+ #
171
+ # Force a commit to the database immediately.
172
+ #
173
+ def commit
174
+ sanity_check
175
+ @handle.commit
176
+ end
177
+
178
+ #
179
+ # Force a rollback to the database immediately.
180
+ #
181
+ def rollback
182
+ sanity_check
183
+ @handle.rollback
184
+ end
185
+
186
+ #
187
+ # Commits, runs the block provided, yielding the DatabaseHandle as it's
188
+ # argument. If an exception is raised through the block, rollback occurs.
189
+ # Otherwise, commit occurs.
190
+ #
191
+ def transaction
192
+ sanity_check
193
+ raise InterfaceError, "No block given" unless block_given?
194
+
195
+ commit
196
+ begin
197
+ yield self
198
+ commit
199
+ rescue Exception
200
+ rollback
201
+ raise
202
+ end
203
+ end
204
+
205
+ # Get an attribute from the DatabaseHandle.
206
+ def [] (attr)
207
+ sanity_check
208
+ @handle[attr]
209
+ end
210
+
211
+ # Set an attribute on the DatabaseHandle.
212
+ def []= (attr, val)
213
+ sanity_check
214
+ @handle[attr] = val
215
+ end
216
+
217
+ protected
218
+
219
+ def sanity_check(stmt=nil)
220
+ raise InterfaceError, "Database connection was already closed!" if @handle.nil?
221
+ check_statement(stmt) if stmt
222
+ end
223
+
224
+ # basic sanity checks for statements
225
+ def check_statement(stmt)
226
+ raise InterfaceError, "Statement is empty, or contains nothing but whitespace" if stmt !~ /\S/
227
+ end
228
+ end
229
+ end
@@ -0,0 +1,60 @@
1
+ module DBI
2
+ # DriverHandles, while not directly exposed, are essentially the backend
3
+ # for the facade that many DBI root-level methods communicate with.
4
+ class DriverHandle < Handle
5
+
6
+ attr_writer :driver_name
7
+
8
+ # Connect to the database. The DSN will have been parsed at this point
9
+ # and the named parameters should need no explanation.
10
+ #
11
+ # If a block is provided to DBI.connect, the connected DatabaseHandle
12
+ # will be provided as the first argument to the block, and the
13
+ # DatabaseHandle will be disconnected upon block exit.
14
+ #
15
+ def connect(db_args, user, auth, params)
16
+
17
+ user = @handle.default_user[0] if user.nil?
18
+ auth = @handle.default_user[1] if auth.nil?
19
+
20
+ # TODO: what if only one of them is nil?
21
+ #if user.nil? and auth.nil? then
22
+ # user, auth = @handle.default_user
23
+ #end
24
+
25
+ params ||= {}
26
+ new_params = @handle.default_attributes
27
+ params.each {|k,v| new_params[k] = v}
28
+
29
+ if params.has_key?(:_convert_types)
30
+ @convert_types = params[:_convert_types]
31
+ end
32
+
33
+ db = @handle.connect(db_args, user, auth, new_params)
34
+ dbh = DatabaseHandle.new(db, @convert_types)
35
+ # FIXME trace
36
+ # dbh.trace(@trace_mode, @trace_output)
37
+ dbh.driver_name = @driver_name
38
+
39
+ if block_given?
40
+ begin
41
+ yield dbh
42
+ ensure
43
+ dbh.disconnect if dbh.connected?
44
+ end
45
+ else
46
+ return dbh
47
+ end
48
+ end
49
+
50
+ # See BaseDriver#data_sources.
51
+ def data_sources
52
+ @handle.data_sources
53
+ end
54
+
55
+ # See BaseDriver#disconnect_all.
56
+ def disconnect_all
57
+ @handle.disconnect_all
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,408 @@
1
+ module DBI
2
+ #
3
+ # StatementHandle is the interface the consumer sees after successfully
4
+ # issuing a DatabaseHandle#prepare. They may also be exposed through other
5
+ # methods that send statements to the database.
6
+ #
7
+ # Almost all methods in this class will raise InterfaceError if the
8
+ # statement is already finished.
9
+ #
10
+ class StatementHandle < Handle
11
+
12
+ include Enumerable
13
+
14
+ attr_accessor :dbh
15
+ attr_accessor :raise_error
16
+
17
+ def initialize(handle, fetchable=false, prepared=true, convert_types=true, executed=false)
18
+ super(handle)
19
+ @fetchable = fetchable
20
+ @prepared = prepared # only false if immediate execute was used
21
+ @executed = executed # only true if the statement was already executed.
22
+ @cols = nil
23
+ @coltypes = nil
24
+ @convert_types = convert_types
25
+
26
+ if @fetchable
27
+ @row = DBI::Row.new(column_names, column_types, nil, @convert_types)
28
+ else
29
+ @row = nil
30
+ end
31
+ end
32
+
33
+ # Returns true if the StatementHandle has had #finish called on it,
34
+ # explicitly or otherwise.
35
+ def finished?
36
+ @handle.nil?
37
+ end
38
+
39
+ # Returns true if the statement is believed to return data upon #fetch.
40
+ #
41
+ # The current reliability of this (and the concept in general) is
42
+ # suspect.
43
+ def fetchable?
44
+ @fetchable
45
+ end
46
+
47
+ #
48
+ # Instruct successive calls to #fetch to cast the type returned into
49
+ # `type`, for row position `pos`. Like all bind_* calls, `pos` indexes
50
+ # starting at 1.
51
+ #
52
+ # `type` is an object with the DBI::Type calling convention.
53
+ #
54
+ # This call must be called after #execute has successfully ran,
55
+ # otherwise it will raise InterfaceError.
56
+ #
57
+ # Example:
58
+ # # `foo` is an integer and this statement will return two rows.
59
+ # sth = dbh.prepare("select foo from bar")
60
+ # # would raise InterfaceError if called here
61
+ # sth.execute
62
+ #
63
+ # sth.bind_coltype(1, DBI::Type::Varchar)
64
+ # # would normally use DBI::Type::Integer and return a Fixnum. We'll make it a string.
65
+ # sth.fetch => ["1"]
66
+ #
67
+ # # Here we coerce it to Float.
68
+ # sth.bind_coltype(1, DBI::Type::Float)
69
+ # sth.fetch => [1.0]
70
+ # sth.finish
71
+ #
72
+ def bind_coltype(pos, type)
73
+ sanity_check({:prepared => true, :executed => true})
74
+
75
+ coltypes = column_types
76
+
77
+ if (pos - 1) < 1
78
+ raise InterfaceError, "bind positions index starting at 1"
79
+ end
80
+
81
+ coltypes[pos-1] = type
82
+ @row = DBI::Row.new(column_names, coltypes, nil, @convert_types)
83
+ end
84
+
85
+ #
86
+ # Just like BaseStatement#bind_param, but will attempt to convert the
87
+ # type if it's supposed to, adhering to the DBD's current ruleset.
88
+ #
89
+ def bind_param(param, value, attribs=nil)
90
+ sanity_check({ :prepared => true })
91
+
92
+ if @convert_types
93
+ value = DBI::Utils::ConvParam.conv_param(dbh.driver_name, value)[0]
94
+ end
95
+
96
+ @handle.bind_param(param, value, attribs)
97
+ end
98
+
99
+
100
+ # Execute the statement.
101
+ #
102
+ # This generally means that the statement will be sent to the database
103
+ # and some form of result cursor will be obtained, but is ultimately
104
+ # driver-dependent.
105
+ #
106
+ # If arguments are supplied, these are fed to #bind_param.
107
+ def execute(bindvars={})
108
+ cancel # cancel before
109
+ sanity_check({:prepared => true })
110
+
111
+ if @convert_types
112
+ bindvars = DBI::Utils::ConvParam.conv_param(dbh.driver_name, bindvars)
113
+ end
114
+
115
+ @handle.bind_params(bindvars)
116
+ @handle.execute
117
+ @fetchable = true
118
+ @executed = true
119
+
120
+ # TODO:?
121
+ #if @row.nil?
122
+ @row = DBI::Row.new(column_names, column_types, nil, @convert_types)
123
+ #end
124
+ return nil
125
+ end
126
+
127
+ #
128
+ # Finish the statement, causing the database to release all assets
129
+ # related to it (any result cursors, normally).
130
+ #
131
+ # StatementHandles that have already been finished will normally be
132
+ # inoperable and unavailable for further use.
133
+ #
134
+ def finish
135
+ sanity_check
136
+ @handle.finish
137
+ @handle = nil
138
+ end
139
+
140
+ #
141
+ # Cancel the query, closing any open result cursors and truncating any result sets.
142
+ #
143
+ # The difference between this and #finish is that cancelled statements
144
+ # may be re-executed.
145
+ #
146
+ def cancel
147
+ sanity_check
148
+ @handle.cancel if @fetchable
149
+ @fetchable = false
150
+ end
151
+
152
+ #
153
+ # Obtains the column names for this query as an array.
154
+ #
155
+ def column_names
156
+ sanity_check
157
+ return @cols unless @cols.nil?
158
+ @cols = @handle.column_info.collect {|col| col['name'] }
159
+ end
160
+
161
+ #
162
+ # Obtain the type mappings for the columns in this query based on
163
+ # ColumnInfo data on the query.
164
+ #
165
+ # The result will be a position-dependent array of objects that conform
166
+ # to the DBI::Type calling syntax.
167
+ #
168
+ def column_types
169
+ sanity_check
170
+ return @coltypes unless @coltypes.nil?
171
+ @coltypes = @handle.column_info.collect do |col|
172
+ if col['dbi_type']
173
+ col['dbi_type']
174
+ else
175
+ DBI::TypeUtil.type_name_to_module(col['type_name'])
176
+ end
177
+ end
178
+ end
179
+
180
+ #
181
+ # See BaseStatement#column_info.
182
+ #
183
+ def column_info
184
+ sanity_check
185
+ @handle.column_info.collect {|col| ColumnInfo.new(col) }
186
+ end
187
+
188
+ #
189
+ # Should return the row modified count as the result of statement execution.
190
+ #
191
+ # However, some low-level drivers do not supply this information or
192
+ # supply misleading information (> 0 rows for read-only select
193
+ # statements, f.e.)
194
+ #
195
+ def rows
196
+ sanity_check
197
+ @handle.rows
198
+ end
199
+
200
+
201
+ #
202
+ # See BaseStatement#fetch.
203
+ #
204
+ # fetch can also take a block which will be applied to each row in a
205
+ # similar fashion to Enumerable#collect. See #each.
206
+ #
207
+ def fetch(&p)
208
+ sanity_check({ :fetchable => true, :prepared => true, :executed => true })
209
+
210
+ if block_given?
211
+ while (res = @handle.fetch) != nil
212
+ @row = @row.dup
213
+ @row.set_values(res)
214
+ yield @row
215
+ end
216
+ @handle.cancel
217
+ @fetchable = false
218
+ return nil
219
+ else
220
+ res = @handle.fetch
221
+ if res.nil?
222
+ @handle.cancel
223
+ @fetchable = false
224
+ else
225
+ @row = @row.dup
226
+ @row.set_values(res)
227
+ res = @row
228
+ end
229
+ return res
230
+ end
231
+ end
232
+
233
+ #
234
+ # Synonym for #fetch with a block.
235
+ #
236
+ def each(&p)
237
+ sanity_check({:fetchable => true, :prepared => true, :executed => true})
238
+ raise InterfaceError, "No block given" unless block_given?
239
+
240
+ fetch(&p)
241
+ end
242
+
243
+ #
244
+ # Similar to #fetch, but returns Array of Array instead of Array of
245
+ # DBI::Row objects (and therefore does not perform type mapping). This
246
+ # is basically a way to get the raw data from the DBD.
247
+ #
248
+ def fetch_array
249
+ sanity_check({:fetchable => true, :prepared => true, :executed => true})
250
+
251
+ if block_given?
252
+ while (res = @handle.fetch) != nil
253
+ yield res
254
+ end
255
+ @handle.cancel
256
+ @fetchable = false
257
+ return nil
258
+ else
259
+ res = @handle.fetch
260
+ if res.nil?
261
+ @handle.cancel
262
+ @fetchable = false
263
+ end
264
+ return res
265
+ end
266
+ end
267
+
268
+ #
269
+ # Map the columns and results into an Array of Hash resultset.
270
+ #
271
+ # No type conversion is performed here. Expect this to change in 0.6.0.
272
+ #
273
+ def fetch_hash
274
+ sanity_check({:fetchable => true, :prepared => true, :executed => true})
275
+
276
+ cols = column_names
277
+
278
+ if block_given?
279
+ while (row = @handle.fetch) != nil
280
+ hash = {}
281
+ row.each_with_index {|v, i| hash[cols[i]] = v}
282
+ yield hash
283
+ end
284
+ @handle.cancel
285
+ @fetchable = false
286
+ return nil
287
+ else
288
+ row = @handle.fetch
289
+ if row.nil?
290
+ @handle.cancel
291
+ @fetchable = false
292
+ return nil
293
+ else
294
+ hash = {}
295
+ row.each_with_index {|v, i| hash[cols[i]] = v}
296
+ return hash
297
+ end
298
+ end
299
+ end
300
+
301
+ #
302
+ # Fetch `cnt` rows. Result is array of DBI::Row
303
+ #
304
+ def fetch_many(cnt)
305
+ sanity_check({:fetchable => true, :prepared => true, :executed => true})
306
+
307
+ cols = column_names
308
+ rows = @handle.fetch_many(cnt)
309
+ if rows.nil? or rows.empty?
310
+ @handle.cancel
311
+ @fetchable = false
312
+ return []
313
+ else
314
+ return rows.collect{|r| tmp = @row.dup; tmp.set_values(r); tmp }
315
+ end
316
+ end
317
+
318
+ #
319
+ # Fetch the entire result set. Result is array of DBI::Row.
320
+ #
321
+ def fetch_all
322
+ sanity_check({:fetchable => true, :prepared => true, :executed => true})
323
+
324
+ cols = column_names
325
+ fetched_rows = []
326
+
327
+ begin
328
+ while row = fetch do
329
+ fetched_rows.push(row)
330
+ end
331
+ rescue Exception
332
+ end
333
+
334
+ @handle.cancel
335
+ @fetchable = false
336
+
337
+ return fetched_rows
338
+ end
339
+
340
+ #
341
+ # See BaseStatement#fetch_scroll.
342
+ #
343
+ def fetch_scroll(direction, offset=1)
344
+ sanity_check({:fetchable => true, :prepared => true, :executed => true})
345
+
346
+ row = @handle.fetch_scroll(direction, offset)
347
+ if row.nil?
348
+ #@handle.cancel
349
+ #@fetchable = false
350
+ return nil
351
+ else
352
+ @row.set_values(row)
353
+ return @row
354
+ end
355
+ end
356
+
357
+ # Get an attribute from the StatementHandle object.
358
+ def [] (attr)
359
+ sanity_check
360
+ @handle[attr]
361
+ end
362
+
363
+ # Set an attribute on the StatementHandle object.
364
+ def []= (attr, val)
365
+ sanity_check
366
+ @handle[attr] = val
367
+ end
368
+
369
+ protected
370
+
371
+ def sanity_check(params={})
372
+ raise InterfaceError, "Statement was already closed!" if @handle.nil?
373
+
374
+ params.each_key do |key|
375
+ case key
376
+ when :fetchable
377
+ check_fetchable
378
+ when :executed
379
+ check_executed
380
+ when :prepared
381
+ check_prepared
382
+ when :statement
383
+ check_statement(params[:statement])
384
+ end
385
+ end
386
+ end
387
+
388
+ def check_prepared
389
+ raise InterfaceError, "Statement wasn't prepared before." unless @prepared
390
+ end
391
+
392
+ def check_fetchable
393
+ if !@fetchable and @raise_error
394
+ raise InterfaceError, "Statement does not have any data for fetching."
395
+ end
396
+ end
397
+
398
+ def check_executed
399
+ raise InterfaceError, "Statement hasn't been executed yet." unless @executed
400
+ end
401
+
402
+ # basic sanity checks for statements
403
+ def check_statement(stmt)
404
+ raise InterfaceError, "Statement is empty, or contains nothing but whitespace" if stmt !~ /\S/
405
+ end
406
+
407
+ end # class StatementHandle
408
+ end