sequel_core 2.2.0 → 3.8.0

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 (66) hide show
  1. metadata +30 -101
  2. data/CHANGELOG +0 -1519
  3. data/COPYING +0 -19
  4. data/README +0 -313
  5. data/Rakefile +0 -158
  6. data/bin/sequel +0 -117
  7. data/doc/cheat_sheet.rdoc +0 -225
  8. data/doc/dataset_filtering.rdoc +0 -182
  9. data/lib/sequel_core.rb +0 -136
  10. data/lib/sequel_core/adapters/adapter_skeleton.rb +0 -68
  11. data/lib/sequel_core/adapters/ado.rb +0 -90
  12. data/lib/sequel_core/adapters/db2.rb +0 -160
  13. data/lib/sequel_core/adapters/dbi.rb +0 -127
  14. data/lib/sequel_core/adapters/informix.rb +0 -89
  15. data/lib/sequel_core/adapters/jdbc.rb +0 -110
  16. data/lib/sequel_core/adapters/mysql.rb +0 -486
  17. data/lib/sequel_core/adapters/odbc.rb +0 -167
  18. data/lib/sequel_core/adapters/odbc_mssql.rb +0 -106
  19. data/lib/sequel_core/adapters/openbase.rb +0 -76
  20. data/lib/sequel_core/adapters/oracle.rb +0 -182
  21. data/lib/sequel_core/adapters/postgres.rb +0 -560
  22. data/lib/sequel_core/adapters/sqlite.rb +0 -270
  23. data/lib/sequel_core/connection_pool.rb +0 -194
  24. data/lib/sequel_core/core_ext.rb +0 -197
  25. data/lib/sequel_core/core_sql.rb +0 -184
  26. data/lib/sequel_core/database.rb +0 -462
  27. data/lib/sequel_core/database/schema.rb +0 -156
  28. data/lib/sequel_core/dataset.rb +0 -457
  29. data/lib/sequel_core/dataset/callback.rb +0 -13
  30. data/lib/sequel_core/dataset/convenience.rb +0 -245
  31. data/lib/sequel_core/dataset/pagination.rb +0 -96
  32. data/lib/sequel_core/dataset/query.rb +0 -41
  33. data/lib/sequel_core/dataset/schema.rb +0 -15
  34. data/lib/sequel_core/dataset/sql.rb +0 -889
  35. data/lib/sequel_core/deprecated.rb +0 -26
  36. data/lib/sequel_core/exceptions.rb +0 -42
  37. data/lib/sequel_core/migration.rb +0 -187
  38. data/lib/sequel_core/object_graph.rb +0 -216
  39. data/lib/sequel_core/pretty_table.rb +0 -71
  40. data/lib/sequel_core/schema.rb +0 -2
  41. data/lib/sequel_core/schema/generator.rb +0 -239
  42. data/lib/sequel_core/schema/sql.rb +0 -326
  43. data/lib/sequel_core/sql.rb +0 -812
  44. data/lib/sequel_core/worker.rb +0 -68
  45. data/spec/adapters/informix_spec.rb +0 -96
  46. data/spec/adapters/mysql_spec.rb +0 -765
  47. data/spec/adapters/oracle_spec.rb +0 -222
  48. data/spec/adapters/postgres_spec.rb +0 -441
  49. data/spec/adapters/sqlite_spec.rb +0 -413
  50. data/spec/connection_pool_spec.rb +0 -363
  51. data/spec/core_ext_spec.rb +0 -156
  52. data/spec/core_sql_spec.rb +0 -427
  53. data/spec/database_spec.rb +0 -963
  54. data/spec/dataset_spec.rb +0 -2933
  55. data/spec/expression_filters_spec.rb +0 -316
  56. data/spec/migration_spec.rb +0 -261
  57. data/spec/object_graph_spec.rb +0 -230
  58. data/spec/pretty_table_spec.rb +0 -58
  59. data/spec/rcov.opts +0 -6
  60. data/spec/schema_generator_spec.rb +0 -122
  61. data/spec/schema_spec.rb +0 -422
  62. data/spec/spec.opts +0 -0
  63. data/spec/spec_config.rb +0 -7
  64. data/spec/spec_config.rb.example +0 -8
  65. data/spec/spec_helper.rb +0 -55
  66. data/spec/worker_spec.rb +0 -96
