diff --git a/doc/src/sgml/glossary.sgml b/doc/src/sgml/glossary.sgml
index 76525c6302..1dac096f23 100644
--- a/doc/src/sgml/glossary.sgml
+++ b/doc/src/sgml/glossary.sgml
@@ -1689,6 +1689,30 @@
+
+ Type
+
+
+ All data stored within the database is typed. Each type has both a name, and associated
+ properties, as well as an overarching Type, of which there are two variations. Extensible
+ types can created by users and comprise of: base, composite, domain, enum, and range. There
+ are also the system-only pseudo-types. Type records are stored in pg_type and the
+ overarching type is found in pg_type.typtype.
+
+
+
+
+
+ Type Definition
+
+
+ Collective term for the various Type
+ variants that are allowed for pg_type.typtype catalog table column values;
+ specifically, ones that are extensible.
+
+
+
+
Unique constraint
diff --git a/doc/src/sgml/ref/drop_domain.sgml b/doc/src/sgml/ref/drop_domain.sgml
index b18faf3917..8b04b3818b 100644
--- a/doc/src/sgml/ref/drop_domain.sgml
+++ b/doc/src/sgml/ref/drop_domain.sgml
@@ -30,7 +30,9 @@ DROP DOMAIN [ IF EXISTS ] name [, .
DROP DOMAIN removes a domain. Only the owner of
- a domain can remove it.
+ a domain can remove it. The duplicates the functionality provided by
+ but restricts the object type to domain.
+
@@ -42,8 +44,13 @@ DROP DOMAIN [ IF EXISTS ] name [, .
IF EXISTS
- Do not throw an error if the domain does not exist. A notice is issued
- in this case.
+ This parameter instructs PostgreSQL to search
+ for the first instance of any
+ type definition
+ with the provided name.
+ If no type definitions are found a notice is issued and the command ends.
+ If a type definition is found then one of two things will happen:
+ if the type definition is a domain it is dropped, otherwise the command fails.
diff --git a/doc/src/sgml/ref/drop_foreign_table.sgml b/doc/src/sgml/ref/drop_foreign_table.sgml
index 07b3fd4251..0288fb2062 100644
--- a/doc/src/sgml/ref/drop_foreign_table.sgml
+++ b/doc/src/sgml/ref/drop_foreign_table.sgml
@@ -42,8 +42,11 @@ DROP FOREIGN TABLE [ IF EXISTS ] nameIF EXISTS
- Do not throw an error if the foreign table does not exist.
- A notice is issued in this case.
+ This parameter instructs PostgreSQL to search
+ for the first instance of any relation with the provided name.
+ If no relations are found a notice is issued and the command ends.
+ If a relation is found then one of two things will happen:
+ if the relation is a foreign table it is dropped, otherwise the command fails.
diff --git a/doc/src/sgml/ref/drop_index.sgml b/doc/src/sgml/ref/drop_index.sgml
index 0aedd71bd6..dff437cf9b 100644
--- a/doc/src/sgml/ref/drop_index.sgml
+++ b/doc/src/sgml/ref/drop_index.sgml
@@ -70,8 +70,11 @@ DROP INDEX [ CONCURRENTLY ] [ IF EXISTS ] nameIF EXISTS
- Do not throw an error if the index does not exist. A notice is issued
- in this case.
+ This parameter instructs PostgreSQL to search
+ for the first instance of any relation with the provided name.
+ If no relations are found a notice is issued and the command ends.
+ If a relation is found then one of two things will happen:
+ if the relation is an index it is dropped, otherwise the command fails.
diff --git a/doc/src/sgml/ref/drop_materialized_view.sgml b/doc/src/sgml/ref/drop_materialized_view.sgml
index c8f3bc5b0d..6647a0db0d 100644
--- a/doc/src/sgml/ref/drop_materialized_view.sgml
+++ b/doc/src/sgml/ref/drop_materialized_view.sgml
@@ -43,8 +43,11 @@ DROP MATERIALIZED VIEW [ IF EXISTS ] nameIF EXISTS
- Do not throw an error if the materialized view does not exist. A notice
- is issued in this case.
+ This parameter instructs PostgreSQL to search
+ for the first instance of any relation with the provided name.
+ If no relations are found a notice is issued and the command ends.
+ If a relation is found then one of two things will happen:
+ if the relation is a materialized view it is dropped, otherwise the command fails.
diff --git a/doc/src/sgml/ref/drop_sequence.sgml b/doc/src/sgml/ref/drop_sequence.sgml
index 387c98edbc..b3209d6d01 100644
--- a/doc/src/sgml/ref/drop_sequence.sgml
+++ b/doc/src/sgml/ref/drop_sequence.sgml
@@ -42,8 +42,11 @@ DROP SEQUENCE [ IF EXISTS ] name [,
IF EXISTS
- Do not throw an error if the sequence does not exist. A notice is issued
- in this case.
+ This parameter instructs PostgreSQL to search
+ for the first instance of any relation with the provided name.
+ If no relations are found a notice is issued and the command ends.
+ If a relation is found then one of two things will happen:
+ if the relation is a sequence it is dropped, otherwise the command fails.
diff --git a/doc/src/sgml/ref/drop_table.sgml b/doc/src/sgml/ref/drop_table.sgml
index bf8996d198..9c9147f2ef 100644
--- a/doc/src/sgml/ref/drop_table.sgml
+++ b/doc/src/sgml/ref/drop_table.sgml
@@ -55,8 +55,11 @@ DROP TABLE [ IF EXISTS ] name [, ..
IF EXISTS
- Do not throw an error if the table does not exist. A notice is issued
- in this case.
+ This parameter instructs PostgreSQL to search
+ for the first instance of any relation with the provided name.
+ If no relations are found a notice is issued and the command ends.
+ If a relation is found then one of two things will happen:
+ if the relation is a table it is dropped, otherwise the command fails.
diff --git a/doc/src/sgml/ref/drop_type.sgml b/doc/src/sgml/ref/drop_type.sgml
index 9e555c0624..305a62486f 100644
--- a/doc/src/sgml/ref/drop_type.sgml
+++ b/doc/src/sgml/ref/drop_type.sgml
@@ -42,8 +42,17 @@ DROP TYPE [ IF EXISTS ] name [, ...
IF EXISTS
- Do not throw an error if the type does not exist. A notice is issued
- in this case.
+ This parameter instructs PostgreSQL to search
+ for the first instance of any
+ type definition
+ with the provided name.
+ If no type definitions are found a notice is issued and the command ends.
+ If a type definition is found then it will be dropped. This includes
+ domains even though they have their own drop command.
+
+ However, an attempt to drop the automatically created composite type of an
+ existing relation will fail as the relation has a dependency on the found
+ type definition.
diff --git a/doc/src/sgml/ref/drop_view.sgml b/doc/src/sgml/ref/drop_view.sgml
index a1c550ec3e..ff75410cf1 100644
--- a/doc/src/sgml/ref/drop_view.sgml
+++ b/doc/src/sgml/ref/drop_view.sgml
@@ -42,8 +42,11 @@ DROP VIEW [ IF EXISTS ] name [, ...
IF EXISTS
- Do not throw an error if the view does not exist. A notice is issued
- in this case.
+ This parameter instructs PostgreSQL to search
+ for the first instance of any relation with the provided name.
+ If no relations are found a notice is issued and the command ends.
+ If a relation is found then one of two things will happen:
+ if the relation is a view it is dropped, otherwise the command fails.
diff --git a/src/test/regress/expected/drop_if_exists.out b/src/test/regress/expected/drop_if_exists.out
index 5e44c2c3ce..f328d94b9e 100644
--- a/src/test/regress/expected/drop_if_exists.out
+++ b/src/test/regress/expected/drop_if_exists.out
@@ -330,6 +330,167 @@ HINT: Specify the argument list to select the routine unambiguously.
-- cleanup
DROP PROCEDURE test_ambiguous_procname(int);
DROP PROCEDURE test_ambiguous_procname(text);
+-- Demonstrate namespace collision behavior
+CREATE SCHEMA test_if_exists_first;
+CREATE SCHEMA test_if_exists_second;
+SET search_path TO test_if_exists_first, test_if_exists_second;
+DROP TABLE test_if_exists_second.test_rel_exists;
+ERROR: table "test_rel_exists" does not exist
+DROP TABLE IF EXISTS test_if_exists_second.test_rel_exists;
+NOTICE: table "test_rel_exists" does not exist, skipping
+CREATE TABLE test_if_exists_second.test_rel_exists (a int, b text);
+CREATE TABLE test_if_exists_first.test_rel_with_index (ai int, bi text);
+-- table presence in the second schema causes a failure here
+-- even though a corresponding non-schema-qualified create
+-- statement would succeed.
+DROP VIEW IF EXISTS test_rel_exists;
+ERROR: "test_rel_exists" is not a view
+HINT: Use DROP TABLE to remove a table.
+DROP INDEX IF EXISTS test_rel_exists;
+ERROR: "test_rel_exists" is not an index
+HINT: Use DROP TABLE to remove a table.
+DROP TYPE IF EXISTS test_rel_exists;
+ERROR: cannot drop type test_rel_exists because table test_rel_exists requires it
+HINT: You can drop table test_rel_exists instead.
+DROP SEQUENCE IF EXISTS test_rel_exists;
+ERROR: "test_rel_exists" is not a sequence
+HINT: Use DROP TABLE to remove a table.
+DROP MATERIALIZED VIEW IF EXISTS test_rel_exists;
+ERROR: "test_rel_exists" is not a materialized view
+HINT: Use DROP TABLE to remove a table.
+DROP FOREIGN TABLE IF EXISTS test_rel_exists;
+ERROR: "test_rel_exists" is not a foreign table
+HINT: Use DROP TABLE to remove a table.
+-- a role is not a relation so this shouldn't be affected
+DROP ROLE IF EXISTS test_rel_exists;
+NOTICE: role "test_rel_exists" does not exist, skipping
+-- type affirmation (this isn't the same as the implicit type created with the table)
+CREATE TYPE test_if_exists_first.test_rel_exists AS (c text, d int);
+-- existence of type prevents finding the table
+DROP TABLE test_rel_exists;
+ERROR: "test_rel_exists" is not a table
+HINT: Use DROP TYPE to remove a type.
+-- cleanup
+DROP TYPE IF EXISTS test_rel_exists;
+-- view affirmation
+CREATE VIEW test_if_exists_first.test_rel_exists AS
+ SELECT 1::bigint AS d, 'e'::text AS e;
+-- existence of view prevents finding the table
+DROP TABLE test_rel_exists;
+ERROR: "test_rel_exists" is not a table
+HINT: Use DROP VIEW to remove a view.
+-- cleanup
+DROP VIEW test_rel_exists;
+-- index affirmation
+CREATE INDEX test_rel_exists ON test_if_exists_first.test_rel_with_index (ai);
+-- existence of index prevents finding the table
+DROP TABLE test_rel_exists;
+ERROR: "test_rel_exists" is not a table
+HINT: Use DROP INDEX to remove an index.
+-- cleanup
+DROP INDEX test_rel_exists;
+-- sequence affirmation
+CREATE SEQUENCE test_rel_exists;
+-- existence of sequence prevents finding the table
+DROP TABLE test_rel_exists;
+ERROR: "test_rel_exists" is not a table
+HINT: Use DROP SEQUENCE to remove a sequence.
+-- cleanup
+DROP SEQUENCE test_rel_exists;
+-- materialized affirmation
+CREATE MATERIALIZED VIEW test_if_exists_first.test_rel_exists AS
+ SELECT 1::bigint AS d, 'e'::text AS e;
+-- existence of materialized view prevents finding the table
+DROP TABLE test_rel_exists;
+ERROR: "test_rel_exists" is not a table
+HINT: Use DROP MATERIALIZED VIEW to remove a materialized view.
+-- schema qualification works though (and cleanup)
+DROP TABLE test_if_exists_second.test_rel_exists;
+DROP MATERIALIZED VIEW test_rel_exists;
+DROP TABLE test_if_exists_first.test_rel_with_index;
+-- Type & Domain behavior is thus:
+CREATE TABLE test_if_exists_second.test_rel_exists (a int, b text);
+-- domain dropping errors with presence of table; no hint provided
+DROP DOMAIN IF EXISTS test_rel_exists;
+ERROR: "test_rel_exists" is not a domain
+-- domain affirmation
+CREATE DOMAIN test_rel_exists int4;
+-- existence of domain in first search_path schema
+-- does not prevent second search_path table dropping
+DROP TABLE test_rel_exists;
+-- cleanup
+DROP DOMAIN test_rel_exists;
+-- setup
+CREATE TABLE test_if_exists_second.test_rel_exists (a int, b text);
+-- type with same name exists as table creation creates a composite type
+CREATE TYPE test_if_exists_second.test_rel_exists AS (c int, d text);
+ERROR: type "test_rel_exists" already exists
+-- domain creation with same name as table fails as auto-generated type conflicts
+CREATE DOMAIN test_if_exists_second.test_rel_exists int4;
+ERROR: type "test_rel_exists" already exists
+-- cannot independently drop a composite type associated with a table
+DROP TYPE IF EXISTS test_if_exists_second.test_rel_exists;
+ERROR: cannot drop type test_rel_exists because table test_rel_exists requires it
+HINT: You can drop table test_rel_exists instead.
+-- cleanup
+DROP TABLE test_if_exists_second.test_rel_exists;
+-- setup
+CREATE TYPE test_if_exists_second.test_rel_exists AS (c int, d text);
+-- auto-created type (which is added also as a relation) prevents table from being created
+CREATE TABLE test_if_exists_second.test_rel_exists (a int, b text);
+ERROR: relation "test_rel_exists" already exists
+-- a composite type is not a domain so a conditional drop fails
+DROP DOMAIN IF EXISTS test_if_exists_second.test_rel_exists;
+ERROR: "test_if_exists_second.test_rel_exists" is not a domain
+-- can still create a domain in the first schema
+CREATE DOMAIN test_rel_exists int4;
+-- unlike the case with relations the fact that domains
+-- and other extensible types share the same namespace
+-- doesn't cause a DROP TYPE command that first
+-- finds a domain to fail - though it does prevent
+-- the search algorithm from looking in the second
+-- schema for an exact match.
+DROP TYPE IF EXISTS test_rel_exists; -- This removes the domain
+ -- type present, not a domain
+DROP DOMAIN IF EXISTS test_if_exists_second.test_rel_exists;
+ERROR: "test_if_exists_second.test_rel_exists" is not a domain
+-- Yep, domain seems to have been removed
+DROP TYPE IF EXISTS test_if_exists_first.test_rel_exists;
+NOTICE: type "test_if_exists_first.test_rel_exists" does not exist, skipping
+-- Yep, domain removed, finding the type
+DROP DOMAIN test_rel_exists;
+ERROR: "test_rel_exists" is not a domain
+-- cleanup
+DROP TYPE test_rel_exists;
+-- test with domain second and type first
+CREATE TYPE test_if_exists_first.test_rel_exists AS (c int, d text);
+CREATE DOMAIN test_if_exists_second.test_rel_exists int4;
+-- fails since the first matched name is not a domain
+DROP DOMAIN IF EXISTS test_rel_exists;
+ERROR: "test_rel_exists" is not a domain
+-- remove the matching type
+DROP TYPE IF EXISTS test_rel_exists;
+-- drop type cleans up domains...
+DROP TYPE IF EXISTS test_if_exists_second.test_rel_exists;
+-- ...so it no longer exists here
+DROP DOMAIN IF EXISTS test_rel_exists;
+NOTICE: type "test_rel_exists" does not exist, skipping
+-- /Type & Domain
+-- Bug # 16492 - this script produces an error, arguably it should not
+CREATE TABLE test_if_exists_first.test_rel_exists (a int, b text);
+DROP TABLE IF EXISTS test_if_exists_first.test_rel_exists;
+DROP VIEW IF EXISTS test_if_exists_first.test_rel_exists;
+NOTICE: view "test_rel_exists" does not exist, skipping
+CREATE VIEW test_if_exists_first.test_rel_exists AS
+ SELECT 1::int AS a, 'one'::text AS b;
+DROP TABLE IF EXISTS test_if_exists_first.test_rel_exists;
+ERROR: "test_rel_exists" is not a table
+HINT: Use DROP VIEW to remove a view.
+DROP VIEW IF EXISTS test_if_exists_first.test_rel_exists;
+CREATE VIEW test_if_exists_first.test_rel_exists AS
+ SELECT 1::int AS a, 'one'::text AS b;
+DROP VIEW test_if_exists_first.test_rel_exists;
+-- /Bug # 16492
-- This test checks both the functionality of 'if exists' and the syntax
-- of the drop database command.
drop database test_database_exists (force);
diff --git a/src/test/regress/sql/drop_if_exists.sql b/src/test/regress/sql/drop_if_exists.sql
index ac6168b91f..5cb7f17875 100644
--- a/src/test/regress/sql/drop_if_exists.sql
+++ b/src/test/regress/sql/drop_if_exists.sql
@@ -296,6 +296,142 @@ DROP ROUTINE IF EXISTS test_ambiguous_procname;
DROP PROCEDURE test_ambiguous_procname(int);
DROP PROCEDURE test_ambiguous_procname(text);
+-- Demonstrate namespace collision behavior
+CREATE SCHEMA test_if_exists_first;
+CREATE SCHEMA test_if_exists_second;
+SET search_path TO test_if_exists_first, test_if_exists_second;
+
+DROP TABLE test_if_exists_second.test_rel_exists;
+DROP TABLE IF EXISTS test_if_exists_second.test_rel_exists;
+CREATE TABLE test_if_exists_second.test_rel_exists (a int, b text);
+CREATE TABLE test_if_exists_first.test_rel_with_index (ai int, bi text);
+
+-- table presence in the second schema causes a failure here
+-- even though a corresponding non-schema-qualified create
+-- statement would succeed.
+DROP VIEW IF EXISTS test_rel_exists;
+DROP INDEX IF EXISTS test_rel_exists;
+DROP TYPE IF EXISTS test_rel_exists;
+DROP SEQUENCE IF EXISTS test_rel_exists;
+DROP MATERIALIZED VIEW IF EXISTS test_rel_exists;
+DROP FOREIGN TABLE IF EXISTS test_rel_exists;
+
+-- a role is not a relation so this shouldn't be affected
+DROP ROLE IF EXISTS test_rel_exists;
+
+-- type affirmation (this isn't the same as the implicit type created with the table)
+CREATE TYPE test_if_exists_first.test_rel_exists AS (c text, d int);
+-- existence of type prevents finding the table
+DROP TABLE test_rel_exists;
+-- cleanup
+DROP TYPE IF EXISTS test_rel_exists;
+
+-- view affirmation
+CREATE VIEW test_if_exists_first.test_rel_exists AS
+ SELECT 1::bigint AS d, 'e'::text AS e;
+-- existence of view prevents finding the table
+DROP TABLE test_rel_exists;
+-- cleanup
+DROP VIEW test_rel_exists;
+
+-- index affirmation
+CREATE INDEX test_rel_exists ON test_if_exists_first.test_rel_with_index (ai);
+-- existence of index prevents finding the table
+DROP TABLE test_rel_exists;
+-- cleanup
+DROP INDEX test_rel_exists;
+
+-- sequence affirmation
+CREATE SEQUENCE test_rel_exists;
+-- existence of sequence prevents finding the table
+DROP TABLE test_rel_exists;
+-- cleanup
+DROP SEQUENCE test_rel_exists;
+
+-- materialized affirmation
+CREATE MATERIALIZED VIEW test_if_exists_first.test_rel_exists AS
+ SELECT 1::bigint AS d, 'e'::text AS e;
+-- existence of materialized view prevents finding the table
+DROP TABLE test_rel_exists;
+
+-- schema qualification works though (and cleanup)
+DROP TABLE test_if_exists_second.test_rel_exists;
+DROP MATERIALIZED VIEW test_rel_exists;
+DROP TABLE test_if_exists_first.test_rel_with_index;
+
+-- Type & Domain behavior is thus:
+CREATE TABLE test_if_exists_second.test_rel_exists (a int, b text);
+-- domain dropping errors with presence of table; no hint provided
+DROP DOMAIN IF EXISTS test_rel_exists;
+-- domain affirmation
+CREATE DOMAIN test_rel_exists int4;
+-- existence of domain in first search_path schema
+-- does not prevent second search_path table dropping
+DROP TABLE test_rel_exists;
+-- cleanup
+DROP DOMAIN test_rel_exists;
+
+-- setup
+CREATE TABLE test_if_exists_second.test_rel_exists (a int, b text);
+-- type with same name exists as table creation creates a composite type
+CREATE TYPE test_if_exists_second.test_rel_exists AS (c int, d text);
+-- domain creation with same name as table fails as auto-generated type conflicts
+CREATE DOMAIN test_if_exists_second.test_rel_exists int4;
+-- cannot independently drop a composite type associated with a table
+DROP TYPE IF EXISTS test_if_exists_second.test_rel_exists;
+-- cleanup
+DROP TABLE test_if_exists_second.test_rel_exists;
+
+-- setup
+CREATE TYPE test_if_exists_second.test_rel_exists AS (c int, d text);
+-- auto-created type (which is added also as a relation) prevents table from being created
+CREATE TABLE test_if_exists_second.test_rel_exists (a int, b text);
+-- a composite type is not a domain so a conditional drop fails
+DROP DOMAIN IF EXISTS test_if_exists_second.test_rel_exists;
+-- can still create a domain in the first schema
+CREATE DOMAIN test_rel_exists int4;
+-- unlike the case with relations the fact that domains
+-- and other extensible types share the same namespace
+-- doesn't cause a DROP TYPE command that first
+-- finds a domain to fail - though it does prevent
+-- the search algorithm from looking in the second
+-- schema for an exact match.
+DROP TYPE IF EXISTS test_rel_exists; -- This removes the domain
+ -- type present, not a domain
+DROP DOMAIN IF EXISTS test_if_exists_second.test_rel_exists;
+-- Yep, domain seems to have been removed
+DROP TYPE IF EXISTS test_if_exists_first.test_rel_exists;
+-- Yep, domain removed, finding the type
+DROP DOMAIN test_rel_exists;
+-- cleanup
+DROP TYPE test_rel_exists;
+
+-- test with domain second and type first
+CREATE TYPE test_if_exists_first.test_rel_exists AS (c int, d text);
+CREATE DOMAIN test_if_exists_second.test_rel_exists int4;
+-- fails since the first matched name is not a domain
+DROP DOMAIN IF EXISTS test_rel_exists;
+-- remove the matching type
+DROP TYPE IF EXISTS test_rel_exists;
+-- drop type cleans up domains...
+DROP TYPE IF EXISTS test_if_exists_second.test_rel_exists;
+-- ...so it no longer exists here
+DROP DOMAIN IF EXISTS test_rel_exists;
+-- /Type & Domain
+
+-- Bug # 16492 - this script produces an error, arguably it should not
+CREATE TABLE test_if_exists_first.test_rel_exists (a int, b text);
+DROP TABLE IF EXISTS test_if_exists_first.test_rel_exists;
+DROP VIEW IF EXISTS test_if_exists_first.test_rel_exists;
+CREATE VIEW test_if_exists_first.test_rel_exists AS
+ SELECT 1::int AS a, 'one'::text AS b;
+DROP TABLE IF EXISTS test_if_exists_first.test_rel_exists;
+DROP VIEW IF EXISTS test_if_exists_first.test_rel_exists;
+CREATE VIEW test_if_exists_first.test_rel_exists AS
+ SELECT 1::int AS a, 'one'::text AS b;
+DROP VIEW test_if_exists_first.test_rel_exists;
+-- /Bug # 16492
+
-- This test checks both the functionality of 'if exists' and the syntax
-- of the drop database command.
drop database test_database_exists (force);