activerecord-postgresql-extensions 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +4 -0
  3. data/Gemfile +1 -0
  4. data/Guardfile +3 -3
  5. data/MIT-LICENSE +1 -1
  6. data/README.rdoc +10 -3
  7. data/lib/active_record/postgresql_extensions/adapter_extensions.rb +100 -60
  8. data/lib/active_record/postgresql_extensions/constraints.rb +13 -17
  9. data/lib/active_record/postgresql_extensions/event_triggers.rb +129 -0
  10. data/lib/active_record/postgresql_extensions/extensions.rb +14 -15
  11. data/lib/active_record/postgresql_extensions/features.rb +80 -41
  12. data/lib/active_record/postgresql_extensions/functions.rb +1 -1
  13. data/lib/active_record/postgresql_extensions/geometry.rb +6 -8
  14. data/lib/active_record/postgresql_extensions/indexes.rb +19 -11
  15. data/lib/active_record/postgresql_extensions/languages.rb +1 -1
  16. data/lib/active_record/postgresql_extensions/materialized_views.rb +272 -0
  17. data/lib/active_record/postgresql_extensions/permissions.rb +60 -22
  18. data/lib/active_record/postgresql_extensions/roles.rb +18 -7
  19. data/lib/active_record/postgresql_extensions/rules.rb +5 -0
  20. data/lib/active_record/postgresql_extensions/schemas.rb +39 -3
  21. data/lib/active_record/postgresql_extensions/sequences.rb +6 -3
  22. data/lib/active_record/postgresql_extensions/tables.rb +47 -19
  23. data/lib/active_record/postgresql_extensions/tablespaces.rb +1 -1
  24. data/lib/active_record/postgresql_extensions/text_search.rb +3 -3
  25. data/lib/active_record/postgresql_extensions/triggers.rb +3 -3
  26. data/lib/active_record/postgresql_extensions/types.rb +104 -1
  27. data/lib/active_record/postgresql_extensions/utils.rb +35 -13
  28. data/lib/active_record/postgresql_extensions/vacuum.rb +1 -1
  29. data/lib/active_record/postgresql_extensions/version.rb +1 -1
  30. data/lib/active_record/postgresql_extensions/views.rb +137 -6
  31. data/lib/activerecord-postgresql-extensions.rb +13 -11
  32. data/test/{adapter_tests.rb → adapter_extensions_tests.rb} +96 -3
  33. data/test/constraints_tests.rb +216 -104
  34. data/test/event_triggers_tests.rb +109 -0
  35. data/test/extensions_tests.rb +47 -39
  36. data/test/functions_tests.rb +47 -38
  37. data/test/geometry_tests.rb +268 -135
  38. data/test/{index_tests.rb → indexes_tests.rb} +16 -16
  39. data/test/languages_tests.rb +26 -9
  40. data/test/materialized_views_tests.rb +174 -0
  41. data/test/permissions_tests.rb +159 -45
  42. data/test/roles_tests.rb +17 -7
  43. data/test/rules_tests.rb +14 -6
  44. data/test/schemas_tests.rb +35 -9
  45. data/test/sequences_tests.rb +9 -11
  46. data/test/tables_tests.rb +132 -42
  47. data/test/tablespace_tests.rb +21 -15
  48. data/test/test_helper.rb +56 -10
  49. data/test/text_search_tests.rb +42 -44
  50. data/test/trigger_tests.rb +1 -3
  51. data/test/types_tests.rb +95 -0
  52. data/test/vacuum_tests.rb +1 -3
  53. data/test/views_tests.rb +203 -0
  54. metadata +22 -16
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZDVjMzkzNjNhYzc2MzQxNDkyZTA3MWQzM2FlZGZlZmQzYzkxMDkxNA==
5
+ data.tar.gz: !binary |-
6
+ NjMzOTZjOTFkOGE3NTQyMmU1ODg2NzJhNmQ3MzQ3NjgwNTRkNzZhNQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MzEzN2MzMjg4YjYzZWI5NjIyNWJmNmNjNjc1NmZiMjNkYjZmODM5MjUyN2Iw
10
+ NTJjYzBkYzMxZTZjYTk3OTE2ODZhZDZmZjc5YmUxNzY2YmIxMDdjZjRiMzk1
11
+ YjRjZjk0NTkxMDdjN2Q5MTRkYmM3YmMxMWU4MDhkZGFhMWMxMDA=
12
+ data.tar.gz: !binary |-
13
+ ZTUyOGIwZTc5MjAwMDRlZGE4ZTI0MzI5OTk1YTM1NjM3MTVkZGJlYjA2MTA0
14
+ MzczY2U4NTMwNDdhZTU2MmJhNTJmMjBlYjFmZDU1NzExMDI2ZjRhZmVhNzAz
15
+ YWNjYmE1NWU1MzkxMDk3ZDMwYzBiMzNkZGNhZjUyMTg5OTAzN2I=
data/.gitignore CHANGED
@@ -1,3 +1,6 @@
1
+ .*.swp
2
+ .*.swo
3
+ *.tmp
1
4
  *.kpf
