dawanda-sqlite3 1.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/.gemtest +0 -0
  2. data/API_CHANGES.rdoc +50 -0
  3. data/CHANGELOG.rdoc +184 -0
  4. data/ChangeLog.cvs +88 -0
  5. data/LICENSE +27 -0
  6. data/Manifest.txt +50 -0
  7. data/README.rdoc +95 -0
  8. data/Rakefile +10 -0
  9. data/ext/sqlite3/backup.c +168 -0
  10. data/ext/sqlite3/backup.h +15 -0
  11. data/ext/sqlite3/database.c +762 -0
  12. data/ext/sqlite3/database.h +15 -0
  13. data/ext/sqlite3/exception.c +94 -0
  14. data/ext/sqlite3/exception.h +8 -0
  15. data/ext/sqlite3/extconf.rb +41 -0
  16. data/ext/sqlite3/sqlite3.c +40 -0
  17. data/ext/sqlite3/sqlite3_ruby.h +44 -0
  18. data/ext/sqlite3/statement.c +418 -0
  19. data/ext/sqlite3/statement.h +16 -0
  20. data/faq/faq.rb +145 -0
  21. data/faq/faq.yml +426 -0
  22. data/lib/sqlite3.rb +10 -0
  23. data/lib/sqlite3/constants.rb +49 -0
  24. data/lib/sqlite3/database.rb +587 -0
  25. data/lib/sqlite3/errors.rb +44 -0
  26. data/lib/sqlite3/pragmas.rb +280 -0
  27. data/lib/sqlite3/resultset.rb +126 -0
  28. data/lib/sqlite3/statement.rb +148 -0
  29. data/lib/sqlite3/translator.rb +118 -0
  30. data/lib/sqlite3/value.rb +57 -0
  31. data/lib/sqlite3/version.rb +25 -0
  32. data/setup.rb +1333 -0
  33. data/tasks/faq.rake +9 -0
  34. data/tasks/gem.rake +31 -0
  35. data/tasks/native.rake +61 -0
  36. data/tasks/vendor_sqlite3.rake +104 -0
  37. data/test/helper.rb +3 -0
  38. data/test/test_backup.rb +33 -0
  39. data/test/test_collation.rb +82 -0
  40. data/test/test_database.rb +319 -0
  41. data/test/test_database_readonly.rb +29 -0
  42. data/test/test_deprecated.rb +37 -0
  43. data/test/test_encoding.rb +119 -0
  44. data/test/test_integration.rb +544 -0
  45. data/test/test_integration_open_close.rb +30 -0
  46. data/test/test_integration_pending.rb +115 -0
  47. data/test/test_integration_resultset.rb +156 -0
  48. data/test/test_integration_statement.rb +194 -0
  49. data/test/test_sqlite3.rb +9 -0
  50. data/test/test_statement.rb +213 -0
  51. data/test/test_statement_execute.rb +35 -0
  52. metadata +184 -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