sqlite3-static 3.12.2

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.
@@ -0,0 +1,16 @@
1
+ #ifndef SQLITE3_STATEMENT_RUBY
2
+ #define SQLITE3_STATEMENT_RUBY
3
+
4
+ #include <sqlite3_ruby.h>
5
+
6
+ struct _sqlite3StmtRuby {
7
+ sqlite3_stmt *st;
8
+ int done_p;
9
+ };
10
+
11
+ typedef struct _sqlite3StmtRuby sqlite3StmtRuby;
12
+ typedef sqlite3StmtRuby * sqlite3StmtRubyPtr;
13
+
14
+ void init_sqlite3_statement();
15
+
16
+ #endif
data/lib/sqlite3.rb ADDED
@@ -0,0 +1,15 @@
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'
11
+
12
+ module SQLite3
13
+ # Was sqlite3 compiled with thread safety on?
14
+ def self.threadsafe?; threadsafe > 0; end
15
+ end
@@ -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,600 @@
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 unless stmt.closed?
98
+ end
99
+ end
100
+
101
+ # Returns the filename for the database named +db_name+. +db_name+ defaults
102
+ # to "main". Main return `nil` or an empty string if the database is
103
+ # temporary or in-memory.
104
+ def filename db_name = 'main'
105
+ db_filename db_name
106
+ end
107
+
108
+ # Executes the given SQL statement. If additional parameters are given,
109
+ # they are treated as bind variables, and are bound to the placeholders in
110
+ # the query.
111
+ #
112
+ # Note that if any of the values passed to this are hashes, then the
113
+ # key/value pairs are each bound separately, with the key being used as
114
+ # the name of the placeholder to bind the value to.
115
+ #
116
+ # The block is optional. If given, it will be invoked for each row returned
117
+ # by the query. Otherwise, any results are accumulated into an array and
118
+ # returned wholesale.
119
+ #
120
+ # See also #execute2, #query, and #execute_batch for additional ways of
121
+ # executing statements.
122
+ def execute sql, bind_vars = [], *args, &block
123
+ # FIXME: This is a terrible hack and should be removed but is required
124
+ # for older versions of rails
125
+ hack = Object.const_defined?(:ActiveRecord) && sql =~ /^PRAGMA index_list/
126
+
127
+ if bind_vars.nil? || !args.empty?
128
+ if args.empty?
129
+ bind_vars = []
130
+ else
131
+ bind_vars = [bind_vars] + args
132
+ end
133
+
134
+ warn(<<-eowarn) if $VERBOSE
135
+ #{caller[0]} is calling SQLite3::Database#execute with nil or multiple bind params
136
+ without using an array. Please switch to passing bind parameters as an array.
137
+ Support for bind parameters as *args will be removed in 2.0.0.
138
+ eowarn
139
+ end
140
+
141
+ prepare( sql ) do |stmt|
142
+ stmt.bind_params(bind_vars)
143
+ columns = stmt.columns
144
+ stmt = ResultSet.new(self, stmt).to_a if type_translation
145
+
146
+ if block_given?
147
+ stmt.each do |row|
148
+ if @results_as_hash
149
+ yield type_translation ? row : ordered_map_for(columns, row)
150
+ else
151
+ yield row
152
+ end
153
+ end
154
+ else
155
+ if @results_as_hash
156
+ stmt.map { |row|
157
+ h = type_translation ? row : ordered_map_for(columns, row)
158
+
159
+ # FIXME UGH TERRIBLE HACK!
160
+ h['unique'] = h['unique'].to_s if hack
161
+
162
+ h
163
+ }
164
+ else
165
+ stmt.to_a
166
+ end
167
+ end
168
+ end
169
+ end
170
+
171
+ # Executes the given SQL statement, exactly as with #execute. However, the
172
+ # first row returned (either via the block, or in the returned array) is
173
+ # always the names of the columns. Subsequent rows correspond to the data
174
+ # from the result set.
175
+ #
176
+ # Thus, even if the query itself returns no rows, this method will always
177
+ # return at least one row--the names of the columns.
178
+ #
179
+ # See also #execute, #query, and #execute_batch for additional ways of
180
+ # executing statements.
181
+ def execute2( sql, *bind_vars )
182
+ prepare( sql ) do |stmt|
183
+ result = stmt.execute( *bind_vars )
184
+ if block_given?
185
+ yield stmt.columns
186
+ result.each { |row| yield row }
187
+ else
188
+ return result.inject( [ stmt.columns ] ) { |arr,row|
189
+ arr << row; arr }
190
+ end
191
+ end
192
+ end
193
+
194
+ # Executes all SQL statements in the given string. By contrast, the other
195
+ # means of executing queries will only execute the first statement in the
196
+ # string, ignoring all subsequent statements. This will execute each one
197
+ # in turn. The same bind parameters, if given, will be applied to each
198
+ # statement.
199
+ #
200
+ # This always returns +nil+, making it unsuitable for queries that return
201
+ # rows.
202
+ def execute_batch( sql, bind_vars = [], *args )
203
+ # FIXME: remove this stuff later
204
+ unless [Array, Hash].include?(bind_vars.class)
205
+ bind_vars = [bind_vars]
206
+ warn(<<-eowarn) if $VERBOSE
207
+ #{caller[0]} is calling SQLite3::Database#execute_batch with bind parameters
208
+ that are not a list of a hash. Please switch to passing bind parameters as an
209
+ array or hash. Support for this behavior will be removed in version 2.0.0.
210
+ eowarn
211
+ end
212
+
213
+ # FIXME: remove this stuff later
214
+ if bind_vars.nil? || !args.empty?
215
+ if args.empty?
216
+ bind_vars = []
217
+ else
218
+ bind_vars = [nil] + args
219
+ end
220
+
221
+ warn(<<-eowarn) if $VERBOSE
222
+ #{caller[0]} is calling SQLite3::Database#execute_batch with nil or multiple bind params
223
+ without using an array. Please switch to passing bind parameters as an array.
224
+ Support for this behavior will be removed in version 2.0.0.
225
+ eowarn
226
+ end
227
+
228
+ sql = sql.strip
229
+ until sql.empty? do
230
+ prepare( sql ) do |stmt|
231
+ unless stmt.closed?
232
+ # FIXME: this should probably use sqlite3's api for batch execution
233
+ # This implementation requires stepping over the results.
234
+ if bind_vars.length == stmt.bind_parameter_count
235
+ stmt.bind_params(bind_vars)
236
+ end
237
+ stmt.step
238
+ end
239
+ sql = stmt.remainder.strip
240
+ end
241
+ end
242
+ # FIXME: we should not return `nil` as a success return value
243
+ nil
244
+ end
245
+
246
+ # This is a convenience method for creating a statement, binding
247
+ # paramters to it, and calling execute:
248
+ #
249
+ # result = db.query( "select * from foo where a=?", [5])
250
+ # # is the same as
251
+ # result = db.prepare( "select * from foo where a=?" ).execute( 5 )
252
+ #
253
+ # You must be sure to call +close+ on the ResultSet instance that is
254
+ # returned, or you could have problems with locks on the table. If called
255
+ # with a block, +close+ will be invoked implicitly when the block
256
+ # terminates.
257
+ def query( sql, bind_vars = [], *args )
258
+
259
+ if bind_vars.nil? || !args.empty?
260
+ if args.empty?
261
+ bind_vars = []
262
+ else
263
+ bind_vars = [bind_vars] + args
264
+ end
265
+
266
+ warn(<<-eowarn) if $VERBOSE
267
+ #{caller[0]} is calling SQLite3::Database#query with nil or multiple bind params
268
+ without using an array. Please switch to passing bind parameters as an array.
269
+ Support for this will be removed in version 2.0.0.
270
+ eowarn
271
+ end
272
+
273
+ result = prepare( sql ).execute( bind_vars )
274
+ if block_given?
275
+ begin
276
+ yield result
277
+ ensure
278
+ result.close
279
+ end
280
+ else
281
+ return result
282
+ end
283
+ end
284
+
285
+ # A convenience method for obtaining the first row of a result set, and
286
+ # discarding all others. It is otherwise identical to #execute.
287
+ #
288
+ # See also #get_first_value.
289
+ def get_first_row( sql, *bind_vars )
290
+ execute( sql, *bind_vars ).first
291
+ end
292
+
293
+ # A convenience method for obtaining the first value of the first row of a
294
+ # result set, and discarding all other values and rows. It is otherwise
295
+ # identical to #execute.
296
+ #
297
+ # See also #get_first_row.
298
+ def get_first_value( sql, *bind_vars )
299
+ execute( sql, *bind_vars ) { |row| return row[0] }
300
+ nil
301
+ end
302
+
303
+ alias :busy_timeout :busy_timeout=
304
+
305
+ # Creates a new function for use in SQL statements. It will be added as
306
+ # +name+, with the given +arity+. (For variable arity functions, use
307
+ # -1 for the arity.)
308
+ #
309
+ # The block should accept at least one parameter--the FunctionProxy
310
+ # instance that wraps this function invocation--and any other
311
+ # arguments it needs (up to its arity).
312
+ #
313
+ # The block does not return a value directly. Instead, it will invoke
314
+ # the FunctionProxy#result= method on the +func+ parameter and
315
+ # indicate the return value that way.
316
+ #
317
+ # Example:
318
+ #
319
+ # db.create_function( "maim", 1 ) do |func, value|
320
+ # if value.nil?
321
+ # func.result = nil
322
+ # else
323
+ # func.result = value.split(//).sort.join
324
+ # end
325
+ # end
326
+ #
327
+ # puts db.get_first_value( "select maim(name) from table" )
328
+ def create_function name, arity, text_rep=Constants::TextRep::ANY, &block
329
+ define_function(name) do |*args|
330
+ fp = FunctionProxy.new
331
+ block.call(fp, *args)
332
+ fp.result
333
+ end
334
+ self
335
+ end
336
+
337
+ # Creates a new aggregate function for use in SQL statements. Aggregate
338
+ # functions are functions that apply over every row in the result set,
339
+ # instead of over just a single row. (A very common aggregate function
340
+ # is the "count" function, for determining the number of rows that match
341
+ # a query.)
342
+ #
343
+ # The new function will be added as +name+, with the given +arity+. (For
344
+ # variable arity functions, use -1 for the arity.)
345
+ #
346
+ # The +step+ parameter must be a proc object that accepts as its first
347
+ # parameter a FunctionProxy instance (representing the function
348
+ # invocation), with any subsequent parameters (up to the function's arity).
349
+ # The +step+ callback will be invoked once for each row of the result set.
350
+ #
351
+ # The +finalize+ parameter must be a +proc+ object that accepts only a
352
+ # single parameter, the FunctionProxy instance representing the current
353
+ # function invocation. It should invoke FunctionProxy#result= to
354
+ # store the result of the function.
355
+ #
356
+ # Example:
357
+ #
358
+ # db.create_aggregate( "lengths", 1 ) do
359
+ # step do |func, value|
360
+ # func[ :total ] ||= 0
361
+ # func[ :total ] += ( value ? value.length : 0 )
362
+ # end
363
+ #
364
+ # finalize do |func|
365
+ # func.result = func[ :total ] || 0
366
+ # end
367
+ # end
368
+ #
369
+ # puts db.get_first_value( "select lengths(name) from table" )
370
+ #
371
+ # See also #create_aggregate_handler for a more object-oriented approach to
372
+ # aggregate functions.
373
+ def create_aggregate( name, arity, step=nil, finalize=nil,
374
+ text_rep=Constants::TextRep::ANY, &block )
375
+
376
+ factory = Class.new do
377
+ def self.step( &block )
378
+ define_method(:step, &block)
379
+ end
380
+
381
+ def self.finalize( &block )
382
+ define_method(:finalize, &block)
383
+ end
384
+ end
385
+
386
+ if block_given?
387
+ factory.instance_eval(&block)
388
+ else
389
+ factory.class_eval do
390
+ define_method(:step, step)
391
+ define_method(:finalize, finalize)
392
+ end
393
+ end
394
+
395
+ proxy = factory.new
396
+ proxy.extend(Module.new {
397
+ attr_accessor :ctx
398
+
399
+ def step( *args )
400
+ super(@ctx, *args)
401
+ end
402
+
403
+ def finalize
404
+ super(@ctx)
405
+ result = @ctx.result
406
+ @ctx = FunctionProxy.new
407
+ result
408
+ end
409
+ })
410
+ proxy.ctx = FunctionProxy.new
411
+ define_aggregator(name, proxy)
412
+ end
413
+
414
+ # This is another approach to creating an aggregate function (see
415
+ # #create_aggregate). Instead of explicitly specifying the name,
416
+ # callbacks, arity, and type, you specify a factory object
417
+ # (the "handler") that knows how to obtain all of that information. The
418
+ # handler should respond to the following messages:
419
+ #
420
+ # +arity+:: corresponds to the +arity+ parameter of #create_aggregate. This
421
+ # message is optional, and if the handler does not respond to it,
422
+ # the function will have an arity of -1.
423
+ # +name+:: this is the name of the function. The handler _must_ implement
424
+ # this message.
425
+ # +new+:: this must be implemented by the handler. It should return a new
426
+ # instance of the object that will handle a specific invocation of
427
+ # the function.
428
+ #
429
+ # The handler instance (the object returned by the +new+ message, described
430
+ # above), must respond to the following messages:
431
+ #
432
+ # +step+:: this is the method that will be called for each step of the
433
+ # aggregate function's evaluation. It should implement the same
434
+ # signature as the +step+ callback for #create_aggregate.
435
+ # +finalize+:: this is the method that will be called to finalize the
436
+ # aggregate function's evaluation. It should implement the
437
+ # same signature as the +finalize+ callback for
438
+ # #create_aggregate.
439
+ #
440
+ # Example:
441
+ #
442
+ # class LengthsAggregateHandler
443
+ # def self.arity; 1; end
444
+ # def self.name; 'lengths'; end
445
+ #
446
+ # def initialize
447
+ # @total = 0
448
+ # end
449
+ #
450
+ # def step( ctx, name )
451
+ # @total += ( name ? name.length : 0 )
452
+ # end
453
+ #
454
+ # def finalize( ctx )
455
+ # ctx.result = @total
456
+ # end
457
+ # end
458
+ #
459
+ # db.create_aggregate_handler( LengthsAggregateHandler )
460
+ # puts db.get_first_value( "select lengths(name) from A" )
461
+ def create_aggregate_handler( handler )
462
+ proxy = Class.new do
463
+ def initialize klass
464
+ @klass = klass
465
+ @fp = FunctionProxy.new
466
+ end
467
+
468
+ def step( *args )
469
+ instance.step(@fp, *args)
470
+ end
471
+
472
+ def finalize
473
+ instance.finalize @fp
474
+ @instance = nil
475
+ @fp.result
476
+ end
477
+
478
+ private
479
+
480
+ def instance
481
+ @instance ||= @klass.new
482
+ end
483
+ end
484
+ define_aggregator(handler.name, proxy.new(handler))
485
+ self
486
+ end
487
+
488
+ # Begins a new transaction. Note that nested transactions are not allowed
489
+ # by SQLite, so attempting to nest a transaction will result in a runtime
490
+ # exception.
491
+ #
492
+ # The +mode+ parameter may be either <tt>:deferred</tt> (the default),
493
+ # <tt>:immediate</tt>, or <tt>:exclusive</tt>.
494
+ #
495
+ # If a block is given, the database instance is yielded to it, and the
496
+ # transaction is committed when the block terminates. If the block
497
+ # raises an exception, a rollback will be performed instead. Note that if
498
+ # a block is given, #commit and #rollback should never be called
499
+ # explicitly or you'll get an error when the block terminates.
500
+ #
501
+ # If a block is not given, it is the caller's responsibility to end the
502
+ # transaction explicitly, either by calling #commit, or by calling
503
+ # #rollback.
504
+ def transaction( mode = :deferred )
505
+ execute "begin #{mode.to_s} transaction"
506
+
507
+ if block_given?
508
+ abort = false
509
+ begin
510
+ yield self
511
+ rescue ::Object
512
+ abort = true
513
+ raise
514
+ ensure
515
+ abort and rollback or commit
516
+ end
517
+ end
518
+
519
+ true
520
+ end
521
+
522
+ # Commits the current transaction. If there is no current transaction,
523
+ # this will cause an error to be raised. This returns +true+, in order
524
+ # to allow it to be used in idioms like
525
+ # <tt>abort? and rollback or commit</tt>.
526
+ def commit
527
+ execute "commit transaction"
528
+ true
529
+ end
530
+
531
+ # Rolls the current transaction back. If there is no current transaction,
532
+ # this will cause an error to be raised. This returns +true+, in order
533
+ # to allow it to be used in idioms like
534
+ # <tt>abort? and rollback or commit</tt>.
535
+ def rollback
536
+ execute "rollback transaction"
537
+ true
538
+ end
539
+
540
+ # Returns +true+ if the database has been open in readonly mode
541
+ # A helper to check before performing any operation
542
+ def readonly?
543
+ @readonly
544
+ end
545
+
546
+ # A helper class for dealing with custom functions (see #create_function,
547
+ # #create_aggregate, and #create_aggregate_handler). It encapsulates the
548
+ # opaque function object that represents the current invocation. It also
549
+ # provides more convenient access to the API functions that operate on
550
+ # the function object.
551
+ #
552
+ # This class will almost _always_ be instantiated indirectly, by working
553
+ # with the create methods mentioned above.
554
+ class FunctionProxy
555
+ attr_accessor :result
556
+
557
+ # Create a new FunctionProxy that encapsulates the given +func+ object.
558
+ # If context is non-nil, the functions context will be set to that. If
559
+ # it is non-nil, it must quack like a Hash. If it is nil, then none of
560
+ # the context functions will be available.
561
+ def initialize
562
+ @result = nil
563
+ @context = {}
564
+ end
565
+
566
+ # Set the result of the function to the given error message.
567
+ # The function will then return that error.
568
+ def set_error( error )
569
+ @driver.result_error( @func, error.to_s, -1 )
570
+ end
571
+
572
+ # (Only available to aggregate functions.) Returns the number of rows
573
+ # that the aggregate has processed so far. This will include the current
574
+ # row, and so will always return at least 1.
575
+ def count
576
+ @driver.aggregate_count( @func )
577
+ end
578
+
579
+ # Returns the value with the given key from the context. This is only
580
+ # available to aggregate functions.
581
+ def []( key )
582
+ @context[ key ]
583
+ end
584
+
585
+ # Sets the value with the given key in the context. This is only
586
+ # available to aggregate functions.
587
+ def []=( key, value )
588
+ @context[ key ] = value
589
+ end
590
+ end
591
+
592
+ private
593
+
594
+ def ordered_map_for columns, row
595
+ h = Hash[*columns.zip(row).flatten]
596
+ row.each_with_index { |r, i| h[i] = r }
597
+ h
598
+ end
599
+ end
600
+ end