@@ -1,560 +0,0 @@
1
- begin
2
- require 'pg'
3
- rescue LoadError => e
4
- begin
5
- require 'postgres'
6
- class PGconn
7
- unless method_defined?(:escape_string)
8
- if self.respond_to?(:escape)
9
- def escape_string(str)
10
- self.class.escape(str)
11
- end
12
- else
13
- def escape_string(obj)
14
- raise Sequel::Error, "string escaping not supported with this postgres driver. Try using ruby-pg, ruby-postgres, or postgres-pr."
15
- end
16
- end
17
- end
18
- unless method_defined?(:escape_bytea)
19
- if self.respond_to?(:escape_bytea)
20
- def escape_bytea(obj)
21
- self.class.escape_bytea(obj)
22
- end
23
- else
24
- begin
25
- require 'postgres-pr/typeconv/conv'
26
- require 'postgres-pr/typeconv/bytea'
27
- extend Postgres::Conversion
28
- def escape_bytea(obj)
29
- self.class.encode_bytea(obj)
30
- end
31
- metaalias :unescape_bytea, :decode_bytea
32
- rescue
33
- def escape_bytea(obj)
34
- raise Sequel::Error, "bytea escaping not supported with this postgres driver. Try using ruby-pg, ruby-postgres, or postgres-pr."
35
- end
36
- def self.unescape_bytea(obj)
37
- raise Sequel::Error, "bytea unescaping not supported with this postgres driver. Try using ruby-pg, ruby-postgres, or postgres-pr."
38
- end
39
- end
40
- end
41
- end
42
- alias_method :finish, :close unless method_defined?(:finish)
43
- end
44
- class PGresult
45
- alias_method :nfields, :num_fields unless method_defined?(:nfields)
46
- alias_method :ntuples, :num_tuples unless method_defined?(:ntuples)
47
- alias_method :ftype, :type unless method_defined?(:ftype)
48
- alias_method :fname, :fieldname unless method_defined?(:fname)
49
- alias_method :cmd_tuples, :cmdtuples unless method_defined?(:cmd_tuples)
50
- end
51
- rescue LoadError
52
- raise e
53
- end
54
- end
55
-
56
- module Sequel
57
- module Postgres
58
- class Adapter < ::PGconn
59
- def connected?
60
- status == Adapter::CONNECTION_OK
61
- end
62
-
63
- def execute(sql, &block)
64
- q = nil
65
- begin
66
- q = exec(sql)
67
- rescue PGError => e
68
- unless connected?
69
- reset
70
- q = exec(sql)
71
- else
72
- raise e
73
- end
74
- end
75
- begin
76
- block ? block[q] : q.cmd_tuples
77
- ensure
78
- q.clear
79
- end
80
- end
81
-
82
- attr_accessor :transaction_depth
83
-
84
- SELECT_CURRVAL = "SELECT currval('%s')".freeze
85
-
86
- def last_insert_id(table)
87
- @table_sequences ||= {}
88
- if !@table_sequences.include?(table)
89
- pkey_and_seq = pkey_and_sequence(table)
90
- if pkey_and_seq
91
- @table_sequences[table] = pkey_and_seq[1]
92
- end
93
- end
94
- if seq = @table_sequences[table]
95
- execute(SELECT_CURRVAL % seq) do |r|
96
- return r.getvalue(0,0).to_i unless r.nil? || (r.ntuples == 0)
97
- end
98
- end
99
- nil # primary key sequence not found
100
- end
101
-
102
- # Shamelessly appropriated from ActiveRecord's Postgresql adapter.
103
- SELECT_PK_AND_SERIAL_SEQUENCE = <<-end_sql
104
- SELECT attr.attname, name.nspname, seq.relname
105
- FROM pg_class seq, pg_attribute attr, pg_depend dep,
106
- pg_namespace name, pg_constraint cons
107
- WHERE seq.oid = dep.objid
108
- AND seq.relnamespace = name.oid
109
- AND seq.relkind = 'S'
110
- AND attr.attrelid = dep.refobjid
111
- AND attr.attnum = dep.refobjsubid
112
- AND attr.attrelid = cons.conrelid
113
- AND attr.attnum = cons.conkey[1]
114
- AND cons.contype = 'p'
115
- AND dep.refobjid = '%s'::regclass
116
- end_sql
117
-
118
- SELECT_PK_AND_CUSTOM_SEQUENCE = <<-end_sql
119
- SELECT attr.attname,
120
- CASE
121
- WHEN split_part(def.adsrc, '''', 2) ~ '.' THEN
122
- substr(split_part(def.adsrc, '''', 2),
123
- strpos(split_part(def.adsrc, '''', 2), '.')+1)
124
- ELSE split_part(def.adsrc, '''', 2)
125
- END
126
- FROM pg_class t
127
- JOIN pg_namespace name ON (t.relnamespace = name.oid)
128
- JOIN pg_attribute attr ON (t.oid = attrelid)
129
- JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
130
- JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
131
- WHERE t.oid = '%s'::regclass
132
- AND cons.contype = 'p'
133
- AND def.adsrc ~* 'nextval'
134
- end_sql
135
-
136
- SELECT_PK = <<-end_sql
137
- SELECT pg_attribute.attname
138
- FROM pg_class, pg_attribute, pg_index
139
- WHERE pg_class.oid = pg_attribute.attrelid AND
140
- pg_class.oid = pg_index.indrelid AND
141
- pg_index.indkey[0] = pg_attribute.attnum AND
142
- pg_index.indisprimary = 't' AND
143
- pg_class.relname = '%s'
144
- end_sql
145
-
146
- def pkey_and_sequence(table)
147
- execute(SELECT_PK_AND_SERIAL_SEQUENCE % table) do |r|
148
- return [r.getvalue(0,2), r.getvalue(0,2)] unless r.nil? || (r.ntuples == 0)
149
- end
150
-
151
- execute(SELECT_PK_AND_CUSTOM_SEQUENCE % table) do |r|
152
- return [r.getvalue(0,0), r.getvalue(0,1)] unless r.nil? || (r.ntuples == 0)
153
- end
154
- end
155
-
156
- def primary_key(table)
157
- execute(SELECT_PK % table) do |r|
158
- if (r.nil? || (r.ntuples == 0)) then
159
- return nil
160
- else
161
- r.getvalue(0,0)
162
- end
163
- end
164
- end
165
-
166
- def self.string_to_bool(s)
167
- if(s.blank?)
168
- nil
169
- elsif(s.downcase == 't' || s.downcase == 'true')
170
- true
171
- else
172
- false
173
- end
174
- end
175
- end
176
-
177
- PG_TYPES = {
178
- 16 => lambda{ |s| Adapter.string_to_bool(s) }, # boolean
179
- 17 => lambda{ |s| Adapter.unescape_bytea(s).to_blob }, # bytea
180
- 20 => lambda{ |s| s.to_i }, # int8
181
- 21 => lambda{ |s| s.to_i }, # int2
182
- 22 => lambda{ |s| s.to_i }, # int2vector
183
- 23 => lambda{ |s| s.to_i }, # int4
184
- 26 => lambda{ |s| s.to_i }, # oid
185
- 700 => lambda{ |s| s.to_f }, # float4
186
- 701 => lambda{ |s| s.to_f }, # float8
187
- 790 => lambda{ |s| s.to_d }, # money
188
- 1082 => lambda{ |s| s.to_date }, # date
189
- 1083 => lambda{ |s| s.to_time }, # time without time zone
190
- 1114 => lambda{ |s| s.to_sequel_time }, # timestamp without time zone
191
- 1184 => lambda{ |s| s.to_sequel_time }, # timestamp with time zone
192
- 1186 => lambda{ |s| s.to_i }, # interval
193
- 1266 => lambda{ |s| s.to_time }, # time with time zone
194
- 1700 => lambda{ |s| s.to_d }, # numeric
195
- }
196
-
197
- if Adapter.respond_to?(:translate_results=)
198
- Adapter.translate_results = false
199
- end
200
- AUTO_TRANSLATE = false
201
-
202
- class Database < Sequel::Database
203
- set_adapter_scheme :postgres
204
-
205
- def connect
206
- conn = Adapter.connect(
207
- @opts[:host] || 'localhost',
208
- @opts[:port] || 5432,
209
- '', '',
210
- @opts[:database],
211
- @opts[:user],
212
- @opts[:password]
213
- )
214
- if encoding = @opts[:encoding] || @opts[:charset]
215
- conn.set_client_encoding(encoding)
216
- end
217
- conn
218
- end
219
-
220
- def disconnect
221
- @pool.disconnect {|c| c.finish}
222
- end
223
-
224
- def dataset(opts = nil)
225
- Postgres::Dataset.new(self, opts)
226
- end
227
-
228
- RELATION_QUERY = {:from => [:pg_class], :select => [:relname]}.freeze
229
- RELATION_FILTER = "(relkind = 'r') AND (relname !~ '^pg|sql')".freeze
230
- SYSTEM_TABLE_REGEXP = /^pg|sql/.freeze
231
-
232
- def tables
233
- dataset(RELATION_QUERY).filter(RELATION_FILTER).map {|r| r[:relname].to_sym}
234
- end
235
-
236
- def locks
237
- dataset.from("pg_class, pg_locks").
238
- select("pg_class.relname, pg_locks.*").
239
- filter("pg_class.relfilenode=pg_locks.relation")
240
- end
241
-
242
- def execute(sql, &block)
243
- begin
244
- log_info(sql)
245
- @pool.hold {|conn| conn.execute(sql, &block)}
246
- rescue => e
247
- log_info(e.message)
248
- raise convert_pgerror(e)
249
- end
250
- end
251
-
252
- def primary_key_for_table(conn, table)
253
- @primary_keys ||= {}
254
- @primary_keys[table] ||= conn.primary_key(table)
255
- end
256
-
257
- RE_CURRVAL_ERROR = /currval of sequence "(.*)" is not yet defined in this session/.freeze
258
-
259
- def insert_result(conn, table, values)
260
- begin
261
- result = conn.last_insert_id(table)
262
- return result if result
263
- rescue PGError => e
264
- raise(Error, e.message) unless RE_CURRVAL_ERROR.match(e.message)
265
- end
266
-
267
- case values
268
- when Hash
269
- values[primary_key_for_table(conn, table)]
270
- when Array
271
- values.first
272
- else
273
- nil
274
- end
275
- end
276
-
277
- def server_version
278
- return @server_version if @server_version
279
- @server_version = pool.hold do |conn|
280
- if conn.respond_to?(:server_version)
281
- begin
282
- conn.server_version
283
- rescue StandardError
284
- nil
285
- end
286
- end
287
- end
288
- unless @server_version
289
- m = /PostgreSQL (\d+)\.(\d+)\.(\d+)/.match(get(:version[]))
290
- @server_version = (m[1].to_i * 10000) + (m[2].to_i * 100) + m[3].to_i
291
- end
292
- @server_version
293
- end
294
-
295
- def execute_insert(sql, table, values)
296
- begin
297
- log_info(sql)
298
- @pool.hold do |conn|
299
- conn.execute(sql)
300
- insert_result(conn, table, values)
301
- end
302
- rescue => e
303
- log_info(e.message)
304
- raise convert_pgerror(e)
305
- end
306
- end
307
-
308
- SQL_BEGIN = 'BEGIN'.freeze
309
- SQL_SAVEPOINT = 'SAVEPOINT autopoint_%d'.freeze
310
- SQL_COMMIT = 'COMMIT'.freeze
311
- SQL_ROLLBACK_TO_SAVEPOINT = 'ROLLBACK TO SAVEPOINT autopoint_%d'.freeze
312
- SQL_ROLLBACK = 'ROLLBACK'.freeze
313
- SQL_RELEASE_SAVEPOINT = 'RELEASE SAVEPOINT autopoint_%d'.freeze
314
-
315
- def transaction
316
- @pool.hold do |conn|
317
- conn.transaction_depth = 0 if conn.transaction_depth.nil?
318
- if conn.transaction_depth > 0
319
- log_info(SQL_SAVEPOINT % conn.transaction_depth)
320
- conn.execute(SQL_SAVEPOINT % conn.transaction_depth)
321
- else
322
- log_info(SQL_BEGIN)
323
- conn.execute(SQL_BEGIN)
324
- end
325
- begin
326
- conn.transaction_depth += 1
327
- yield conn
328
- rescue ::Exception => e
329
- if conn.transaction_depth > 1
330
- log_info(SQL_ROLLBACK_TO_SAVEPOINT % [conn.transaction_depth - 1])
331
- conn.execute(SQL_ROLLBACK_TO_SAVEPOINT % [conn.transaction_depth - 1])
332
- else
333
- log_info(SQL_ROLLBACK)
334
- conn.execute(SQL_ROLLBACK) rescue nil
335
- end
336
- raise convert_pgerror(e) unless Error::Rollback === e
337
- ensure
338
- unless e
339
- begin
340
- if conn.transaction_depth < 2
341
- log_info(SQL_COMMIT)
342
- conn.execute(SQL_COMMIT)
343
- else
344
- log_info(SQL_RELEASE_SAVEPOINT % [conn.transaction_depth - 1])
345
- conn.execute(SQL_RELEASE_SAVEPOINT % [conn.transaction_depth - 1])
346
- end
347
- rescue => e
348
- log_info(e.message)
349
- raise convert_pgerror(e)
350
- end
351
- end
352
- conn.transaction_depth -= 1
353
- end
354
- end
355
- end
356
-
357
- def serial_primary_key_options
358
- {:primary_key => true, :type => :serial}
359
- end
360
-
361
- def index_definition_sql(table_name, index)
362
- index_name = index[:name] || default_index_name(table_name, index[:columns])
363
- expr = literal(Array(index[:columns]))
364
- unique = "UNIQUE " if index[:unique]
365
- index_type = index[:type]
366
- filter = index[:where] || index[:filter]
367
- filter = " WHERE #{filter_expr(filter)}" if filter
368
- case index_type
369
- when :full_text
370
- lang = index[:language] ? "#{literal(index[:language])}, " : ""
371
- cols = index[:columns].map {|c| literal(c)}.join(" || ")
372
- expr = "(to_tsvector(#{lang}#{cols}))"
373
- index_type = :gin
374
- when :spatial
375
- index_type = :gist
376
- end
377
- "CREATE #{unique}INDEX #{index_name} ON #{table_name} #{"USING #{index_type} " if index_type}#{expr}#{filter}"
378
- end
379
-
380
- def drop_table_sql(name)
381
- "DROP TABLE #{name} CASCADE"
382
- end
383
-
384
- private
385
- # If the given exception is a PGError, return a Sequel::Error with the same message, otherwise
386
- # just return the given exception
387
- def convert_pgerror(e)
388
- PGError === e ? Error.new(e.message) : e
389
- end
390
-
391
- # PostgreSQL currently can always reuse connections. It doesn't need the pool to convert exceptions, either.
392
- def connection_pool_default_options
393
- super.merge(:pool_convert_exceptions=>false)
394
- end
395
-
396
- def schema_ds_filter(table_name, opts)
397
- filt = super
398
- # Restrict it to the given or public schema, unless specifically requesting :schema = nil
399
- filt = SQL::BooleanExpression.new(:AND, filt, {:c__table_schema=>opts[:schema] || 'public'}) if opts[:schema] || !opts.include?(:schema)
400
- filt
401
- end
402
- end
403
-
404
- class Dataset < Sequel::Dataset
405
- def quoted_identifier(c)
406
- "\"#{c}\""
407
- end
408
-
409
- PG_TIMESTAMP_FORMAT = "TIMESTAMP '%Y-%m-%d %H:%M:%S".freeze
410
- BOOL_FALSE = 'false'.freeze
411
- BOOL_TRUE = 'true'.freeze
412
-
413
- def literal(v)
414
- case v
415
- when LiteralString
416
- v
417
- when String
418
- db.synchronize{|c| "'#{SQL::Blob === v ? c.escape_bytea(v) : c.escape_string(v)}'"}
419
- when Time
420
- "#{v.strftime(PG_TIMESTAMP_FORMAT)}.#{sprintf("%06d",v.usec)}'"
421
- when DateTime
422
- "#{v.strftime(PG_TIMESTAMP_FORMAT)}.#{sprintf("%06d", (v.sec_fraction * 86400000000).to_i)}'"
423
- when TrueClass
424
- BOOL_TRUE
425
- when FalseClass
426
- BOOL_FALSE
427
- else
428
- super
429
- end
430
- end
431
-
432
- def match_expr(l, r)
433
- case r
434
- when Regexp
435
- r.casefold? ? \
436
- "(#{literal(l)} ~* #{literal(r.source)})" :
437
- "(#{literal(l)} ~ #{literal(r.source)})"
438
- else
439
- super
440
- end
441
- end
442
-
443
- def full_text_search(cols, terms, opts = {})
444
- lang = opts[:language] ? "#{literal(opts[:language])}, " : ""
445
- cols = cols.is_a?(Array) ? cols.map {|c| literal(c)}.join(" || ") : literal(cols)
446
- terms = terms.is_a?(Array) ? literal(terms.join(" | ")) : literal(terms)
447
- filter("to_tsvector(#{lang}#{cols}) @@ to_tsquery(#{lang}#{terms})")
448
- end
449
-
450
- FOR_UPDATE = ' FOR UPDATE'.freeze
451
- FOR_SHARE = ' FOR SHARE'.freeze
452
-
453
- def select_sql(opts = nil)
454
- row_lock_mode = opts ? opts[:lock] : @opts[:lock]
455
- sql = super
456
- case row_lock_mode
457
- when :update
458
- sql << FOR_UPDATE
459
- when :share
460
- sql << FOR_SHARE
461
- end
462
- sql
463
- end
464
-
465
- def for_update
466
- clone(:lock => :update)
467
- end
468
-
469
- def for_share
470
- clone(:lock => :share)
471
- end
472
-
473
- EXPLAIN = 'EXPLAIN '.freeze
474
- EXPLAIN_ANALYZE = 'EXPLAIN ANALYZE '.freeze
475
- QUERY_PLAN = 'QUERY PLAN'.to_sym
476
-
477
- def explain(opts = nil)
478
- analysis = []
479
- fetch_rows(EXPLAIN + select_sql(opts)) do |r|
480
- analysis << r[QUERY_PLAN]
481
- end
482
- analysis.join("\r\n")
483
- end
484
-
485
- def analyze(opts = nil)
486
- analysis = []
487
- fetch_rows(EXPLAIN_ANALYZE + select_sql(opts)) do |r|
488
- analysis << r[QUERY_PLAN]
489
- end
490
- analysis.join("\r\n")
491
- end
492
-
493
- LOCK = 'LOCK TABLE %s IN %s MODE'.freeze
494
-
495
- ACCESS_SHARE = 'ACCESS SHARE'.freeze
496
- ROW_SHARE = 'ROW SHARE'.freeze
497
- ROW_EXCLUSIVE = 'ROW EXCLUSIVE'.freeze
498
- SHARE_UPDATE_EXCLUSIVE = 'SHARE UPDATE EXCLUSIVE'.freeze
499
- SHARE = 'SHARE'.freeze
500
- SHARE_ROW_EXCLUSIVE = 'SHARE ROW EXCLUSIVE'.freeze
501
- EXCLUSIVE = 'EXCLUSIVE'.freeze
502
- ACCESS_EXCLUSIVE = 'ACCESS EXCLUSIVE'.freeze
503
-
504
- # Locks the table with the specified mode.
505
- def lock(mode, &block)
506
- sql = LOCK % [source_list(@opts[:from]), mode]
507
- @db.synchronize do
508
- if block # perform locking inside a transaction and yield to block
509
- @db.transaction {@db.execute(sql); yield}
510
- else
511
- @db.execute(sql) # lock without a transaction
512
- self
513
- end
514
- end
515
- end
516
-
517
- def multi_insert_sql(columns, values)
518
- return super if @db.server_version < 80200
519
-
520
- # postgresql 8.2 introduces support for multi-row insert
521
- columns = column_list(columns)
522
- values = values.map {|r| literal(Array(r))}.join(COMMA_SEPARATOR)
523
- ["INSERT INTO #{source_list(@opts[:from])} (#{columns}) VALUES #{values}"]
524
- end
525
-
526
- def insert(*values)
527
- @db.execute_insert(insert_sql(*values), source_list(@opts[:from]),
528
- values.size == 1 ? values.first : values)
529
- end
530
-
531
- def update(*args, &block)
532
- @db.execute(update_sql(*args, &block))
533
- end
534
-
535
- def delete(opts = nil)
536
- @db.execute(delete_sql(opts))
537
- end
538
-
539
- def fetch_rows(sql, &block)
540
- @columns = []
541
- @db.execute(sql) do |res|
542
- (0...res.ntuples).each do |recnum|
543
- converted_rec = {}
544
- (0...res.nfields).each do |fieldnum|
545
- fieldsym = res.fname(fieldnum).to_sym
546
- @columns << fieldsym
547
- converted_rec[fieldsym] = if value = res.getvalue(recnum,fieldnum)
548
- (PG_TYPES[res.ftype(fieldnum)] || lambda{|s| s.to_s}).call(value)
549
- else
550
- value
551
- end
552
- end
553
- yield converted_rec
554
- end
555
- end
556
- end
557
- end
558
- end
559
- end
560
-