2
5
  *.komodoproject
3
6
  *~
@@ -5,6 +8,7 @@
5
8
  *tmp*
6
9
  pkg/
7
10
  doc/
11
+ coverage/
8
12
  *.orig
9
13
  *.patch
10
14
  .vimrc_local
data/Gemfile CHANGED
@@ -13,6 +13,7 @@ gem "rake", "~> 10.0"
13
13
  gem "minitest"
14
14
  gem "minitest-reporters"
15
15
  gem "guard-minitest"
16
+ gem "simplecov"
16
17
 
17
18
  if RbConfig::CONFIG['host_os'] =~ /^darwin/
18
19
  gem "rb-fsevent"
data/Guardfile CHANGED
@@ -1,9 +1,9 @@
1
1
 
2
- guard 'minitest', :test_folders => 'test', :test_file_patterns => '*_tests.rb' do
2
+ guard 'minitest', :test_folders => 'test', :test_file_patterns => '*_tests.rb', :all_on_start => false do
3
3
  watch(%r|^test/(.+)_tests\.rb|)
4
4
 
5
- watch(%r|^lib/(.*)([^/]+)\.rb|) do |m|
6
- "test/#{m[1]}#{m[2]}_tests.rb"
5
+ watch(%r|^lib/(.*/)?(.+)\.rb|) do |m|
6
+ "test/#{m[2]}_tests.rb"
7
7
  end
8
8
 
9
9
  watch(%r|^test/test_helper\.rb|) do
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012 2167961 Ontario Inc., Zoocasa <code@zoocasa.com>
1
+ Copyright (c) 2013 2167961 Ontario Inc., Zoocasa <code@zoocasa.com>
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person
4
4
  obtaining a copy of this software and associated documentation
data/README.rdoc CHANGED
@@ -9,7 +9,8 @@ PostgreSQL adapter including:
9
9
  and per table.
10
10
 
11
11
  * some methods for manipulating all sorts of stuff like procedural languages,
12
- functions, sequences, views, schemas and triggers.
12
+ functions, sequences, views, schemas, triggers, types, extensions,
13
+ materialized views and event triggers.
13
14
 
14
15
  * better support for creating indexes with expressions so you can use functions
15
16
  and GiST and GIN indexes.
@@ -26,8 +27,8 @@ PostgreSQL adapter including:
26
27
 
27
28
  * support for some PostGIS functionality including some support for using
28
29
  PostGIS columns in migrations. For manipulating PostGIS data, see our
29
- geos-extensions gem at https://github.com/zoocasa/geos-extensions or
30
- the RGeo project at https://github.com/dazuma/rgeo .
30
+ activerecord-spatial gem at https://github.com/zoocasa/activerecord-spatial
31
+ or the RGeo project at https://github.com/dazuma/rgeo .
31
32
 
