activerecord-postgresql-extensions 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. data/MIT-LICENSE +23 -0
  2. data/README.rdoc +32 -0
  3. data/Rakefile +42 -0
  4. data/VERSION +1 -0
  5. data/lib/activerecord-postgresql-extensions.rb +30 -0
  6. data/lib/postgresql_extensions/foreign_key_associations.rb +367 -0
  7. data/lib/postgresql_extensions/postgresql_adapter_extensions.rb +646 -0
  8. data/lib/postgresql_extensions/postgresql_constraints.rb +579 -0
  9. data/lib/postgresql_extensions/postgresql_functions.rb +345 -0
  10. data/lib/postgresql_extensions/postgresql_geometry.rb +212 -0
  11. data/lib/postgresql_extensions/postgresql_indexes.rb +219 -0
  12. data/lib/postgresql_extensions/postgresql_languages.rb +80 -0
  13. data/lib/postgresql_extensions/postgresql_permissions.rb +322 -0
  14. data/lib/postgresql_extensions/postgresql_rules.rb +112 -0
  15. data/lib/postgresql_extensions/postgresql_schemas.rb +49 -0
  16. data/lib/postgresql_extensions/postgresql_sequences.rb +222 -0
  17. data/lib/postgresql_extensions/postgresql_tables.rb +308 -0
  18. data/lib/postgresql_extensions/postgresql_triggers.rb +131 -0
  19. data/lib/postgresql_extensions/postgresql_types.rb +17 -0
  20. data/lib/postgresql_extensions/postgresql_views.rb +103 -0
  21. data/postgresql-extensions.gemspec +50 -0
  22. data/test/adapter_test.rb +45 -0
  23. data/test/constraints_test.rb +98 -0
  24. data/test/functions_test.rb +112 -0
  25. data/test/geometry_test.rb +43 -0
  26. data/test/index_test.rb +68 -0
  27. data/test/languages_test.rb +48 -0
  28. data/test/permissions_test.rb +163 -0
  29. data/test/rules_test.rb +32 -0
  30. data/test/schemas_test.rb +43 -0
  31. data/test/sequences_test.rb +90 -0
  32. data/test/tables_test.rb +49 -0
  33. data/test/test_helper.rb +64 -0
  34. metadata +97 -0
