sqlite3 1.3.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.
Files changed (53) hide show
  1. data/API_CHANGES.rdoc +50 -0
  2. data/CHANGELOG.rdoc +177 -0
  3. data/ChangeLog.cvs +88 -0
  4. data/LICENSE +27 -0
  5. data/Manifest.txt +50 -0
  6. data/README.rdoc +103 -0
  7. data/Rakefile +10 -0
  8. data/ext/sqlite3/backup.c +164 -0
  9. data/ext/sqlite3/backup.h +15 -0
  10. data/ext/sqlite3/database.c +762 -0
  11. data/ext/sqlite3/database.h +15 -0
  12. data/ext/sqlite3/exception.c +94 -0
  13. data/ext/sqlite3/exception.h +8 -0
  14. data/ext/sqlite3/extconf.rb +47 -0
  15. data/ext/sqlite3/sqlite3.c +36 -0
  16. data/ext/sqlite3/sqlite3_ruby.h +44 -0
  17. data/ext/sqlite3/statement.c +419 -0
  18. data/ext/sqlite3/statement.h +16 -0
  19. data/faq/faq.rb +145 -0
  20. data/faq/faq.yml +426 -0
  21. data/lib/sqlite3.rb +10 -0
  22. data/lib/sqlite3/1.8/sqlite3_native.so +0 -0
  23. data/lib/sqlite3/1.9/sqlite3_native.so +0 -0
  24. data/lib/sqlite3/constants.rb +49 -0
  25. data/lib/sqlite3/database.rb +587 -0
  26. data/lib/sqlite3/errors.rb +44 -0
  27. data/lib/sqlite3/pragmas.rb +280 -0
  28. data/lib/sqlite3/resultset.rb +126 -0
  29. data/lib/sqlite3/statement.rb +148 -0
  30. data/lib/sqlite3/translator.rb +118 -0
  31. data/lib/sqlite3/value.rb +57 -0
  32. data/lib/sqlite3/version.rb +25 -0
  33. data/setup.rb +1333 -0
  34. data/tasks/faq.rake +9 -0
  35. data/tasks/gem.rake +31 -0
  36. data/tasks/native.rake +61 -0
  37. data/tasks/vendor_sqlite3.rake +104 -0
  38. data/test/helper.rb +3 -0
  39. data/test/test_backup.rb +33 -0
  40. data/test/test_collation.rb +82 -0
  41. data/test/test_database.rb +312 -0
  42. data/test/test_database_readonly.rb +29 -0
  43. data/test/test_deprecated.rb +37 -0
  44. data/test/test_encoding.rb +119 -0
  45. data/test/test_integration.rb +544 -0
  46. data/test/test_integration_open_close.rb +30 -0
  47. data/test/test_integration_pending.rb +115 -0
  48. data/test/test_integration_resultset.rb +156 -0
  49. data/test/test_integration_statement.rb +194 -0
  50. data/test/test_sqlite3.rb +9 -0
  51. data/test/test_statement.rb +207 -0
  52. data/test/test_statement_execute.rb +35 -0
  53. metadata +202 -0