32
33
  == Building db/schema.rb
33
34
 
@@ -46,3 +47,9 @@ containing the database schema in db/development_structure.sql.
46
47
  Details on this configuration option can be found here:
47
48
 
48
49
  http://guides.rubyonrails.org/configuring.html
50
+
51
+ == License
52
+
53
+ This gem is licensed under an MIT-style license. See the +MIT-LICENSE+ file for
54
+ details.
55
+
@@ -1,39 +1,10 @@
1
1
 
2
2
  module ActiveRecord
3
+ class InvalidCopyFromOptions < ActiveRecordError #:nodoc:
4
+ end
5
+
3
6
  module ConnectionAdapters
4
7
  class PostgreSQLAdapter
5
- if defined?(Rails)
6
- LOGGER_REGEXP = /^#{Rails.root}(?!\/vendor\/rails)/
7
-
8
- def query_with_extra_logging(*args) #:nodoc:
9
- if ActiveRecord::Base.enable_extended_logging && Rails.logger && Rails.logger.level == Logger::DEBUG
10
- sql = args.first
11
- unless (sql =~ /(pg_get_constraintdef|pg_attribute|pg_class)/)
12
- Rails.logger.debug
13
- Rails.logger.debug(caller.select { |x|
14
- ActiveRecord::Base.enable_really_extended_logging || x.match(LOGGER_REGEXP)
15
- }.join("\n"))
16
- end
17
- end
18
- query_without_extra_logging(*args)
19
- end
20
- alias_method_chain :query, :extra_logging
21
-
22
- def execute_with_extra_logging(*args) #:nodoc:
23
- if ActiveRecord::Base.enable_extended_logging && Rails.logger && Rails.logger.level == Logger::DEBUG
24
- sql = args.first
25
- unless (sql =~ /(pg_get_constraintdef|pg_attribute|pg_class)/)
26
- Rails.logger.debug
27
- Rails.logger.debug(caller.select { |x|
28
- ActiveRecord::Base.enable_really_extended_logging || x.match(LOGGER_REGEXP)
29
- }.join("\n"))
30
- end
31
- end
32
- execute_without_extra_logging(*args)
33
- end
34
- alias_method_chain :execute, :extra_logging
35
- end
36
-
37
8
  # with_schema is kind of like with_scope. It wraps various
38
9
  # object names in SQL statements into a PostgreSQL schema. You
39
10
  # can have multiple with_schemas wrapped around each other, and
@@ -301,16 +272,27 @@ module ActiveRecord
301
272
  # * <tt>:not_null</tt> - allows you to specify one or more columns
302
273
  # to be inserted with a default value rather than NULL for any
303
274
  # missing values.
275
+ # * <tt>:freeze</tt> - a performance enhancement added in PostgreSQL 9.3.
276
+ # See the PostgreSQL documentation for details.
277
+ # * <tt>:encoding</tt> - set the encoding of the input. Available in
278
+ # PostgreSQL 9.1+.
304
279
  #
305
- # ==== Local Server Files vs. Local Client Files
280
+ # ==== Local Server Files vs. Local Client Files vs. PROGRAM
306
281
  #
307
- # The copy_from_file method allows you to import rows from a file
282
+ # The copy_from method allows you to import rows from a file
308
283
  # that exists on either your client's file system or on the
309
284
  # database server's file system using the <tt>:local</tt> option.
310
285
  #
286
+ # PostgreSQL 9.3 additionally introduced the PROGRAM option to COPY
287
+ # FROM that allows you to pipe the output of a shell command to
288
+ # STDIN. This option requires that the COPY FROM command be run from on
289
+ # the server and as such may be limited by server restrictions such as
290
+ # access controls and permissions.
291
+ #
311
292
  # To process a file on the remote database server's file system:
312
293
  #
