activerecord-postgresql-extensions 0.0.7

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 (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