@@ -0,0 +1,10 @@
1
+ # support multiple ruby version (fat binaries under windows)
2
+ begin
3
+ RUBY_VERSION =~ /(\d+.\d+)/
4
+ require "sqlite3/#{$1}/sqlite3_native"
5
+ rescue LoadError
6
+ require 'sqlite3/sqlite3_native'
7
+ end
8
+
9
+ require 'sqlite3/database'
10
+ require 'sqlite3/version'
@@ -0,0 +1,49 @@
1
+ module SQLite3 ; module Constants
2
+
3
+ module TextRep
4
+ UTF8 = 1
5
+ UTF16LE = 2
6
+ UTF16BE = 3
7
+ UTF16 = 4
8
+ ANY = 5
9
+ end
10
+
11
+ module ColumnType
12
+ INTEGER = 1
13
+ FLOAT = 2
14
+ TEXT = 3
15
+ BLOB = 4
16
+ NULL = 5
17
+ end
18
+
19
+ module ErrorCode
20
+ OK = 0 # Successful result
21
+ ERROR = 1 # SQL error or missing database
22
+ INTERNAL = 2 # An internal logic error in SQLite
23
+ PERM = 3 # Access permission denied
24
+ ABORT = 4 # Callback routine requested an abort
25
+ BUSY = 5 # The database file is locked
26
+ LOCKED = 6 # A table in the database is locked
27
+ NOMEM = 7 # A malloc() failed
28
+ READONLY = 8 # Attempt to write a readonly database
29
+ INTERRUPT = 9 # Operation terminated by sqlite_interrupt()
30
+ IOERR = 10 # Some kind of disk I/O error occurred
31
+ CORRUPT = 11 # The database disk image is malformed
32
+ NOTFOUND = 12 # (Internal Only) Table or record not found
33
+ FULL = 13 # Insertion failed because database is full
34
+ CANTOPEN = 14 # Unable to open the database file
35
+ PROTOCOL = 15 # Database lock protocol error
36
+ EMPTY = 16 # (Internal Only) Database table is empty
37
+ SCHEMA = 17 # The database schema changed
38
+ TOOBIG = 18 # Too much data for one row of a table
39
+ CONSTRAINT = 19 # Abort due to contraint violation
40
+ MISMATCH = 20 # Data type mismatch
41
+ MISUSE = 21 # Library used incorrectly
42
+ NOLFS = 22 # Uses OS features not supported on host
43
+ AUTH = 23 # Authorization denied
44
+
45
+ ROW = 100 # sqlite_step() has another row ready
46
+ DONE = 101 # sqlite_step() has finished executing
47
+ end
48
+
49
+ end ; end
@@ -0,0 +1,587 @@
1
+ require 'sqlite3/constants'
2
+ require 'sqlite3/errors'
3
+ require 'sqlite3/pragmas'
4
+ require 'sqlite3/statement'
5
+ require 'sqlite3/translator'
6
+ require 'sqlite3/value'
7
+
8
+ module SQLite3
9
+
10
+ # The Database class encapsulates a single connection to a SQLite3 database.
11
+ # Its usage is very straightforward:
12
+ #
13
+ # require 'sqlite3'
14
+ #
15
+ # SQLite3::Database.new( "data.db" ) do |db|
16
+ # db.execute( "select * from table" ) do |row|
17
+ # p row
18
+ # end
19
+ # end
20
+ #
21
+ # It wraps the lower-level methods provides by the selected driver, and
22
+ # includes the Pragmas module for access to various pragma convenience
23
+ # methods.
24
+ #
25
+ # The Database class provides type translation services as well, by which
26
+ # the SQLite3 data types (which are all represented as strings) may be
27
+ # converted into their corresponding types (as defined in the schemas
28
+ # for their tables). This translation only occurs when querying data from
29
+ # the database--insertions and updates are all still typeless.
30
+ #
31
+ # Furthermore, the Database class has been designed to work well with the
32
+ # ArrayFields module from Ara Howard. If you require the ArrayFields
33
+ # module before performing a query, and if you have not enabled results as
34
+ # hashes, then the results will all be indexible by field name.
35
+ class Database
36
+ attr_reader :collations
37
+
38
+ include Pragmas
39
+
40
+ class << self
41
+
42
+ alias :open :new
43
+
44
+ # Quotes the given string, making it safe to use in an SQL statement.
45
+ # It replaces all instances of the single-quote character with two
46
+ # single-quote characters. The modified string is returned.
47
+ def quote( string )
48
+ string.gsub( /'/, "''" )
49
+ end
50
+
51
+ end
52
+
53
+ # A boolean that indicates whether rows in result sets should be returned
54
+ # as hashes or not. By default, rows are returned as arrays.
55
+ attr_accessor :results_as_hash
56
+
57
+ def type_translation= value # :nodoc:
58
+ warn(<<-eowarn) if $VERBOSE
59
+ #{caller[0]} is calling SQLite3::Database#type_translation=
60
+ SQLite3::Database#type_translation= is deprecated and will be removed
61
+ in version 2.0.0.
62
+ eowarn
63
+ @type_translation = value
64
+ end
65
+ attr_reader :type_translation # :nodoc:
66
+
67
+ # Return the type translator employed by this database instance. Each
68
+ # database instance has its own type translator; this allows for different
69
+ # type handlers to be installed in each instance without affecting other
70
+ # instances. Furthermore, the translators are instantiated lazily, so that
71
+ # if a database does not use type translation, it will not be burdened by
72
+ # the overhead of a useless type translator. (See the Translator class.)
73
+ def translator
74
+ @translator ||= Translator.new
75
+ end
76
+
77
+ # Installs (or removes) a block that will be invoked for every access
78
+ # to the database. If the block returns 0 (or +nil+), the statement
79
+ # is allowed to proceed. Returning 1 causes an authorization error to
80
+ # occur, and returning 2 causes the access to be silently denied.
81
+ def authorizer( &block )
82
+ self.authorizer = block
83
+ end
84
+
85
+ # Returns a Statement object representing the given SQL. This does not
86
+ # execute the statement; it merely prepares the statement for execution.
87
+ #
88
+ # The Statement can then be executed using Statement#execute.
89
+ #
90
+ def prepare sql
91
+ stmt = SQLite3::Statement.new( self, sql )
92
+ return stmt unless block_given?
93
+
94
+ begin
95
+ yield stmt
96
+ ensure
97
+ stmt.close
98
+ end
99
+ end
100
+
101
+ # Executes the given SQL statement. If additional parameters are given,
102
+ # they are treated as bind variables, and are bound to the placeholders in
103
+ # the query.
104
+ #
105
+ # Note that if any of the values passed to this are hashes, then the
106
+ # key/value pairs are each bound separately, with the key being used as
107
+ # the name of the placeholder to bind the value to.
108
+ #
109
+ # The block is optional. If given, it will be invoked for each row returned
110
+ # by the query. Otherwise, any results are accumulated into an array and
111
+ # returned wholesale.
112
+ #
113
+ # See also #execute2, #query, and #execute_batch for additional ways of
114
+ # executing statements.
115
+ def execute sql, bind_vars = [], *args, &block
116
+ # FIXME: This is a terrible hack and should be removed but is required
117
+ # for older versions of rails
118
+ hack = Object.const_defined?(:ActiveRecord) && sql =~ /^PRAGMA index_list/
119
+
120
+ if bind_vars.nil? || !args.empty?
121
+ if args.empty?
122
+ bind_vars = []
123
+ else
124
+ bind_vars = [bind_vars] + args
125
+ end
126
+
127
+ warn(<<-eowarn) if $VERBOSE
128
+ #{caller[0]} is calling SQLite3::Database#execute with nil or multiple bind params
129
+ without using an array. Please switch to passing bind parameters as an array.
130
+ Support for bind parameters as *args will be removed in 2.0.0.
131
+ eowarn
132
+ end
133
+
134
+ prepare( sql ) do |stmt|
135
+ stmt.bind_params(bind_vars)
136
+ columns = stmt.columns
137
+ stmt = ResultSet.new(self, stmt).to_a if type_translation
138
+
139
+ if block_given?
140
+ stmt.each do |row|
141
+ if @results_as_hash
142
+ yield type_translation ? row : ordered_map_for(columns, row)
143
+ else
144
+ yield row
145
+ end
146
+ end
147
+ else
148
+ if @results_as_hash
149
+ stmt.map { |row|
150
+ h = type_translation ? row : ordered_map_for(columns, row)
151
+
152
+ # FIXME UGH TERRIBLE HACK!
153
+ h['unique'] = h['unique'].to_s if hack
154
+
155
+ h
156
+ }
157
+ else
158
+ stmt.to_a
159
+ end
160
+ end
161
+ end
162
+ end
163
+
164
+ # Executes the given SQL statement, exactly as with #execute. However, the
165
+ # first row returned (either via the block, or in the returned array) is
166
+ # always the names of the columns. Subsequent rows correspond to the data
167
+ # from the result set.
168
+ #
169
+ # Thus, even if the query itself returns no rows, this method will always
170
+ # return at least one row--the names of the columns.
171
+ #
172
+ # See also #execute, #query, and #execute_batch for additional ways of
173
+ # executing statements.
174
+ def execute2( sql, *bind_vars )
175
+ prepare( sql ) do |stmt|
176
+ result = stmt.execute( *bind_vars )
177
+ if block_given?
178
+ yield stmt.columns
179
+ result.each { |row| yield row }
180
+ else
181
+ return result.inject( [ stmt.columns ] ) { |arr,row|
182
+ arr << row; arr }
183
+ end
184
+ end
185
+ end
186
+
187
+ # Executes all SQL statements in the given string. By contrast, the other
188
+ # means of executing queries will only execute the first statement in the
189
+ # string, ignoring all subsequent statements. This will execute each one
190
+ # in turn. The same bind parameters, if given, will be applied to each
191
+ # statement.
192
+ #
193
+ # This always returns +nil+, making it unsuitable for queries that return
194
+ # rows.
195
+ def execute_batch( sql, bind_vars = [], *args )
196
+ # FIXME: remove this stuff later
197
+ unless [Array, Hash].include?(bind_vars.class)
198
+ bind_vars = [bind_vars]
199
+ warn(<<-eowarn) if $VERBOSE
200
+ #{caller[0]} is calling SQLite3::Database#execute_batch with bind parameters
201
+ that are not a list of a hash. Please switch to passing bind parameters as an
202
+ array or hash. Support for this behavior will be removed in version 2.0.0.
203
+ eowarn
204
+ end
205
+
206
+ # FIXME: remove this stuff later
207
+ if bind_vars.nil? || !args.empty?
208
+ if args.empty?
209
+ bind_vars = []
210
+ else
211
+ bind_vars = [nil] + args
212
+ end
213
+
214
+ warn(<<-eowarn) if $VERBOSE
215
+ #{caller[0]} is calling SQLite3::Database#execute_batch with nil or multiple bind params
216
+ without using an array. Please switch to passing bind parameters as an array.
217
+ Support for this behavior will be removed in version 2.0.0.
218
+ eowarn
219
+ end
220
+
221
+ sql = sql.strip
222
+ until sql.empty? do
223
+ prepare( sql ) do |stmt|
224
+ # FIXME: this should probably use sqlite3's api for batch execution
225
+ # This implementation requires stepping over the results.
226
+ if bind_vars.length == stmt.bind_parameter_count
227
+ stmt.bind_params(bind_vars)
228
+ end
229
+ stmt.step
230
+ sql = stmt.remainder.strip
231
+ end
232
+ end
233
+ nil
234
+ end
235
+
236
+ # This is a convenience method for creating a statement, binding
237
+ # paramters to it, and calling execute:
238
+ #
239
+ # result = db.query( "select * from foo where a=?", 5 )
240
+ # # is the same as
241
+ # result = db.prepare( "select * from foo where a=?" ).execute( 5 )
242
+ #
243
+ # You must be sure to call +close+ on the ResultSet instance that is
244
+ # returned, or you could have problems with locks on the table. If called
245
+ # with a block, +close+ will be invoked implicitly when the block
246
+ # terminates.
247
+ def query( sql, bind_vars = [], *args )
248
+
249
+ if bind_vars.nil? || !args.empty?
250
+ if args.empty?
251
+ bind_vars = []
252
+ else
253
+ bind_vars = [nil] + args
254
+ end
255
+
256
+ warn(<<-eowarn) if $VERBOSE
257
+ #{caller[0]} is calling SQLite3::Database#query with nil or multiple bind params
258
+ without using an array. Please switch to passing bind parameters as an array.
259
+ Support for this will be removed in version 2.0.0.
260
+ eowarn
261
+ end
262
+
263
+ result = prepare( sql ).execute( bind_vars )
264
+ if block_given?
265
+ begin
266
+ yield result
267
+ ensure
268
+ result.close
269
+ end
270
+ else
271
+ return result
272
+ end
273
+ end
274
+
275
+ # A convenience method for obtaining the first row of a result set, and
276
+ # discarding all others. It is otherwise identical to #execute.
277
+ #
278
+ # See also #get_first_value.
279
+ def get_first_row( sql, *bind_vars )
280
+ execute( sql, *bind_vars ).first
281
+ end
282
+
283
+ # A convenience method for obtaining the first value of the first row of a
284
+ # result set, and discarding all other values and rows. It is otherwise
285
+ # identical to #execute.
286
+ #
287
+ # See also #get_first_row.
288
+ def get_first_value( sql, *bind_vars )
289
+ execute( sql, *bind_vars ) { |row| return row[0] }
290
+ nil
291
+ end
292
+
293
+ alias :busy_timeout :busy_timeout=
294
+
295
+ # Creates a new function for use in SQL statements. It will be added as
296
+ # +name+, with the given +arity+. (For variable arity functions, use
297
+ # -1 for the arity.)
298
+ #
299
+ # The block should accept at least one parameter--the FunctionProxy
300
+ # instance that wraps this function invocation--and any other
301
+ # arguments it needs (up to its arity).
302
+ #
303
+ # The block does not return a value directly. Instead, it will invoke
304
+ # the FunctionProxy#result= method on the +func+ parameter and
305
+ # indicate the return value that way.
306
+ #
307
+ # Example:
308
+ #
309
+ # db.create_function( "maim", 1 ) do |func, value|
310
+ # if value.nil?
311
+ # func.result = nil
312
+ # else
313
+ # func.result = value.split(//).sort.join
314
+ # end
315
+ # end
316
+ #
317
+ # puts db.get_first_value( "select maim(name) from table" )
318
+ def create_function name, arity, text_rep=Constants::TextRep::ANY, &block
319
+ define_function(name) do |*args|
320
+ fp = FunctionProxy.new
321
+ block.call(fp, *args)
322
+ fp.result
323
+ end
324
+ self
325
+ end
326
+
327
+ # Creates a new aggregate function for use in SQL statements. Aggregate
328
+ # functions are functions that apply over every row in the result set,
329
+ # instead of over just a single row. (A very common aggregate function
330
+ # is the "count" function, for determining the number of rows that match
331
+ # a query.)
332
+ #
333
+ # The new function will be added as +name+, with the given +arity+. (For
334
+ # variable arity functions, use -1 for the arity.)
335
+ #
336
+ # The +step+ parameter must be a proc object that accepts as its first
337
+ # parameter a FunctionProxy instance (representing the function
338
+ # invocation), with any subsequent parameters (up to the function's arity).
339
+ # The +step+ callback will be invoked once for each row of the result set.
340
+ #
341
+ # The +finalize+ parameter must be a +proc+ object that accepts only a
342
+ # single parameter, the FunctionProxy instance representing the current
343
+ # function invocation. It should invoke FunctionProxy#result= to
344
+ # store the result of the function.
345
+ #
346
+ # Example:
347
+ #
348
+ # db.create_aggregate( "lengths", 1 ) do
349
+ # step do |func, value|
350
+ # func[ :total ] ||= 0
351
+ # func[ :total ] += ( value ? value.length : 0 )
352
+ # end
353
+ #
354
+ # finalize do |func|
355
+ # func.result = func[ :total ] || 0
356
+ # end
357
+ # end
358
+ #
359
+ # puts db.get_first_value( "select lengths(name) from table" )
360
+ #
361
+ # See also #create_aggregate_handler for a more object-oriented approach to
362
+ # aggregate functions.
363
+ def create_aggregate( name, arity, step=nil, finalize=nil,
364
+ text_rep=Constants::TextRep::ANY, &block )
365
+
366
+ factory = Class.new do
367
+ def self.step( &block )
368
+ define_method(:step, &block)
369
+ end
370
+
371
+ def self.finalize( &block )
372
+ define_method(:finalize, &block)
373
+ end
374
+ end
375
+
376
+ if block_given?
377
+ factory.instance_eval(&block)
378
+ else
379
+ factory.class_eval do
380
+ define_method(:step, step)
381
+ define_method(:finalize, finalize)
382
+ end
383
+ end
384
+
385
+ proxy = factory.new
386
+ proxy.extend(Module.new {
387
+ attr_accessor :ctx
388
+
389
+ def step( *args )
390
+ super(@ctx, *args)
391
+ end
392
+
393
+ def finalize
394
+ super(@ctx)
395
+ end
396
+ })
397
+ proxy.ctx = FunctionProxy.new
398
+ define_aggregator(name, proxy)
399
+ end
400
+
401
+ # This is another approach to creating an aggregate function (see
402
+ # #create_aggregate). Instead of explicitly specifying the name,
403
+ # callbacks, arity, and type, you specify a factory object
404
+ # (the "handler") that knows how to obtain all of that information. The
405
+ # handler should respond to the following messages:
406
+ #
407
+ # +arity+:: corresponds to the +arity+ parameter of #create_aggregate. This
408
+ # message is optional, and if the handler does not respond to it,
409
+ # the function will have an arity of -1.
410
+ # +name+:: this is the name of the function. The handler _must_ implement
411
+ # this message.
412
+ # +new+:: this must be implemented by the handler. It should return a new
413
+ # instance of the object that will handle a specific invocation of
414
+ # the function.
415
+ #
416
+ # The handler instance (the object returned by the +new+ message, described
417
+ # above), must respond to the following messages:
418
+ #
419
+ # +step+:: this is the method that will be called for each step of the
420
+ # aggregate function's evaluation. It should implement the same
421
+ # signature as the +step+ callback for #create_aggregate.
422
+ # +finalize+:: this is the method that will be called to finalize the
423
+ # aggregate function's evaluation. It should implement the
424
+ # same signature as the +finalize+ callback for
425
+ # #create_aggregate.
426
+ #
427
+ # Example:
428
+ #
429
+ # class LengthsAggregateHandler
430
+ # def self.arity; 1; end
431
+ #
432
+ # def initialize
433
+ # @total = 0
434
+ # end
435
+ #
436
+ # def step( ctx, name )
437
+ # @total += ( name ? name.length : 0 )
438
+ # end
439
+ #
440
+ # def finalize( ctx )
441
+ # ctx.result = @total
442
+ # end
443
+ # end
444
+ #
445
+ # db.create_aggregate_handler( LengthsAggregateHandler )
446
+ # puts db.get_first_value( "select lengths(name) from A" )
447
+ def create_aggregate_handler( handler )
448
+ proxy = Class.new do
449
+ def initialize handler
450
+ @handler = handler
451
+ @fp = FunctionProxy.new
452
+ end
453
+
454
+ def step( *args )
455
+ @handler.step(@fp, *args)
456
+ end
457
+
458
+ def finalize
459
+ @handler.finalize @fp
460
+ @fp.result
461
+ end
462
+ end
463
+ define_aggregator(handler.name, proxy.new(handler.new))
464
+ self
465
+ end
466
+
467
+ # Begins a new transaction. Note that nested transactions are not allowed
468
+ # by SQLite, so attempting to nest a transaction will result in a runtime
469
+ # exception.
470
+ #
471
+ # The +mode+ parameter may be either <tt>:deferred</tt> (the default),
472
+ # <tt>:immediate</tt>, or <tt>:exclusive</tt>.
473
+ #
474
+ # If a block is given, the database instance is yielded to it, and the
475
+ # transaction is committed when the block terminates. If the block
476
+ # raises an exception, a rollback will be performed instead. Note that if
477
+ # a block is given, #commit and #rollback should never be called
478
+ # explicitly or you'll get an error when the block terminates.
479
+ #
480
+ # If a block is not given, it is the caller's responsibility to end the
481
+ # transaction explicitly, either by calling #commit, or by calling
482
+ # #rollback.
483
+ def transaction( mode = :deferred )
484
+ execute "begin #{mode.to_s} transaction"
485
+ @transaction_active = true
486
+
487
+ if block_given?
488
+ abort = false
489
+ begin
490
+ yield self
491
+ rescue ::Object
492
+ abort = true
493
+ raise
494
+ ensure
495
+ abort and rollback or commit
496
+ end
497
+ end
498
+
499
+ true
500
+ end
501
+
502
+ # Commits the current transaction. If there is no current transaction,
503
+ # this will cause an error to be raised. This returns +true+, in order
504
+ # to allow it to be used in idioms like
505
+ # <tt>abort? and rollback or commit</tt>.
506
+ def commit
507
+ execute "commit transaction"
508
+ @transaction_active = false
509
+ true
510
+ end
511
+
512
+ # Rolls the current transaction back. If there is no current transaction,
513
+ # this will cause an error to be raised. This returns +true+, in order
514
+ # to allow it to be used in idioms like
515
+ # <tt>abort? and rollback or commit</tt>.
516
+ def rollback
517
+ execute "rollback transaction"
518
+ @transaction_active = false
519
+ true
520
+ end
521
+
522
+ # Returns +true+ if there is a transaction active, and +false+ otherwise.
523
+ def transaction_active?
524
+ @transaction_active
525
+ end
526
+
527
+ # Returns +true+ if the database has been open in readonly mode
528
+ # A helper to check before performing any operation
529
+ def readonly?
530
+ @readonly
531
+ end
532
+
533
+ # A helper class for dealing with custom functions (see #create_function,
534
+ # #create_aggregate, and #create_aggregate_handler). It encapsulates the
535
+ # opaque function object that represents the current invocation. It also
536
+ # provides more convenient access to the API functions that operate on
537
+ # the function object.
538
+ #
539
+ # This class will almost _always_ be instantiated indirectly, by working
540
+ # with the create methods mentioned above.
541
+ class FunctionProxy
542
+ attr_accessor :result
543
+
544
+ # Create a new FunctionProxy that encapsulates the given +func+ object.
545
+ # If context is non-nil, the functions context will be set to that. If
546
+ # it is non-nil, it must quack like a Hash. If it is nil, then none of
547
+ # the context functions will be available.
548
+ def initialize
549
+ @result = nil
550
+ @context = {}
551
+ end
552
+
553
+ # Set the result of the function to the given error message.
554
+ # The function will then return that error.
555
+ def set_error( error )
556
+ @driver.result_error( @func, error.to_s, -1 )
557
+ end
558
+
559
+ # (Only available to aggregate functions.) Returns the number of rows
560
+ # that the aggregate has processed so far. This will include the current
561
+ # row, and so will always return at least 1.
562
+ def count
563
+ @driver.aggregate_count( @func )
564
+ end
565
+
566
+ # Returns the value with the given key from the context. This is only
567
+ # available to aggregate functions.
568
+ def []( key )
569
+ @context[ key ]
570
+ end
571
+
572
+ # Sets the value with the given key in the context. This is only
573
+ # available to aggregate functions.
574
+ def []=( key, value )
575
+ @context[ key ] = value
576
+ end
577
+ end
578
+
579
+ private
580
+
581
+ def ordered_map_for columns, row
582
+ h = Hash[*columns.zip(row).flatten]
583
+ row.each_with_index { |r, i| h[i] = r }
584
+ h
585
+ end
586
+ end
587
+ end