313
- # * the file must be given as an absolute path;
294
+ # * the file must be given as an absolute path or as a valid shell
295
+ # command if using the PROGRAM option;
314
296
  # * must be readable by the user that the actual PostgreSQL
315
297
  # database server runs under; and
316
298
  # * the COPY FROM command itself can only be performed by database
@@ -336,27 +318,33 @@ module ActiveRecord
336
318
  # exists on the file system accessible to the database server,
337
319
  # something that you may not even have access to in the first
338
320
  # place.
339
- def copy_from_file(table_name, file, options = {})
321
+ def copy_from(table_name, file, options = {})
340
322
  options = {
341
323
  :local => true
342
324
  }.merge(options)
343
325
 
344
- sql = "COPY #{quote_table_name(table_name)} "
326
+ assert_valid_copy_from_options(options)
327
+
328
+ sql = "COPY #{quote_table_name(table_name)}"
345
329
 
346
330
  unless options[:columns].blank?
347
- sql << '(' << Array(options[:columns]).collect { |c| quote_column_name(c) }.join(', ') << ')'
331
+ sql << ' (' << Array.wrap(options[:columns]).collect { |c| quote_column_name(c) }.join(', ') << ')'
348
332
  end
349
333
 
350
- if options[:local]
334
+ if options[:program]
335
+ sql << " FROM PROGRAM #{quote(file)}"
336
+ elsif options[:local]
351
337
  sql << " FROM STDIN"
352
338
  else
353
339
  sql << " FROM #{quote(file)}"
354
340
  end
355
341
 
342
+ sql << ' FREEZE' if options[:freeze]
356
343
  sql << ' BINARY' if options[:binary]
357
344
  sql << ' OIDS' if options[:oids]
358
345
  sql << " DELIMITER AS #{quote(options[:delimiter])}" if options[:delimiter]
359
346
  sql << " NULL AS #{quote(options[:null_as])}" if options[:null]
347
+ sql << " ENCODING #{quote(options[:encoding])}" if options[:encoding]
360
348
 
361
349
  if options[:csv]
362
350
  sql << ' CSV'
@@ -364,25 +352,39 @@ module ActiveRecord
364
352
  sql << ' HEADER' if options[:csv][:header]
365
353
  sql << " QUOTE AS #{quote(options[:csv][:quote])}" if options[:csv][:quote]
366
354
  sql << " ESCAPE AS #{quote(options[:csv][:escape])}" if options[:csv][:escape]
367
- sql << ' FORCE NOT NULL ' << Array(options[:csv][:not_null]).collect do |c|
355
+ sql << ' FORCE NOT NULL ' << Array.wrap(options[:csv][:not_null]).collect do |c|
368
356
  quote_column_name(c)
369
357
  end.join(', ') if options[:csv][:not_null]
370
358
  end
371
359
  end
372
360
 
373
- execute sql
361
+ sql << ';'
362
+
363
+ if options[:program] || !options[:local]
364
+ execute sql
365
+ else
366
+ fp = File.open(file, 'r')
374
367
 
375
- if options[:local]
376
- File.open(file, 'r').each do |l|
377
- self.raw_connection.put_copy_data(l)
368
+ if self.raw_connection.respond_to?(:copy_data)
369
+ self.raw_connection.copy_data(sql) do
370
+ fp.each do |l|
371
+ self.raw_connection.put_copy_data(l)
372
+ end
373
+ end
374
+ else
375
+ execute sql
376
+ fp.each do |l|
377
+ self.raw_connection.put_copy_data(l)
378
+ end
379
+ self.raw_connection.put_copy_end
378
380
  end
379
- self.raw_connection.put_copy_end
380
381
  end
381
382
  end
383
+ alias :copy_from_file :copy_from
382
384
 
383
385
  # Returns an Array of database views.
384
386
  def views(name = nil)
385
- query(<<-SQL, name).map { |row| row[0] }
387
+ query(PostgreSQLExtensions::Utils.strip_heredoc(<<-SQL), name).map { |row| row[0] }
386
388
  SELECT viewname
