commit 57a9256f4c3a61cdaca7315ab77e08e61338fbf9
Author: David G. Johnston <david.g.johnston@gmail.com>
Date:   Wed Jun 17 22:24:08 2020 +0000

    Document existing DROP relation IF EXISTS namespace behavior
    
    Bug# 16492 takes offense to the fact that DROP VIEW IF EXISTS name
    errors if a table with the same name exists but a view with that
    name does not.  While I believe the bug is real there is no
    consensus to actually fix the behavior to work as it is documented.
    Therefore fix the documentation to match the behavior and encode
    that behavior in the regression tests.
    
    It is unclear whether Domains are supposed to be considered relations
    here.  The presence of a table will cause DROP DOMAIN IF EXISTS to
    fail so it is thinking of itself as a relation.  However, the table
    doesn't consider it to be one since DROP TABLE will happily ignore
    the presence of a domain with the table name earlier in the search_path;
    something the other relation types will not do.  Include DROP DOMAIN
    in the documenation fixes, and add it to the glossary for consistency.

diff --git a/doc/src/sgml/glossary.sgml b/doc/src/sgml/glossary.sgml
index 25b03f3b37..5971268614 100644
--- a/doc/src/sgml/glossary.sgml
+++ b/doc/src/sgml/glossary.sgml
@@ -1111,8 +1111,9 @@
      <glossterm linkend="glossary-view">views</glossterm>,
      <glossterm linkend="glossary-foreign-table">foreign tables</glossterm>,
      <glossterm linkend="glossary-materialized-view">materialized views</glossterm>,
-     composite types, and
-     <glossterm linkend="glossary-index">indexes</glossterm> are all relations.
+     composite types,
+     <glossterm linkend="glossary-index">indexes</glossterm>, and
+     domains are all relations.
     </para>
     <para>
      <firstterm>Class</firstterm> is an archaic synonym for
diff --git a/doc/src/sgml/ref/drop_domain.sgml b/doc/src/sgml/ref/drop_domain.sgml
index b18faf3917..9c492709a6 100644
--- a/doc/src/sgml/ref/drop_domain.sgml
+++ b/doc/src/sgml/ref/drop_domain.sgml
@@ -42,8 +42,11 @@ DROP DOMAIN [ IF EXISTS ] <replaceable class="parameter">name</replaceable> [, .
     <term><literal>IF EXISTS</literal></term>
     <listitem>
      <para>
-      Do not throw an error if the domain does not exist. A notice is issued
-      in this case.
+      This parameter instructs <productname>PostgreSQL</productname> 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 domain it is dropped, otherwise the command fails.
      </para>
     </listitem>
    </varlistentry>
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 ] <replaceable class="parameter">name</replaceabl
     <term><literal>IF EXISTS</literal></term>
     <listitem>
      <para>
-      Do not throw an error if the foreign table does not exist.
-      A notice is issued in this case.
+      This parameter instructs <productname>PostgreSQL</productname> 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.
      </para>
     </listitem>
    </varlistentry>
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 ] <replaceable class="parameter">name</r
     <term><literal>IF EXISTS</literal></term>
     <listitem>
      <para>
-      Do not throw an error if the index does not exist. A notice is issued
-      in this case.
+      This parameter instructs <productname>PostgreSQL</productname> 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.
      </para>
     </listitem>
    </varlistentry>
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 ] <replaceable class="parameter">name</replac
     <term><literal>IF EXISTS</literal></term>
     <listitem>
      <para>
-      Do not throw an error if the materialized view does not exist. A notice
-      is issued in this case.
+      This parameter instructs <productname>PostgreSQL</productname> 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.
      </para>
     </listitem>
    </varlistentry>
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 ] <replaceable class="parameter">name</replaceable> [,
     <term><literal>IF EXISTS</literal></term>
     <listitem>
      <para>
-      Do not throw an error if the sequence does not exist. A notice is issued
-      in this case.
+      This parameter instructs <productname>PostgreSQL</productname> 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.
      </para>
     </listitem>
    </varlistentry>
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 ] <replaceable class="parameter">name</replaceable> [, ..
     <term><literal>IF EXISTS</literal></term>
     <listitem>
      <para>
-      Do not throw an error if the table does not exist. A notice is issued
-      in this case.
+      This parameter instructs <productname>PostgreSQL</productname> 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.
      </para>
     </listitem>
    </varlistentry>
diff --git a/doc/src/sgml/ref/drop_type.sgml b/doc/src/sgml/ref/drop_type.sgml
index 9e555c0624..516313b5be 100644
--- a/doc/src/sgml/ref/drop_type.sgml
+++ b/doc/src/sgml/ref/drop_type.sgml
@@ -42,8 +42,11 @@ DROP TYPE [ IF EXISTS ] <replaceable class="parameter">name</replaceable> [, ...
     <term><literal>IF EXISTS</literal></term>
     <listitem>
      <para>
-      Do not throw an error if the type does not exist. A notice is issued
-      in this case.
+      This parameter instructs <productname>PostgreSQL</productname> 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 type it is dropped, otherwise the command fails.
      </para>
     </listitem>
    </varlistentry>
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 ] <replaceable class="parameter">name</replaceable> [, ...
     <term><literal>IF EXISTS</literal></term>
     <listitem>
      <para>
-      Do not throw an error if the view does not exist. A notice is issued
-      in this case.
+      This parameter instructs <productname>PostgreSQL</productname> 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.
      </para>
     </listitem>
    </varlistentry>
diff --git a/src/test/regress/expected/drop_if_exists.out b/src/test/regress/expected/drop_if_exists.out
index 5e44c2c3ce..b9933e5fb5 100644
--- a/src/test/regress/expected/drop_if_exists.out
+++ b/src/test/regress/expected/drop_if_exists.out
@@ -330,6 +330,111 @@ 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;
+-- Domain if exists 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 does not prevent table dropping
+DROP TABLE test_rel_exists;
+--      cleanup
+DROP DOMAIN test_rel_exists;
+-- /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..f08bb19c84 100644
--- a/src/test/regress/sql/drop_if_exists.sql
+++ b/src/test/regress/sql/drop_if_exists.sql
@@ -296,6 +296,94 @@ 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;
+
+-- Domain if exists 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 does not prevent table dropping
+DROP TABLE test_rel_exists;
+--      cleanup
+DROP DOMAIN test_rel_exists;
+-- /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);