@@ -0,0 +1,646 @@
1
+
2
+ module ActiveRecord
3
+ module ConnectionAdapters
4
+ class PostgreSQLAdapter < AbstractAdapter
5
+ if defined?(Rails)
6
+ LOGGER_REGEXP = /^#{Rails.root}(?!\/vendor\/rails)/
7
+
8
+ def query_with_extra_logging(sql, name = nil) #:nodoc:
9
+ if ActiveRecord::Base.enable_extended_logging && Rails.logger && Rails.logger.level == Logger::DEBUG
10
+ unless (sql =~ /(pg_get_constraintdef|pg_attribute|pg_class)/)
11
+ Rails.logger.debug
12
+ Rails.logger.debug(caller.select { |x|
13
+ ActiveRecord::Base.enable_really_extended_logging || x.match(LOGGER_REGEXP)
14
+ }.join("\n"))
15
+ end
16
+ end
17
+ query_without_extra_logging(sql, name)
18
+ end
19
+ alias_method_chain :query, :extra_logging
20
+
21
+ def execute_with_extra_logging(sql, name = nil) #:nodoc:
22
+ if ActiveRecord::Base.enable_extended_logging && Rails.logger && Rails.logger.level == Logger::DEBUG
23
+ unless (sql =~ /(pg_get_constraintdef|pg_attribute|pg_class)/)
24
+ Rails.logger.debug
25
+ Rails.logger.debug(caller.select { |x|
26
+ ActiveRecord::Base.enable_really_extended_logging || x.match(LOGGER_REGEXP)
27
+ }.join("\n"))
28
+ end
29
+ end
30
+ execute_without_extra_logging(sql, name)
31
+ end
32
+ alias_method_chain :execute, :extra_logging
33
+ end
34
+
35
+ # There seems to be a bug in ActiveRecord where it isn't setting
36
+ # the schema search path properly because it's using ',' as a
37
+ # separator rather than /,\s+/.
38
+ def schema_search_path_with_fix_csv=(schema_csv)
39
+ if schema_csv
40
+ csv = schema_csv.gsub(/,\s+/, ',')
41
+ execute "SET search_path TO #{csv}"
42
+ @schema_search_path = csv
43
+ end
44
+ end
45
+ alias_method_chain :schema_search_path=, :fix_csv
46
+
47
+ # Fix ActiveRecord bug when grabbing the current search_path.
48
+ def schema_search_path_with_fix_csv
49
+ @schema_search_path ||= query('SHOW search_path')[0][0].gsub(/,\s+/, ',')
50
+ end
51
+ alias_method_chain :schema_search_path, :fix_csv
52
+
53
+ # with_schema is kind of like with_scope. It wraps various
54
+ # object names in SQL statements into a PostgreSQL schema. You
55
+ # can have multiple with_schemas wrapped around each other, and
56
+ # hopefully they won't collide with one another.
57
+ #
58
+ # Examples:
59
+ #
60
+ # ### ruby
61
+ # # should produce '"geospatial"."my_tables"
62
+ # with_schema :geospatial do
63
+ # quote_table_name('my_table')
64
+ # end
65
+ #
66
+ # # should produce 'SELECT * FROM "geospatial"."models"'
67
+ # with_schema :geospatial do
68
+ # Model.find(:all)
69
+ # end
70
+ def with_schema schema
71
+ scoped_schemas << schema
72
+ begin
73
+ yield
74
+ ensure
75
+ scoped_schemas.pop
76
+ end
77
+ end
78
+
79
+ # When using with_schema, you can temporarily ignore the scoped
80
+ # schemas with ignore_block.
81
+ #
82
+ # Example:
83
+ #
84
+ # ### ruby
85
+ # with_schema :geospatial do
86
+ # create_table(:test) do |t|
87
+ # ignore_schema do
88
+ # t.integer(
89
+ # :ref_id,
90
+ # :references => {
91
+ # :table => :refs,
92
+ # :column => :id,
93
+ # :deferrable => true
94
+ # }
95
+ # )
96
+ # end
97
+ # end
98
+ # end
99
+ #
100
+ # Should produce:
101
+ #
102
+ # ### sql
103
+ # CREATE TABLE "geospatial"."test" (
104
+ # "id" serial primary key,
105
+ # "ref_id" integer DEFAULT NULL NULL,
106
+ # FOREIGN KEY ("ref_id") REFERENCES "refs" ("id")
107
+ # )
108
+ #
109
+ # Here we see that we used the geospatial schema when naming the
110
+ # test table and dropped back to not specifying a schema when
111
+ # setting up the foreign key to the refs table. If we had not
112
+ # used ignore_schema, the foreign key would have been defined
113
+ # thusly:
114
+ #
115
+ # ### sql
116
+ # FOREIGN KEY ("ref_id") REFERENCES "geospatial"."refs" ("id")
117
+ def ignore_schema
118
+ with_schema nil do
119
+ yield
120
+ end
121
+ end
122
+
123
+ # See what the current scoped schemas are. Should be thread-safe
124
+ # if using the PostgreSQL adapter's concurrency mode.
125
+ def scoped_schemas
126
+ scoped_schemas = (Thread.current[:scoped_schemas] ||= {})
127
+ scoped_schemas[self] ||= []
128
+ end
129
+
130
+ # Get the current scoped schema.
131
+ def current_schema
132
+ scoped_schemas.last
133
+ end
134
+
135
+ # A generic quoting method for PostgreSQL.
136
+ def quote_generic(g)
137
+ PGconn.quote_ident(g.to_s)
138
+ end
139
+
140
+ # A generic quoting method for PostgreSQL that specifically ignores
141
+ # any and all schemas.
142
+ def quote_generic_ignore_schema(g)
143
+ if g.is_a?(Hash)
144
+ quote_generic g.values.first
145
+ else
146
+ quote_generic g
147
+ end
148
+ end
149
+
150
+ # A generic quoting method for PostgreSQL with our special schema
151
+ # support.
152
+ def quote_generic_with_schema(g)
153
+ if g.is_a?(Hash)
154
+ "#{quote_schema(g.keys.first)}.#{quote_generic(g.values.first)}"
155
+ else
156
+ if current_schema
157
+ quote_schema(current_schema) << '.'
158
+ end.to_s << quote_generic(g)
159
+ end
160
+ end
161
+
162
+ # Quoting method for roles.
163
+ def quote_role(role)
164
+ quote_generic(role)
165
+ end
166
+
167
+ # Quoting method for rules.
168
+ def quote_rule(rule)
169
+ quote_generic(rule)
170
+ end
171
+
172
+ # Quoting method for procedural languages.
173
+ def quote_language(language)
174
+ quote_generic(language)
175
+ end
176
+
177
+ # Quoting method for schemas. When the schema is :public or
178
+ # 'public' or some form thereof, we'll convert that to "PUBLIC"
179
+ # without quoting.
180
+ def quote_schema(schema)
181
+ if schema.to_s.upcase == 'PUBLIC'
182
+ 'PUBLIC'
183
+ else
184
+ quote_generic(schema)
185
+ end
186
+ end
187
+
188
+ # Quoting method for sequences. This really just goes to the
189
+ # quoting method for table names, as sequences can belong to
190
+ # specific schemas.
191
+ def quote_sequence(name)
192
+ quote_generic_with_schema(name)
193
+ end
194
+
195
+ # Quoting method for server-side functions.
196
+ def quote_function(name)
197
+ quote_generic_with_schema(name)
198
+ end
199
+
200
+ # Quoting method for table names. This method has been extended
201
+ # beyond the standard ActiveRecord quote_table_name to allow for
202
+ #
203
+ # * scoped schema support with with_schema. When using with_schema,
204
+ # table names will be prefixed with the current scoped schema
205
+ # name.
206
+ # * you can specify a specific schema using a Hash containing a
207
+ # single value pair where the key is the schema name and the
208
+ # key is the table name.
209
+ #
210
+ # Example of using a Hash as a table name:
211
+ #
212
+ # ### ruby
213
+ # quote_table_name(:geospatial => :epois) # => "geospatial"."epois"
214
+ # # => "geospatial"."epois"
215
+ #
216
+ # quote_table_name(:epois)
217
+ # # => "epois"
218
+ #
219
+ # with_schema(:geospatial) { quote_table_name(:epois) }
220
+ # # => "geospatial"."epois"
221
+ #
222
+ # with_schema(:geospatial) do
223
+ # ignore_schema do
224
+ # quote_table_name(:epois)
225
+ # end
226
+ # end
227
+ # # => "epois"
228
+ def quote_table_name_with_schemas(name)
229
+ if current_schema || name.is_a?(Hash)
230
+ quote_generic_with_schema(name)
231
+ else
232
+ quote_table_name_without_schemas(name)
233
+ end
234
+ end
235
+ alias_method_chain :quote_table_name, :schemas
236
+
237
+ # Quoting method for view names. This really just goes to the
238
+ # quoting method for table names, as views can belong to specific
239
+ # schemas.
240
+ def quote_view_name(name)
241
+ quote_table_name(name)
242
+ end
243
+
244
+ # Quoting method for tablespaces.
245
+ def quote_tablespace(name)
246
+ quote_generic(name)
247
+ end
248
+
249
+ def extract_schema_name(name)
250
+ schema, name_part = extract_pg_identifier_from_name(name.to_s)
251
+ schema if name_part
252
+ end
253
+
254
+ def extract_table_name(name)
255
+ schema, name_part = extract_pg_identifier_from_name(name.to_s)
256
+
257
+ unless name_part
258
+ schema
259
+ else
260
+ table_name, name_part = extract_pg_identifier_from_name(name_part)
261
+ table_name
262
+ end
263
+ end
264
+
265
+ def extract_schema_and_table_names(name)
266
+ schema, name_part = extract_pg_identifier_from_name(name.to_s)
267
+
268
+ unless name_part
269
+ quote_column_name(schema)
270
+ [ nil, schema ]
271
+ else
272
+ table_name, name_part = extract_pg_identifier_from_name(name_part)
273
+ [ schema, table_name ]
274
+ end
275
+ end
276
+
277
+ # Copies the contents of a file into a table. This uses
278
+ # PostgreSQL's COPY FROM command.
279
+ #
280
+ # The COPY FROM command requires the input file to be readable
281
+ # on the server the database is actually running on. In our method,
282
+ # you have the choice of a file on your client's local file system
283
+ # or one on the server's local file system. See the
284
+ # <tt>:local</tt> option below.
285
+ #
286
+ # See the PostgreSQL documentation for details on COPY FROM.
287
+ #
288
+ # ==== Options
289
+ #
290
+ # * <tt>:columns</tt> - allows you to specify column names.
291
+ # * <tt>:binary</tt> - adds the BINARY clause.
292
+ # * <tt>:oids</tt> - adds the OIDS clause.
293
+ # * <tt>:delimiter</tt> - sets the delimiter for the data fields.
294
+ # The default COPY FROM delimiter in ASCII mode is a tab
295
+ # character, while in CSV it is a comma.
296
+ # * <tt>:null</tt> - allows you to set a default value for null
297
+ # fields. The default for this option is unset.
298
+ # * <tt>:local</tt> - allows you to specify that the file to be
299
+ # copied from is on a file system that is directly accessible
300
+ # from the database server itself. The default is true, i.e.
301
+ # the file is local to the client. See below for a more thorough
302
+ # explanation.
303
+ # * <tt>:csv</tt> - allows you to specify a CSV file. This option
304
+ # can be set to true, in which case you'll be using the server
305
+ # defaults for its CSV imports, or a Hash, in which case you can
306
+ # modify various CSV options like quote and escape characters.
307
+ #
308
+ # ===== CSV Options
309
+ #
310
+ # * <tt>:header</tt> - uses the first line as a CSV header row and
311
+ # skips over it.
312
+ # * <tt>:quote</tt> - the character to use for quoting. The default
313
+ # is a double-quote.
314
+ # * <tt>:escape</tt> - the character to use when escaping a quote
315
+ # character. Usually this is another double-quote.
316
+ # * <tt>:not_null</tt> - allows you to specify one or more columns
317
+ # to be inserted with a default value rather than NULL for any
318
+ # missing values.
319
+ #
320
+ # ==== Local Server Files vs. Local Client Files
321
+ #
322
+ # The copy_from_file method allows you to import rows from a file
323
+ # that exists on either your client's file system or on the
324
+ # database server's file system using the <tt>:local</tt> option.
325
+ #
326
+ # To process a file on the remote database server's file system:
327
+ #
328
+ # * the file must be given as an absolute path;
329
+ # * must be readable by the user that the actual PostgreSQL
330
+ # database server runs under; and
331
+ # * the COPY FROM command itself can only be performed by database
332
+ # superusers.
333
+ #
334
+ # In comparison, reading the file from the local client does not
335
+ # have restrictions enforced by PostgreSQL and can be performed on
336
+ # the client machine. When using a local file, the file itself is
337
+ # actually opened in Ruby and pushed into the database via a
338
+ # "COPY FROM STDIN" command. Thus, the file must be readable by
339
+ # the user your Ruby process is running as. PostgreSQL will not
340
+ # enforce the superuser restriction in this case since you are not
341
+ # touching the database server's local file system.
342
+ #
343
+ # Some considerations:
344
+ #
345
+ # * A copy from the database's local file system is faster than a
346
+ # local copy, as the data need not be read into Ruby and dumped
347
+ # across the network or UNIX socket to the database server.
348
+ # * A local copy is generally more flexible as it bypasses some of
349
+ # PostgreSQL's security considerations.
350
+ # * Copies from the server's file system require that the file
351
+ # exists on the file system accessible to the database server,
352
+ # something that you may not even have access to in the first
353
+ # place.
354
+ def copy_from_file(table_name, file, options = {})
355
+ options = {
356
+ :local => true
357
+ }.merge(options)
358
+
359
+ sql = "COPY #{quote_table_name(table_name)} "
360
+
361
+ unless options[:columns].blank?
362
+ sql << '(' << Array(options[:columns]).collect { |c| quote_column_name(c) }.join(', ') << ')'
363
+ end
364
+
365
+ if options[:local]
366
+ sql << " FROM STDIN"
367
+ else
368
+ sql << " FROM #{quote(file)}"
369
+ end
370
+
371
+ sql << ' BINARY' if options[:binary]
372
+ sql << ' OIDS' if options[:oids]
373
+ sql << " DELIMITER AS #{quote(options[:delimiter])}" if options[:delimiter]
374
+ sql << " NULL AS #{quote(options[:null_as])}" if options[:null]
375
+
376
+ if options[:csv]
377
+ sql << ' CSV'
378
+ if options[:csv].is_a?(Hash)
379
+ sql << ' HEADER' if options[:csv][:header]
380
+ sql << " QUOTE AS #{quote(options[:csv][:quote])}" if options[:csv][:quote]
381
+ sql << " ESCAPE AS #{quote(options[:csv][:escape])}" if options[:csv][:escape]
382
+ sql << ' FORCE NOT NULL ' << Array(options[:csv][:not_null]).collect do |c|
383
+ quote_column_name(c)
384
+ end.join(', ') if options[:csv][:not_null]
385
+ end
386
+ end
387
+
388
+ execute sql
389
+
390
+ if options[:local]
391
+ File.open(file, 'r').each do |l|
392
+ self.raw_connection.put_copy_data(l)
393
+ end
394
+ self.raw_connection.put_copy_end
395
+ end
396
+ end
397
+
398
+ # Returns an Array of database views.
399
+ def views(name = nil)
400
+ query(<<-SQL, name).map { |row| row[0] }
401
+ SELECT viewname
402
+ FROM pg_views
403
+ WHERE schemaname = ANY (current_schemas(false))
404
+ SQL
405
+ end
406
+
407
+ def view_exists?(name)
408
+ name = name.to_s
409
+ schema, view = name.split('.', 2)
410
+
411
+ unless view # A view was provided without a schema
412
+ view = schema
413
+ schema = nil
414
+ end
415
+
416
+ if name =~ /^"/ # Handle quoted view names
417
+ view = name
418
+ schema = nil
419
+ end
420
+
421
+ query(<<-SQL).first[0].to_i > 0
422
+ SELECT COUNT(*)
423
+ FROM pg_views
424
+ WHERE viewname = '#{view.gsub(/(^"|"$)/,'')}'
425
+ #{schema ? "AND schemaname = '#{schema}'" : ''}
426
+ SQL
427
+ end
428
+
429
+ # Returns an Array of tables to ignore.
430
+ def ignored_tables(name = nil)
431
+ query(<<-SQL, name).map { |row| row[0] }
432
+ SELECT tablename
433
+ FROM pg_tables
434
+ WHERE schemaname IN ('pg_catalog')
435
+ SQL
436
+ end
437
+
438
+ def tables_with_views(name = nil) #:nodoc:
439
+ tables_without_views(name) + views(name)
440
+ end
441
+ alias_method_chain :tables, :views
442
+
443
+ def schema_search_path_with_csv_fix=(schema_csv) #:nodoc:
444
+ self.schema_search_path_without_csv_fix = schema_csv.gsub(/, /, ',') if schema_csv
445
+ end
446
+ alias_method_chain :schema_search_path=, :csv_fix
447
+
448
+ def schema_search_path_with_csv_fix #:nodoc:
449
+ @schema_search_path ||= query('SHOW search_path')[0][0].gsub(/, /, ',')
450
+ end
451
+ alias_method_chain :schema_search_path, :csv_fix
452
+
453
+ def disable_referential_integrity_with_views #:nodoc:
454
+ if supports_disable_referential_integrity?() then
455
+ execute((tables - views).collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
456
+ end
457
+ yield
458
+ ensure
459
+ if supports_disable_referential_integrity?() then
460
+ execute((tables - views).collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER ALL" }.join(";"))
461
+ end
462
+ end
463
+ alias_method_chain :disable_referential_integrity, :views
464
+
465
+ # Returns an Array of foreign keys for a particular table. The
466
+ # Array itself is an Array of Arrays, where each particular Array
467
+ # contains the table being referenced, the foreign key and the
468
+ # name of the column in the referenced table.
469
+ def foreign_keys(table_name, name = nil)
470
+ sql = <<-SQL
471
+ SELECT
472
+ confrelid::regclass AS referenced_table_name,
473
+ a.attname AS foreign_key,
474
+ af.attname AS referenced_column
475
+ FROM
476
+ pg_attribute af,
477
+ pg_attribute a,
478
+ pg_class c, (
479
+ SELECT
480
+ conrelid,
481
+ confrelid,
482
+ conkey[i] AS conkey,
483
+ confkey[i] AS confkey
484
+ FROM (
485
+ SELECT
486
+ conrelid,
487
+ confrelid,
488
+ conkey,
489
+ confkey,
490
+ generate_series(1, array_upper(conkey, 1)) AS i
491
+ FROM
492
+ pg_constraint
493
+ WHERE
494
+ contype = 'f'
495
+ ) ss
496
+ ) ss2
497
+ WHERE
498
+ c.oid = conrelid
499
+ AND
500
+ c.relname = #{quote(table_name)}
501
+ AND
502
+ af.attnum = confkey
503
+ AND
504
+ af.attrelid = confrelid
505
+ AND
506
+ a.attnum = conkey
507
+ AND
508
+ a.attrelid = conrelid
509
+ SQL
510
+
511
+ query(sql, name).inject([]) do |memo, (tbl, column, referenced_column)|
512
+ memo.tap {
513
+ memo << {
514
+ :table => tbl,
515
+ :column => column,
516
+ :referenced_column => referenced_column
517
+ }
518
+ }
519
+ end
520
+ end
521
+
522
+ # Returns an Array of foreign keys that point to a particular
523
+ # table. The Array itself is an Array of Arrays, where each
524
+ # particular Array contains the referencing table, the foreign key
525
+ # and the name of the column in the referenced table.
526
+ def referenced_foreign_keys(table_name, name = nil)
527
+ sql = <<-SQL
528
+ SELECT
529
+ c2.relname AS table_name,
530
+ a.attname AS foreign_key,
531
+ af.attname AS referenced_column
532
+ FROM
533
+ pg_attribute af,
534
+ pg_attribute a,
535
+ pg_class c1,
536
+ pg_class c2, (
537
+ SELECT
538
+ conrelid,
539
+ confrelid,
540
+ conkey[i] AS conkey,
541
+ confkey[i] AS confkey
542
+ FROM (
543
+ SELECT
544
+ conrelid,
545
+ confrelid,
546
+ conkey,
547
+ confkey,
548
+ generate_series(1, array_upper(conkey, 1)) AS i
549
+ FROM
550
+ pg_constraint
551
+ WHERE
552
+ contype = 'f'
553
+ ) ss
554
+ ) ss2
555
+ WHERE
556
+ confrelid = c1.oid
557
+ AND
558
+ conrelid = c2.oid
559
+ AND
560
+ c1.relname = #{quote(table_name)}
561
+ AND
562
+ af.attnum = confkey
563
+ AND
564
+ af.attrelid = confrelid
565
+ AND
566
+ a.attnum = conkey
567
+ AND
568
+ a.attrelid = conrelid
569
+ SQL
570
+
571
+ query(sql, name).inject([]) do |memo, (tbl, column, referenced_column)|
572
+ memo.tap {
573
+ memo << {
574
+ :table => tbl,
575
+ :column => column,
576
+ :referenced_column => referenced_column
577
+ }
578
+ }
579
+ end
580
+ end
581
+
582
+ def add_column_options_with_expression!(sql, options) #:nodoc:
583
+ if options_include_default?(options) &&
584
+ options[:default].is_a?(Hash) &&
585
+ options[:default].has_key?(:expression)
586
+
587
+ expression = options.delete(:default)
588
+ sql << " DEFAULT #{expression[:expression]}"
589
+ end
590
+ add_column_options_without_expression!(sql, options)
591
+ end
592
+ alias_method_chain :add_column_options!, :expression
593
+
594
+ def change_column_default_with_expression(table_name, column_name, default) #:nodoc:
595
+ if default.is_a?(Hash) && default.has_key?(:expression)
596
+ execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT #{default[:expression]}"
597
+ else
598
+ change_column_default_without_expression(table_name, column_name, default)
599
+ end
600
+ end
601
+ alias_method_chain :change_column_default, :expression
602
+ end
603
+ end
604
+ end
605
+
606
+ module ActiveRecord
607
+ class Base
608
+ class << self
609
+ def with_schema(schema)
610
+ self.connection.with_schema(schema) { |*block_args|
611
+ yield(*block_args)
612
+ }
613
+ end
614
+
615
+ def ignore_schema
616
+ self.connection.ignore_schema { |*block_args|
617
+ yield(*block_args)
618
+ }
619
+ end
620
+
621
+ def scoped_schemas
622
+ self.connection.scope_schemas
623
+ end
624
+
625
+ def current_schema
626
+ self.connection.current_schema
627
+ end
628
+
629
+ def sequence_exists?
630
+ !!(connection.sequence_exists?(sequence_name) if connection.respond_to?(:sequence_exists?))
631
+ end
632
+
633
+ def view_exists?
634
+ connection.view_exists?(table_name)
635
+ end
636
+ end
637
+ end
638
+ end
639
+
640
+ ActiveRecord::Base.class_eval do
641
+ # Enable extended query logging
642
+ cattr_accessor :enable_extended_logging
643
+
644
+ # Enable REALLY extended query logging
645
+ cattr_accessor :enable_really_extended_logging
646
+ end