387
389
  FROM pg_views
388
390
  WHERE schemaname = ANY (current_schemas(false))
@@ -403,7 +405,7 @@ module ActiveRecord
403
405
  schema = nil
404
406
  end
405
407
 
406
- query(<<-SQL).first[0].to_i > 0
408
+ query(PostgreSQLExtensions::Utils.strip_heredoc(<<-SQL)).first[0].to_i > 0
407
409
  SELECT COUNT(*)
408
410
  FROM pg_views
409
411
  WHERE viewname = '#{view.gsub(/(^"|"$)/,'')}'
@@ -412,7 +414,7 @@ module ActiveRecord
412
414
  end
413
415
 
414
416
  def roles(name = nil)
415
- query(<<-SQL, name).map { |row| row[0] }
417
+ query(PostgreSQLExtensions::Utils.strip_heredoc(<<-SQL), name).map { |row| row[0] }
416
418
  SELECT rolname
417
419
  FROM pg_roles
418
420
  SQL
@@ -450,7 +452,7 @@ module ActiveRecord
450
452
 
451
453
  # Returns an Array of tables to ignore.
452
454
  def ignored_tables(name = nil)
453
- query(<<-SQL, name).map { |row| row[0] }
455
+ query(PostgreSQLExtensions::Utils.strip_heredoc(<<-SQL), name).map { |row| row[0] }
454
456
  SELECT tablename
455
457
  FROM pg_tables
456
458
  WHERE schemaname IN ('pg_catalog');
@@ -506,7 +508,7 @@ module ActiveRecord
506
508
  'ALL'
507
509
  end
508
510
 
509
- Array(triggers).each do |trigger|
511
+ Array.wrap(triggers).each do |trigger|
510
512
  execute("ALTER TABLE #{quoted_table_name} ENABLE TRIGGER #{trigger};")
511
513
  end
512
514
  end
@@ -523,7 +525,7 @@ module ActiveRecord
523
525
  'ALL'
524
526
  end
525
527
 
526
- Array(triggers).each do |trigger|
528
+ Array.wrap(triggers).each do |trigger|
527
529
  execute("ALTER TABLE #{quoted_table_name} DISABLE TRIGGER #{trigger};")
528
530
  end
529
531
  end
@@ -542,7 +544,7 @@ module ActiveRecord
542
544
  # contains the table being referenced, the foreign key and the
543
545
  # name of the column in the referenced table.
544
546
  def foreign_keys(table_name, name = nil)
545
- sql = <<-SQL
547
+ sql = PostgreSQLExtensions::Utils.strip_heredoc(<<-SQL)
546
548
  SELECT
547
549
  confrelid::regclass AS referenced_table_name,
548
550
  a.attname AS foreign_key,
@@ -600,7 +602,7 @@ module ActiveRecord
600
602
  # particular Array contains the referencing table, the foreign key
601
603
  # and the name of the column in the referenced table.
602
604
  def referenced_foreign_keys(table_name, name = nil)
603
- sql = <<-SQL
605
+ sql = PostgreSQLExtensions::Utils.strip_heredoc(<<-SQL)
604
606
  SELECT
605
607
  c2.relname AS table_name,
606
608
  a.attname AS foreign_key,
@@ -656,6 +658,36 @@ module ActiveRecord
656
658
  end
657
659
  end
658
660
 
