diff --git a/doc/postgresql.rdoc b/doc/postgresql.rdoc index 232271896..8cf48a65d 100644 --- a/doc/postgresql.rdoc +++ b/doc/postgresql.rdoc @@ -553,6 +553,12 @@ handle locking: # INSERT INTO "table" ("id") VALUES (2) RETURNING NULL; # COMMIT; +== PostgreSQL-specific reflection Support + +The Database#indexes method supports the options :include_partial and :include_invalid. +These options allow partial and invalid indexes to be included in the results, respectively. +By default, Sequel excludes both partial and invalid indexes. + == Extended Error Info (postgres/pg only) If you run a query that raises a Sequel::DatabaseError, you can pass the exception object to diff --git a/lib/sequel/adapters/shared/postgres.rb b/lib/sequel/adapters/shared/postgres.rb index 5e3e21b58..338ed9063 100644 --- a/lib/sequel/adapters/shared/postgres.rb +++ b/lib/sequel/adapters/shared/postgres.rb @@ -674,6 +674,7 @@ def indexes(table, opts=OPTS) m = output_identifier_meth cond = {Sequel[:tab][:oid]=>regclass_oid(table, opts)} cond[:indpred] = nil unless opts[:include_partial] + cond[:indisvalid] = true unless opts[:include_invalid] indexes = {} _indexes_ds.where_each(cond) do |r| @@ -1049,8 +1050,7 @@ def _indexes_ds where{{ indc[:relkind]=>%w'i I', ind[:indisprimary]=>false, - :indexprs=>nil, - :indisvalid=>true}}. + :indexprs=>nil}}. order(*order). select{[indc[:relname].as(:name), ind[:indisunique].as(:unique), att[:attname].as(:column), con[:condeferrable].as(:deferrable)]} @@ -1757,7 +1757,7 @@ def index_definition_sql(table_name, index) index_type = :gist end - "CREATE #{unique}INDEX#{' CONCURRENTLY' if index[:concurrently]}#{if_not_exists} #{quote_identifier(index_name)} ON #{quote_schema_table(table_name)} #{"USING #{index_type} " if index_type}#{expr}#{" INCLUDE #{literal(Array(index[:include]))}" if index[:include]}#{nulls_distinct}#{" TABLESPACE #{quote_identifier(index[:tablespace])}" if index[:tablespace]}#{filter}" + "CREATE #{unique}INDEX#{' CONCURRENTLY' if index[:concurrently]}#{if_not_exists} #{quote_identifier(index_name)} ON#{' ONLY' if index[:only]} #{quote_schema_table(table_name)} #{"USING #{index_type} " if index_type}#{expr}#{" INCLUDE #{literal(Array(index[:include]))}" if index[:include]}#{nulls_distinct}#{" TABLESPACE #{quote_identifier(index[:tablespace])}" if index[:tablespace]}#{filter}" end # Setup datastructures shared by all postgres adapters. diff --git a/lib/sequel/database/schema_generator.rb b/lib/sequel/database/schema_generator.rb index 22e9f3b0d..71391c21c 100644 --- a/lib/sequel/database/schema_generator.rb +++ b/lib/sequel/database/schema_generator.rb @@ -299,6 +299,7 @@ def has_column?(name) # :opclass :: Set an opclass to use for all columns (per-column opclasses require # custom SQL). # :tablespace :: Specify tablespace for index. + # :only :: Create index only for given table, not for any child tables (PostgreSQL 11+) # # Microsoft SQL Server specific options: # diff --git a/spec/adapters/postgres_spec.rb b/spec/adapters/postgres_spec.rb index 2c665a583..dc85194af 100644 --- a/spec/adapters/postgres_spec.rb +++ b/spec/adapters/postgres_spec.rb @@ -1576,6 +1576,13 @@ def before_create @db.indexes(:test, :include_partial=>true)[:tnv_partial].must_equal(:columns=>[:name, :value], :unique=>false, :deferrable=>nil) end + it "should support parsing invalid indexes with :include_invalid option" do + @db.add_index :test, [:name, :value], :name=>:tnv_invalid + @db.run("UPDATE pg_index SET indisvalid = false WHERE indexrelid = 'tnv_invalid'::regclass;") + @db.indexes(:test)[:tnv_invalid].must_be_nil + @db.indexes(:test, :include_invalid=>true)[:tnv_invalid].must_equal(:columns=>[:name, :value], :unique=>false, :deferrable=>nil) + end + it "should support creating indexes concurrently" do @db.add_index :test, [:name, :value], :concurrently=>true, :name=>'tnv0' end @@ -1634,6 +1641,15 @@ def before_create @db.add_index :atest, :a, :tablespace=>:pg_default end + it "should support creating indexes with ONLY option" do + @db.create_table(:atest, partition_by: :id, :partition_type=>:range){Integer :id} + @db.create_table(:btest, partition_of: :atest){from 1; to 3} + @db.add_index :atest, :id, :only=>true + + @db.indexes(:atest, :include_invalid=>true).size.must_equal 1 + @db.indexes(:btest, :include_invalid=>true).must_be_empty + end if DB.server_version >= 110000 + it "#lock should lock table if inside a transaction" do @db.transaction{@d.lock('EXCLUSIVE'); @d.insert(:name=>'a')} end