661
+ # Run the CLUSTER command on all previously clustered tables available
662
+ # to be clustered by the current user.
663
+ #
664
+ # ==== Options
665
+ #
666
+ # * <tt>:verbose</tt> - Adds the VERBOSE clause.
667
+ def cluster_all(options = {})
668
+ sql = 'CLUSTER'
669
+ sql << ' VERBOSE' if options[:verbose]
670
+
671
+ execute "#{sql};"
672
+ end
673
+
674
+ # Cluster a table or materialized view on an index.
675
+ #
676
+ # ==== Options
677
+ #
678
+ # * <tt>:using</tt> - adds a USING clause to cluster on. If no
679
+ # <tt>:using</tt> option is provided, the object itself will be
680
+ # re-clustered.
681
+ # * <tt>:verbose</tt> - Adds the VERBOSE clause.
682
+ def cluster(name, options = {})
683
+ sql = 'CLUSTER '
684
+ sql << 'VERBOSE ' if options[:verbose]
685
+ sql << quote_table_name(name)
686
+ sql << " USING #{quote_generic(options[:using])}" if options[:using]
687
+
688
+ execute "#{sql};"
689
+ end
690
+
659
691
  def add_column_options_with_expression!(sql, options) #:nodoc:
660
692
  if options_include_default?(options) &&
661
693
  options[:default].is_a?(Hash) &&
@@ -688,6 +720,21 @@ module ActiveRecord
688
720
  end
689
721
  end
690
722
  alias_method_chain :change_column_null, :expression
723
+
724
+ private
725
+ def assert_valid_copy_from_options(options)
726
+ if options[:program] && !ActiveRecord::PostgreSQLExtensions::Features.copy_from_program?
727
+ raise InvalidCopyFromOptions.new("The :program option is only available in PostgreSQL 9.3+.")
728
+ end
729
+
730
+ if options[:freeze] && !ActiveRecord::PostgreSQLExtensions::Features.copy_from_freeze?
731
+ raise InvalidCopyFromOptions.new("The :freeze option is only available in PostgreSQL 9.3+.")
732
+ end
733
+
734
+ if options[:encoding] && !ActiveRecord::PostgreSQLExtensions::Features.copy_from_encoding?
735
+ raise InvalidCopyFromOptions.new("The :encoding option is only available in PostgreSQL 9.1+.")
736
+ end
737
+ end
691
738
  end
692
739
 
693
740
  class PostgreSQLColumn
@@ -742,10 +789,3 @@ module ActiveRecord
742
789
  end
743
790
  end
744
791
 
745
- ActiveRecord::Base.class_eval do
746
- # Enable extended query logging
747
- cattr_accessor :enable_extended_logging
748
-
749
- # Enable REALLY extended query logging
750
- cattr_accessor :enable_really_extended_logging
751
- end
@@ -21,12 +21,6 @@ module ActiveRecord
21
21
  end
22
22
  end
23
23
 
24
- class InvalidConstraintDependencyAction < ActiveRecordError #:nodoc:
25
- def initialize(option)
26
- super("Invalid constraint dependency action - #{option}")
27
- end
28
- end
29
-
30
24
  module ConnectionAdapters
31
25
  class PostgreSQLAdapter
32
26
  # Adds a CHECK constraint to the table. See
@@ -94,6 +88,8 @@ module ActiveRecord
94
88
  # This is a base class for other PostgreSQL constraint classes. It
95
89
  # isn't really meant to be used directly.
96
90
  class PostgreSQLConstraint
91
+ include ActiveRecord::PostgreSQLExtensions::Utils
92
+
97
93
  attr_accessor :base, :options
98
94
 
99
95
  def initialize(base, options) #:nodoc:
@@ -129,7 +125,7 @@ module ActiveRecord
129
125
 
130
126
  def storage_parameters
131
127
  if options[:index_parameters] || options[:storage_parameters]
132
- " WITH (#{options[:index_parameters] || options[:storage_parameters]})"
128
+ " WITH (#{options_from_hash_or_string(options[:index_parameters] || options[:storage_parameters])})"
133
129
  else
134
130
  ''
135
131
  end
@@ -395,8 +391,8 @@ module ActiveRecord
395
391
  # * <tt>:name</tt> - specifies a name for the constraint.
396
392
  # * <tt>:storage_parameters</tt> - PostgreSQL allows you to add a
397
393
  # couple of additional parameters to indexes to govern disk usage and
398
- # such. This option is a simple String that lets you insert these
399
- # options as necessary. See the PostgreSQL documentation on index
394
+ # such. This option is a simple String or a Hash that lets you insert
395
+ # these options as necessary. See the PostgreSQL documentation on index
400
396
  # storage parameters for details. <tt>:index_parameters</tt> can also
401
397
  # be used.
402
398
  # * <tt>:tablespace</tt> - allows you to specify a tablespace for the
@@ -424,7 +420,7 @@ module ActiveRecord
424
420
 
425
421
  def to_sql #:nodoc:
426
422
  sql = "#{constraint_name}UNIQUE ("
427
- sql << Array(columns).collect { |c| base.quote_column_name(c) }.join(', ')
423
+ sql << Array.wrap(columns).collect { |c| base.quote_column_name(c) }.join(', ')
428
424
  sql << ")"
429
425
  sql << storage_parameters
430
426
  sql << using_tablespace
@@ -601,9 +597,9 @@ module ActiveRecord
601
597
  end
602
598
 
603
599
  sql << "#{constraint_name}FOREIGN KEY ("
604
- sql << Array(columns).collect { |c| base.quote_column_name(c) }.join(', ')
600
+ sql << Array.wrap(columns).collect { |c| base.quote_column_name(c) }.join(', ')
605
601
  sql << ") REFERENCES #{base.quote_table_name(table)}"
606
- sql << ' (%s)' % Array(ref_columns).collect { |c| base.quote_column_name(c) }.join(', ') if ref_columns
602
+ sql << ' (%s)' % Array.wrap(ref_columns).collect { |c| base.quote_column_name(c) }.join(', ') if ref_columns
607
603
  sql << " MATCH #{options[:match].to_s.upcase}" if options[:match]
608
604
  sql << " ON DELETE #{options[:on_delete].to_s.gsub(/_/, ' ').upcase}" if options[:on_delete]
609
605
  sql << " ON UPDATE #{options[:on_update].to_s.gsub(/_/, ' ').upcase}" if options[:on_update]
@@ -691,8 +687,8 @@ module ActiveRecord
691
687
  # default which is <tt>:btree</tt>. See the PostgreSQL docs for details.
692
688
  # * <tt>:storage_parameters</tt> - PostgreSQL allows you to add a
693
689
  # couple of additional parameters to indexes to govern disk usage and
694
- # such. This option is a simple String that lets you insert these
695
- # options as necessary. See the PostgreSQL documentation on index
690
+ # such. This option is a simple String or a Hash that lets you insert
691
+ # these options as necessary. See the PostgreSQL documentation on index
696
692
  # storage parameters for details. <tt>:index_parameters</tt> can also
697
693
  # be used.
698
694
  # * <tt>:tablespace</tt> - allows you to specify a tablespace for the
@@ -830,8 +826,8 @@ module ActiveRecord
830
826
  # * <tt>:name</tt> - specifies a name for the constraint.
831
827
  # * <tt>:storage_parameters</tt> - PostgreSQL allows you to add a
832
828
  # couple of additional parameters to indexes to govern disk usage and
833
- # such. This option is a simple String that lets you insert these
834
- # options as necessary. See the PostgreSQL documentation on index
829
+ # such. This option is a simple String or a Hash that lets you insert
830
+ # these options as necessary. See the PostgreSQL documentation on index
835
831
  # storage parameters for details. <tt>:index_parameters</tt> can also
836
832
  # be used.
837
833
  # * <tt>:tablespace</tt> - allows you to specify a tablespace for the
@@ -855,7 +851,7 @@ module ActiveRecord
855
851
  def to_sql #:nodoc:
856
852
  sql = String.new
857
853
  sql << "#{constraint_name}PRIMARY KEY "
858
- sql << "(" << Array(columns).collect { |column|
854
+ sql << "(" << Array.wrap(columns).collect { |column|
859
855
  base.quote_column_name(column)
860
856
  }.join(', ')
861
857
  sql << ")"